diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 188c11ff31..01c09d2231 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -20,6 +20,11 @@ * Do not open an issue on GitHub until you have collected positive feedback about the change. GitHub issues are primarily intended for bug reports and fixes. +#### **Running tests and Debugging** + +* Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/master/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules! +* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657) + #### **Do you have questions about consuming the library or the source code?** * Ask any question about how to use ImageSharp in the [ImageSharp Gitter Chat Room](https://gitter.im/ImageSharp/General). diff --git a/appveyor.yml b/appveyor.yml index 821fd427c8..2cc5182d39 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,10 +12,10 @@ environment: - target_framework: netcoreapp2.1 is_32bit: True - - target_framework: net471 + - target_framework: net472 is_32bit: False - - target_framework: net471 + - target_framework: net472 is_32bit: True - target_framework: net462 diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 1cb3f444f0..ae5069be1d 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -38,8 +38,8 @@ - - + + All diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 770d440656..0c6e0d3b40 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs index 897b3f384f..00141a8d8d 100644 --- a/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing onLocalGradient); TPixel resultColor = default; - resultColor.PackFromVector4(result); + resultColor.FromVector4(result); return resultColor; } } diff --git a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs index c3f81868be..1ef4bb9ec9 100644 --- a/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs @@ -140,7 +140,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.source.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs index 2ce9a7ce57..46ed36f687 100644 --- a/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs @@ -170,7 +170,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index dc73420f30..0957904c62 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -79,8 +79,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int width = maxX - minX; - MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); ParallelHelper.IterateRows( @@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing Span background = source.GetPixelRowSpan(y).Slice(minX, width); Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); - blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); + blender.Blend(configuration, background, background, foreground, this.Opacity); } }); } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 514249a2d4..550c021caa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -3,7 +3,7 @@ using System; using System.Buffers; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; @@ -82,11 +82,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing // we need to offset the pixel grid to account for when we outline a path. // basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5] // and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the# - // region to alline with the pixel grid. + // region to align with the pixel grid. float offset = 0.5f; if (this.Options.Antialias) { - offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset. + offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset. subpixelCount = this.Options.AntialiasSubpixelDepth; if (subpixelCount < 4) { @@ -107,6 +107,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing Span buffer = bBuffer.GetSpan(); Span scanline = bScanline.GetSpan(); + bool isSolidBrushWithoutBlending = this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush); + for (int y = minY; y < maxY; y++) { if (scanlineDirty) @@ -121,7 +123,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int pointsFound = region.Scan(subPixel + offset, buffer, configuration); if (pointsFound == 0) { - // nothing on this line skip + // nothing on this line, skip continue; } @@ -168,16 +170,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { if (!this.Options.Antialias) { + bool hasOnes = false; + bool hasZeros = false; for (int x = 0; x < scanlineWidth; x++) { if (scanline[x] >= 0.5) { scanline[x] = 1; + hasOnes = true; } else { scanline[x] = 0; + hasZeros = true; + } + } + + if (isSolidBrushWithoutBlending && hasOnes != hasZeros) + { + if (hasOnes) + { + source.GetPixelRowSpan(y).Slice(minX, scanlineWidth).Fill(solidBrush.Color); } + + continue; } } @@ -187,5 +203,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing } } } + + private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) + { + solidBrush = this.Brush as SolidBrush; + + if (solidBrush == null) + { + return false; + } + + return this.Options.IsOpaqueColorWithoutBlending(solidBrush.Color); + } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 1095de325f..266d842bfa 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text /// The font we want to render with /// The brush to source pixel colors from. /// The pen to outline text with. - /// The location on the image to start drawign the text from. + /// The location on the image to start drawing the text from. public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location) { Guard.NotNull(text, nameof(text)); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { base.BeforeImageApply(source, sourceRectangle); - // do everythign at the image level as we are deligating the processing down to other processors + // do everything at the image level as we are delegating the processing down to other processors var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) { ApplyKerning = this.Options.ApplyKerning, @@ -97,7 +97,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null); this.textRenderer.Options = (GraphicsOptions)this.Options; - TextRenderer.RenderTextTo(this.textRenderer, this.Text, style); + var renderer = new TextRenderer(this.textRenderer); + renderer.RenderText(this.Text, style); } protected override void AfterImageApply(Image source, Rectangle sourceRectangle) @@ -138,10 +139,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text fistRow = -startY; } - int end = operation.Map.Height; - int maxHeight = source.Height - startY; - end = Math.Min(end, maxHeight); + int end = Math.Min(operation.Map.Height, maxHeight); for (int row = fistRow; row < end; row++) { @@ -164,18 +163,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text private class CachingGlyphRenderer : IGlyphRenderer, IDisposable { - private PathBuilder builder; + // just enough accuracy to allow for 1/8 pixel differences which + // later are accumulated while rendering, but do not grow into full pixel offsets + // The value 8 is benchmarked to: + // - Provide a good accuracy (smaller than 0.2% image difference compared to the non-caching variant) + // - Cache hit ratio above 60% + private const float AccuracyMultiple = 8; + + private readonly PathBuilder builder; private Point currentRenderPosition = default; - private GlyphRendererParameters currentGlyphRenderParams = default; - private int offset = 0; + private (GlyphRendererParameters glyph, PointF subPixelOffset) currentGlyphRenderParams = default; + private readonly int offset = 0; private PointF currentPoint = default(PointF); - private readonly Dictionary glyphData = new Dictionary(); + private readonly Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData> + glyphData = new Dictionary<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData>(); - private bool renderOutline = false; - private bool renderFill = false; - private bool raterizationRequired = false; + private readonly bool renderOutline = false; + private readonly bool renderFill = false; + private bool rasterizationRequired = false; public CachingGlyphRenderer(MemoryAllocator memoryAllocator, int size, IPen pen, bool renderFill) { @@ -213,17 +220,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text this.builder.StartFigure(); } - public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters paramters) + public bool BeginGlyph(RectangleF bounds, GlyphRendererParameters parameters) { this.currentRenderPosition = Point.Truncate(bounds.Location); + PointF subPixelOffset = bounds.Location - this.currentRenderPosition; + + subPixelOffset.X = MathF.Round(subPixelOffset.X * AccuracyMultiple) / AccuracyMultiple; + subPixelOffset.Y = MathF.Round(subPixelOffset.Y * AccuracyMultiple) / AccuracyMultiple; // we have offset our rendering origion a little bit down to prevent edge cropping, move the draw origin up to compensate this.currentRenderPosition = new Point(this.currentRenderPosition.X - this.offset, this.currentRenderPosition.Y - this.offset); - this.currentGlyphRenderParams = paramters; - if (this.glyphData.ContainsKey(paramters)) + this.currentGlyphRenderParams = (parameters, subPixelOffset); + + if (this.glyphData.ContainsKey(this.currentGlyphRenderParams)) { // we have already drawn the glyph vectors skip trying again - this.raterizationRequired = false; + this.rasterizationRequired = false; return false; } @@ -233,7 +245,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text // ensure all glyphs render around [zero, zero] so offset negative root positions so when we draw the glyph we can offet it back this.builder.SetOrigin(new PointF(-(int)bounds.X + this.offset, -(int)bounds.Y + this.offset)); - this.raterizationRequired = true; + this.rasterizationRequired = true; return true; } @@ -252,7 +264,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text public void Dispose() { - foreach (KeyValuePair kv in this.glyphData) + foreach (KeyValuePair<(GlyphRendererParameters glyph, PointF subPixelOffset), GlyphRenderData> kv in this.glyphData) { kv.Value.Dispose(); } @@ -270,7 +282,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text GlyphRenderData renderData = default; // has the glyoh been rendedered already???? - if (this.raterizationRequired) + if (this.rasterizationRequired) { IPath path = this.builder.Build(); diff --git a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs index 87e1dc146a..09a1ff71fb 100644 --- a/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs @@ -95,9 +95,9 @@ namespace SixLabors.ImageSharp.Processing // Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :) var maxColor = default(TPixel); - maxColor.PackFromVector4(new Vector4(float.MaxValue)); + maxColor.FromVector4(new Vector4(float.MaxValue)); var minColor = default(TPixel); - minColor.PackFromVector4(new Vector4(float.MinValue)); + minColor.FromVector4(new Vector4(float.MinValue)); this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold; } @@ -158,7 +158,12 @@ namespace SixLabors.ImageSharp.Processing } Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan); + this.Blender.Blend( + this.Target.Configuration, + destinationRow, + destinationRow, + overlaySpan, + amountSpan); } } } diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6b69c33f07..20a6833c40 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -89,13 +89,24 @@ namespace SixLabors.ImageSharp.Processing /// internal override void Apply(Span scanline, int x, int y) { - Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); + Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x); + + // constrain the spans to each other + if (destinationRow.Length > scanline.Length) + { + destinationRow = destinationRow.Slice(0, scanline.Length); + } + else + { + scanline = scanline.Slice(0, destinationRow.Length); + } MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; + Configuration configuration = this.Target.Configuration; if (this.Options.BlendPercentage == 1f) { - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); + this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } else { @@ -108,7 +119,12 @@ namespace SixLabors.ImageSharp.Processing amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } - this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); + this.Blender.Blend( + configuration, + destinationRow, + destinationRow, + this.Colors.GetSpan(), + amountSpan); } } } diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 328d575969..63ccea4e66 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Advanced /// /// The type of the pixel. /// The source. - /// The span retuned from Pixel source + /// The span returned from Pixel source private static Span GetSpan(IPixelSource source) where TPixel : struct, IPixel => source.PixelBuffer.GetSpan(); @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// - /// The span retuned from Pixel source + /// The span returned from Pixel source /// private static Span GetSpan(IPixelSource source, int row) where TPixel : struct, IPixel @@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// - /// The span retuned from Pixel source + /// The span returned from Pixel source /// private static Span GetSpan(Buffer2D source, int row) where TPixel : struct, IPixel diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs new file mode 100644 index 0000000000..9e7624480d --- /dev/null +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.ImageSharp.Processing.Processors.Quantization; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being + /// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics, + /// these are caused because not every possible generic instantiation can be determined up front at compile time. + /// The Aot Compiler is designed to overcome the limitations of this compiler. + /// + public static class AotCompilerTools + { + /// + /// Seeds the compiler using the given pixel format. + /// + /// The pixel format. + public static void Seed() + where TPixel : struct, IPixel + { + // This is we actually call all the individual methods you need to seed. + AotCompileOctreeQuantizer(); + AotCompileWuQuantizer(); + AotCompileDithering(); + + // TODO: Do the discovery work to figure out what works and what doesn't. + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// Seeds the compiler using the given pixel formats. + /// + /// The first pixel format. + /// The second pixel format. + /// The third pixel format. + public static void Seed() + where TPixel : struct, IPixel + where TPixel2 : struct, IPixel + where TPixel3 : struct, IPixel + { + Seed(); + Seed(); + } + + /// + /// This method doesn't actually do anything but serves an important purpose... + /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion: + /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode." + /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT + /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on + /// iOS so it bombs out. + /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the + /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!! + /// + /// The pixel format. + private static void AotCompileOctreeQuantizer() + where TPixel : struct, IPixel + { + var test = new OctreeFrameQuantizer(new OctreeQuantizer(false)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileWuQuantizer() + where TPixel : struct, IPixel + { + var test = new WuFrameQuantizer(new WuQuantizer(false)); + test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1)); + test.AotGetPalette(); + } + + /// + /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS. + /// + /// The pixel format. + private static void AotCompileDithering() + where TPixel : struct, IPixel + { + var test = new FloydSteinbergDiffuser(); + TPixel pixel = default; + test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 3ce14cdea4..3c197673d3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -37,10 +37,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -70,10 +70,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +103,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +136,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -171,10 +171,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -203,10 +203,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -236,10 +236,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -268,10 +268,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -301,10 +301,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -334,10 +334,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -367,10 +367,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -400,10 +400,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); @@ -433,10 +433,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 3c9e6658cd..0a8607e3bc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -37,10 +38,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -70,10 +71,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +104,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +137,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -169,10 +170,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -201,10 +202,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -234,10 +235,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -267,10 +268,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -300,10 +301,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -333,10 +334,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -366,10 +367,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -399,10 +400,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); @@ -432,10 +433,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 01de794885..3a779ee722 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -35,10 +36,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -68,10 +69,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -103,10 +104,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -136,10 +137,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -169,10 +170,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -202,10 +203,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -235,10 +236,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -268,10 +269,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -301,10 +302,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -334,10 +335,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -367,10 +368,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -400,10 +401,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); @@ -432,10 +433,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 0b469e065f..90eb8e34d7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -31,10 +32,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -63,10 +64,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -130,10 +131,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -165,10 +166,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -229,10 +230,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -261,10 +262,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -293,10 +294,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -325,10 +326,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -357,10 +358,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -389,10 +390,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); @@ -421,10 +422,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index b77f48325f..d03c10a01d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -159,10 +160,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -192,10 +193,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -225,10 +226,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -258,10 +259,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -291,10 +292,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -324,10 +325,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -357,10 +358,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 8963ad495a..fada6d9c59 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -17,7 +18,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion private static readonly CieLuvToCieXyzConverter CieLuvToCieXyzConverter = new CieLuvToCieXyzConverter(); - private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); + private static readonly HunterLabToCieXyzConverter + HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter(); private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter; @@ -40,10 +42,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -75,10 +77,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -110,10 +112,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -145,10 +147,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -177,10 +179,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -211,10 +213,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -245,10 +247,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -279,10 +281,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -314,10 +316,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -350,10 +352,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -382,10 +384,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -415,10 +417,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); @@ -449,10 +451,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 6f8fe61469..b798516359 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 106e8956f1..a7080b9749 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 8b4e29215c..a2121203c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -32,10 +33,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -65,10 +66,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -98,10 +99,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -131,10 +132,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -164,10 +165,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -197,10 +198,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -230,10 +231,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -263,10 +264,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -296,10 +297,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -329,10 +330,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -362,10 +363,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -390,10 +391,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); @@ -423,10 +424,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv destRef = ref MemoryMarshal.GetReference(destination); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index b3286a9cc4..e5996c238e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -12,26 +12,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public partial class ColorSpaceConverter { - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -44,26 +33,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -76,26 +54,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -108,26 +75,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -140,26 +96,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -172,29 +117,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - - // Conversion - return this.cieXyzToHunterLabConverter.Convert(adapted); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -207,26 +138,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); @@ -240,14 +160,24 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsl color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } } /// @@ -255,180 +185,250 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in Hsv color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } } /// - /// Performs the bulk conversion from into + /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public HunterLab ToHunterLab(in LinearRgb color) + /// The span to the source colors + /// The span to the destination colors + public void Convert(ReadOnlySpan source, Span destination) { - var xyzColor = this.ToCieXyz(color); - return this.ToHunterLab(xyzColor); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } } /// - /// Performs the bulk conversion from into + /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; - ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToHunterLab(sp); } } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in Lms color) + public HunterLab ToHunterLab(in CieLab color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLch color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - ref Lms sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - for (int i = 0; i < count; i++) - { - ref Lms sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in Rgb color) + public HunterLab ToHunterLab(in CieXyy color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in CieXyz color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + // Adaptation + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); - ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + // Conversion + return this.cieXyzToHunterLabConverter.Convert(adapted); + } - for (int i = 0; i < count; i++) - { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Cmyk color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } /// - /// Converts a into a + /// Converts a into a /// /// The color to convert. /// The - public HunterLab ToHunterLab(in YCbCr color) + public HunterLab ToHunterLab(in Hsl color) { var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } /// - /// Performs the bulk conversion from into + /// Converts a into a /// - /// The span to the source colors - /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Hsv color) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); - ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in LinearRgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } - for (int i = 0; i < count; i++) - { - ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); - ref HunterLab dp = ref Unsafe.Add(ref destRef, i); - dp = this.ToHunterLab(sp); - } + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in Rgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public HunterLab ToHunterLab(in YCbCr color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToHunterLab(xyzColor); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index 98943c034a..eef626be2f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,26 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -47,26 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -79,26 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -111,26 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -143,26 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -175,29 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in CieXyz color) - { - // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); - - // Conversion - return this.cieXyzToLinearRgbConverter.Convert(adapted); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -210,26 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Cmyk color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -242,26 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Hsl color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -274,26 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Hsv color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -306,26 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -338,26 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLinearRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -370,26 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in Rgb color) - { - // Conversion - return RgbToLinearRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -402,26 +268,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public LinearRgb ToLinearRgb(in YCbCr color) - { - var rgb = this.ToRgb(color); - return this.ToLinearRgb(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); @@ -433,5 +288,151 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLinearRgb(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in CieXyz color) + { + // Adaptation + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); + + // Conversion + return this.cieXyzToLinearRgbConverter.Convert(adapted); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Cmyk color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Hsl color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Hsv color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLinearRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in Rgb color) + { + // Conversion + return RgbToLinearRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public LinearRgb ToLinearRgb(in YCbCr color) + { + var rgb = this.ToRgb(color); + return this.ToLinearRgb(rgb); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index ffd0f88d11..3b8638f7d2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -12,26 +12,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// public partial class ColorSpaceConverter { - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -44,26 +33,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -76,26 +54,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -108,26 +75,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -140,26 +96,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -172,22 +117,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -200,26 +138,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Cmyk color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -232,26 +159,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsl color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -264,26 +180,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Hsv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -296,26 +201,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -328,26 +222,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in LinearRgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -360,26 +243,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in Rgb color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -392,26 +264,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Lms ToLms(in YCbCr color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToLms(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Lms destRef = ref MemoryMarshal.GetReference(destination); @@ -423,5 +284,144 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLms(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Cmyk color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Hsl color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Hsv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in LinearRgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in Rgb color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Lms ToLms(in YCbCr color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToLms(xyzColor); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index cd40c966b1..fc5665e5c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,26 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly LinearRgbToRgbConverter LinearRgbToRgbConverter = new LinearRgbToRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -47,26 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -79,26 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLchuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -111,26 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -143,26 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -175,29 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in CieXyz color) - { - // Conversion - var linear = this.ToLinearRgb(color); - - // Compand - return this.ToRgb(linear); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -210,26 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Cmyk color) - { - // Conversion - return CmykAndRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -242,26 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Hsv color) - { - // Conversion - return HsvAndRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -274,26 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Hsl color) - { - // Conversion - return HslAndRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -306,26 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -338,26 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in LinearRgb color) - { - // Conversion - return LinearRgbToRgbConverter.Convert(color); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -370,26 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - return this.ToRgb(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -402,29 +268,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public Rgb ToRgb(in YCbCr color) - { - // Conversion - Rgb rgb = YCbCrAndRgbConverter.Convert(color); - - // Adaptation - return this.Adapt(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb destRef = ref MemoryMarshal.GetReference(destination); @@ -436,5 +288,154 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToRgb(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLchuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in CieXyz color) + { + // Conversion + var linear = this.ToLinearRgb(color); + + // Compand + return this.ToRgb(linear); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Cmyk color) + { + // Conversion + return CmykAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Hsv color) + { + // Conversion + return HsvAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Hsl color) + { + // Conversion + return HslAndRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in LinearRgb color) + { + // Conversion + return LinearRgbToRgbConverter.Convert(color); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + return this.ToRgb(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public Rgb ToRgb(in YCbCr color) + { + // Conversion + Rgb rgb = YCbCrAndRgbConverter.Convert(color); + + // Adaptation + return this.Adapt(rgb); + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 38e6d5fae0..5780f4f545 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -4,6 +4,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -15,27 +16,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly YCbCrAndRgbConverter YCbCrAndRgbConverter = new YCbCrAndRgbConverter(); - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLab color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -48,27 +37,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLch color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -81,27 +58,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLuv color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -114,27 +79,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyy color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -147,27 +100,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieXyz color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -180,27 +121,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Cmyk color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -213,27 +142,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Hsl color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -246,27 +163,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Hsv color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -279,27 +184,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in HunterLab color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -312,27 +205,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in LinearRgb color) - { - var rgb = this.ToRgb(color); - - return YCbCrAndRgbConverter.Convert(rgb); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -345,27 +226,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Lms color) - { - var xyzColor = this.ToCieXyz(color); - - return this.ToYCbCr(xyzColor); - } - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -378,22 +247,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } } - /// - /// Converts a into a - /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); - /// /// Performs the bulk conversion from into /// /// The span to the source colors /// The span to the destination colors - /// The number of colors to convert. - public void Convert(ReadOnlySpan source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); @@ -405,5 +267,144 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToYCbCr(sp); } } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLab color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLch color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieLuv color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieXyy color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in CieXyz color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Cmyk color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Hsl color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Hsv color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in HunterLab color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in LinearRgb color) + { + var rgb = this.ToRgb(color); + + return YCbCrAndRgbConverter.Convert(rgb); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Lms color) + { + var xyzColor = this.ToCieXyz(color); + + return this.ToYCbCr(xyzColor); + } + + /// + /// Converts a into a + /// + /// The color to convert. + /// The + public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs index 1b14c6413e..69877d8b55 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs @@ -30,7 +30,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the destination colors. /// The source white point. /// The destination white point. - /// The number of colors to convert. - void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count); + void Transform( + ReadOnlySpan source, + Span destination, + CieXyz sourceWhitePoint, + in CieXyz destinationWhitePoint); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs index dd352db809..40d8c5bc69 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation // Conversion algorithm described here: // https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = MathFExtensions.DegreeToRadian(hDegrees); + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); float a = c * MathF.Cos(hRadians); float b = c * MathF.Sin(hRadians); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs index 81196604e5..2b859205a0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float l = input.L, a = input.A, b = input.B; float c = MathF.Sqrt((a * a) + (b * b)); float hRadians = MathF.Atan2(b, a); - float hDegrees = MathFExtensions.RadianToDegree(hRadians); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); // Wrap the angle round at 360. hDegrees %= 360; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs index 4f5a20bec7..ba5b8bfb79 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation // Conversion algorithm described here: // https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29 float l = input.L, c = input.C, hDegrees = input.H; - float hRadians = MathFExtensions.DegreeToRadian(hDegrees); + float hRadians = GeometryUtilities.DegreeToRadian(hDegrees); float u = c * MathF.Cos(hRadians); float v = c * MathF.Sin(hRadians); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs index 297c18c5c3..3c7d356a5e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float l = input.L, a = input.U, b = input.V; float c = MathF.Sqrt((a * a) + (b * b)); float hRadians = MathF.Atan2(b, a); - float hDegrees = MathFExtensions.RadianToDegree(hRadians); + float hDegrees = GeometryUtilities.RadianToDegree(hRadians); // Wrap the angle round at 360. hDegrees %= 360; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs index c27c61608d..f21235d06c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs @@ -45,9 +45,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(this.HunterLabWhitePoint); float kb = ComputeKb(this.HunterLabWhitePoint); - float l = 100 * MathF.Sqrt(y / yn); - float a = ka * (((x / xn) - (y / yn)) / MathF.Sqrt(y / yn)); - float b = kb * (((y / yn) - (z / zn)) / MathF.Sqrt(y / yn)); + float yByYn = y / yn; + float sqrtYbyYn = MathF.Sqrt(yByYn); + float l = 100 * sqrtYbyYn; + float a = ka * (((x / xn) - yByYn) / sqrtYbyYn); + float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn); if (float.IsNaN(a)) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs index 783d29a557..4d6808e6c0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs @@ -26,9 +26,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(input.WhitePoint); float kb = ComputeKb(input.WhitePoint); - float y = ImageMaths.Pow2(l / 100F) * yn; - float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn; - float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn); + float pow = ImageMaths.Pow2(l / 100F); + float sqrtPow = MathF.Sqrt(pow); + float y = pow * yn; + + float x = (((a / ka) * sqrtPow) + pow) * xn; + float z = (((b / kb) * sqrtPow) - pow) * (-zn); return new CieXyz(x, y, z); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 9b200b8736..85a36331b2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -65,9 +65,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - public void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count) + public void Transform( + ReadOnlySpan source, + Span destination, + CieXyz sourceWhitePoint, + in CieXyz destinationWhitePoint) { - Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + int count = source.Length; if (sourceWhitePoint.Equals(destinationWhitePoint)) { diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index 82899863c9..59c878485d 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -20,6 +20,11 @@ namespace SixLabors.ImageSharp /// The string. public static string GetString(this Encoding encoding, ReadOnlySpan buffer) { + if (buffer.Length == 0) + { + return string.Empty; + } + fixed (byte* bytes = buffer) { return encoding.GetString(bytes, buffer.Length); diff --git a/src/ImageSharp/Common/Extensions/SimdUtils.cs b/src/ImageSharp/Common/Extensions/SimdUtils.cs deleted file mode 100644 index 7b77fefcac..0000000000 --- a/src/ImageSharp/Common/Extensions/SimdUtils.cs +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Diagnostics; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp -{ - /// - /// Various extension and utility methods for and utilizing SIMD capabilities - /// - internal static class SimdUtils - { - /// - /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. - /// - public static bool IsAvx2CompatibleArchitecture => Vector.Count == 8 && Vector.Count == 8; - - internal static void GuardAvx2(string operation) - { - if (!IsAvx2CompatibleArchitecture) - { - throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); - } - } - - /// - /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector4 PseudoRound(this Vector4 v) - { - var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); - - return v + (sign * 0.5f); - } - - /// - /// Rounds all values in 'v' to the nearest integer following semantics. - /// Source: - /// - /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 - /// - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector FastRound(this Vector x) - { - Vector magic0 = new Vector(int.MinValue); // 0x80000000 - Vector sgn0 = Vector.AsVectorSingle(magic0); - Vector and0 = Vector.BitwiseAnd(sgn0, x); - Vector or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); - Vector add0 = Vector.Add(x, or0); - Vector sub0 = Vector.Subtract(add0, or0); - return sub0; - } - - /// - /// Convert 'source.Length' values normalized into [0..1] from 'source' into 'dest' buffer of values. - /// The values gonna be scaled up into [0-255] and rounded. - /// Based on: - /// - /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions - /// - /// - internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - /// - /// Same as but clamps overflown values before conversion. - /// - internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) - { - GuardAvx2(nameof(BulkConvertNormalizedFloatToByte)); - - DebugGuard.IsTrue((source.Length % Vector.Count) == 0, nameof(source), "source.Length should be divisable by Vector.Count!"); - - if (source.Length == 0) - { - return; - } - - ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - int n = source.Length / 8; - - Vector magick = new Vector(32768.0f); - Vector scale = new Vector(255f) / new Vector(256f); - - // need to copy to a temporary struct, because - // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) - // does not work. TODO: This might be a CoreClr bug, need to ask/report - var temp = default(Octet.OfUInt32); - ref Vector tempRef = ref Unsafe.As>(ref temp); - - for (int i = 0; i < n; i++) - { - // union { float f; uint32_t i; } u; - // u.f = 32768.0f + x * (255.0f / 256.0f); - // return (uint8_t)u.i; - Vector x = Unsafe.Add(ref srcBase, i); - x = Vector.Max(x, Vector.Zero); - x = Vector.Min(x, Vector.One); - - x = (x * scale) + magick; - tempRef = x; - - ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); - d.LoadFrom(ref temp); - } - } - - // TODO: Replace these with T4-d library level tuples! - internal static class Octet - { - [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] - public struct OfUInt32 - { - [FieldOffset(0 * sizeof(uint))] - public uint V0; - - [FieldOffset(1 * sizeof(uint))] - public uint V1; - - [FieldOffset(2 * sizeof(uint))] - public uint V2; - - [FieldOffset(3 * sizeof(uint))] - public uint V3; - - [FieldOffset(4 * sizeof(uint))] - public uint V4; - - [FieldOffset(5 * sizeof(uint))] - public uint V5; - - [FieldOffset(6 * sizeof(uint))] - public uint V6; - - [FieldOffset(7 * sizeof(uint))] - public uint V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } - } - - [StructLayout(LayoutKind.Explicit, Size = 8)] - public struct OfByte - { - [FieldOffset(0)] - public byte V0; - - [FieldOffset(1)] - public byte V1; - - [FieldOffset(2)] - public byte V2; - - [FieldOffset(3)] - public byte V3; - - [FieldOffset(4)] - public byte V4; - - [FieldOffset(5)] - public byte V5; - - [FieldOffset(6)] - public byte V6; - - [FieldOffset(7)] - public byte V7; - - public override string ToString() - { - return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]"; - } - - public void LoadFrom(ref OfUInt32 i) - { - this.V0 = (byte)i.V0; - this.V1 = (byte)i.V1; - this.V2 = (byte)i.V2; - this.V3 = (byte)i.V3; - this.V4 = (byte)i.V4; - this.V5 = (byte)i.V5; - this.V6 = (byte)i.V6; - this.V7 = (byte)i.V7; - } - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index 2cf18b2456..43eebeac87 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -163,6 +163,20 @@ namespace SixLabors.ImageSharp } } + /// + /// Verifies whether a specific condition is met, throwing an exception if it's false. + /// + /// The condition + /// The error message + [Conditional("DEBUG")] + public static void IsTrue(bool target, string message) + { + if (!target) + { + throw new InvalidOperationException(message); + } + } + /// /// Verifies, that the method parameter with specified target value is false /// and throws an exception if it is found to be so. diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 34ba544726..d8cf69a52e 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp { @@ -19,12 +20,13 @@ namespace SixLabors.ImageSharp /// The target object, which cannot be null. /// The name of the parameter that is to be checked. /// is null + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNull(T value, string parameterName) where T : class { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } } @@ -35,16 +37,17 @@ namespace SixLabors.ImageSharp /// Name of the parameter. /// is null. /// is empty or contains only blanks. + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNullOrWhiteSpace(string value, string parameterName) { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } if (string.IsNullOrWhiteSpace(value)) { - throw new ArgumentException("Must not be empty or whitespace.", parameterName); + ThrowArgumentException("Must not be empty or whitespace.", parameterName); } } @@ -56,16 +59,17 @@ namespace SixLabors.ImageSharp /// Name of the parameter. /// is null. /// is empty. + [MethodImpl(InliningOptions.ShortMethod)] public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value is null) { - throw new ArgumentNullException(parameterName); + ThrowArgumentNullException(parameterName); } if (value.Count == 0) { - throw new ArgumentException("Must not be empty.", parameterName); + ThrowArgumentException("Must not be empty.", parameterName); } } @@ -79,12 +83,13 @@ namespace SixLabors.ImageSharp /// /// is greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeLessThan(TValue value, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(max) >= 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than {max}."); } } @@ -99,12 +104,13 @@ namespace SixLabors.ImageSharp /// /// is greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(max) > 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be less than or equal to {max}."); } } @@ -119,12 +125,13 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) where TValue : IComparable { if (value.CompareTo(min) <= 0) { - throw new ArgumentOutOfRangeException( + ThrowArgumentOutOfRangeException( parameterName, $"Value {value} must be greater than {min}."); } @@ -141,12 +148,13 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) where TValue : IComparable { if (value.CompareTo(min) < 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min}."); } } @@ -162,12 +170,13 @@ namespace SixLabors.ImageSharp /// /// is less than the minimum value of greater than the maximum value. /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TValue max, string parameterName) where TValue : IComparable { if (value.CompareTo(min) < 0 || value.CompareTo(max) > 0) { - throw new ArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); + ThrowArgumentOutOfRangeException(parameterName, $"Value {value} must be greater than or equal to {min} and less than or equal to {max}."); } } @@ -181,11 +190,12 @@ namespace SixLabors.ImageSharp /// /// is false /// + [MethodImpl(InliningOptions.ShortMethod)] public static void IsTrue(bool target, string parameterName, string message) { if (!target) { - throw new ArgumentException(message, parameterName); + ThrowArgumentException(message, parameterName); } } @@ -199,11 +209,12 @@ namespace SixLabors.ImageSharp /// /// is true /// + [MethodImpl(InliningOptions.ShortMethod)] public static void IsFalse(bool target, string parameterName, string message) { if (target) { - throw new ArgumentException(message, parameterName); + ThrowArgumentException(message, parameterName); } } @@ -217,11 +228,32 @@ namespace SixLabors.ImageSharp /// /// has less than items /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeSizedAtLeast(ReadOnlySpan source, int minLength, string parameterName) { if (source.Length < minLength) { - throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + } + } + + /// + /// Verifies that the 'destination' span is not shorter than 'source'. + /// + /// The source element type + /// The destination element type + /// The source span + /// The destination span + /// The name of the argument for 'destination' + [MethodImpl(InliningOptions.ShortMethod)] + public static void DestinationShouldNotBeTooShort( + ReadOnlySpan source, + Span destination, + string destinationParamName) + { + if (destination.Length < source.Length) + { + ThrowArgumentException($"Destination span is too short!", destinationParamName); } } @@ -235,56 +267,31 @@ namespace SixLabors.ImageSharp /// /// has less than items /// + [MethodImpl(InliningOptions.ShortMethod)] public static void MustBeSizedAtLeast(Span source, int minLength, string parameterName) { if (source.Length < minLength) { - throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); + ThrowArgumentException($"Span-s must be at least of length {minLength}!", parameterName); } } - /// - /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - public static void SpansMustBeSizedAtLeast( - Span source, - string sourceParamName, - Span dest, - string destParamName, - int minLength) + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentException(string message, string parameterName) { - MustBeSizedAtLeast(source, minLength, sourceParamName); - MustBeSizedAtLeast(dest, minLength, destParamName); + throw new ArgumentException(message, parameterName); } - /// - /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - public static void SpansMustBeSizedAtLeast( - ReadOnlySpan source, - string sourceParamName, - Span dest, - string destParamName, - int minLength) + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentOutOfRangeException(string parameterName, string message) + { + throw new ArgumentOutOfRangeException(parameterName, message); + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ThrowArgumentNullException(string parameterName) { - MustBeSizedAtLeast(source, minLength, sourceParamName); - MustBeSizedAtLeast(dest, minLength, destParamName); + throw new ArgumentNullException(parameterName); } } } diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 35769d96a7..0c5b051809 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -5,6 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp @@ -14,6 +15,75 @@ namespace SixLabors.ImageSharp /// internal static class ImageMaths { + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => + (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f); + + /// + /// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => + (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F)); + + /// + /// Scales a value from a 16 bit to it's 8 bit equivalent. + /// + /// The 8 bit component value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static byte DownScaleFrom16BitTo8Bit(ushort component) + { + // To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is: + // + // (V * 255) / 65535 + // + // This reduces to round(V / 257), or floor((V + 128.5)/257) + // + // Represent V as the two byte value vhi.vlo. Make a guess that the + // result is the top byte of V, vhi, then the correction to this value + // is: + // + // error = floor(((V-vhi.vhi) + 128.5) / 257) + // = floor(((vlo-vhi) + 128.5) / 257) + // + // This can be approximated using integer arithmetic (and a signed + // shift): + // + // error = (vlo-vhi+128) >> 8; + // + // The approximate differs from the exact answer only when (vlo-vhi) is + // 128; it then gives a correction of +1 when the exact correction is + // 0. This gives 128 errors. The exact answer (correct for all 16-bit + // input values) is: + // + // error = (vlo-vhi+128)*65535 >> 24; + // + // An alternative arithmetic calculation which also gives no errors is: + // + // (V * 255 + 32895) >> 16 + return (byte)(((component * 255) + 32895) >> 16); + } + + /// + /// Scales a value from an 8 bit to it's 16 bit equivalent. + /// + /// The 8 bit component value. + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257); + /// /// Determine the Greatest CommonDivisor (GCD) of two numbers. /// @@ -31,7 +101,6 @@ namespace SixLabors.ImageSharp /// /// Determine the Least Common Multiple (LCM) of two numbers. - /// TODO: This method might be useful for building a more compact /// public static int LeastCommonMultiple(int a, int b) { @@ -39,6 +108,25 @@ namespace SixLabors.ImageSharp return (a / GreatestCommonDivisor(a, b)) * b; } + /// + /// Calculates % 4 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo4(int x) => x & 3; + + /// + /// Calculates % 8 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int Modulo8(int x) => x & 7; + + /// + /// Fast (x mod m) calculator, with the restriction that + /// should be power of 2. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static int ModuloP2(int x, int m) => x & (m - 1); + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// @@ -46,7 +134,7 @@ namespace SixLabors.ImageSharp /// A number that is greater than , but less than or equal to /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int FastAbs(int x) { int y = x >> 31; @@ -58,7 +146,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 2. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow2(float x) => x * x; /// @@ -66,7 +154,7 @@ namespace SixLabors.ImageSharp /// /// A single-precision floating-point number /// The number raised to the power of 3. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Pow3(float x) => x * x * x; /// @@ -77,7 +165,7 @@ namespace SixLabors.ImageSharp /// /// The /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); /// @@ -85,7 +173,7 @@ namespace SixLabors.ImageSharp /// /// The bit depth. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth; /// @@ -94,7 +182,7 @@ namespace SixLabors.ImageSharp /// The x provided to G(x). /// The spread of the blur. /// The Gaussian G(x) - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Gaussian(float x, float sigma) { const float Numerator = 1.0f; @@ -117,7 +205,7 @@ namespace SixLabors.ImageSharp /// /// The sine cardinal of . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float SinC(float f) { if (MathF.Abs(f) > Constants.Epsilon) @@ -140,7 +228,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float GetBcValue(float x, float b, float c) { if (x < 0F) @@ -176,7 +264,7 @@ namespace SixLabors.ImageSharp /// /// The bounding . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); /// diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index ad85c4fc81..069a426d75 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// Uncomment this for verbose profiler results: +// Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN! // #define PROFILING using System.Runtime.CompilerServices; diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs new file mode 100644 index 0000000000..85c9f00748 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs @@ -0,0 +1,215 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Tuples; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.) + /// + public static class BasicIntrinsics256 + { + public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture; + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.Modulo8(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// SIMD optimized implementation for . + /// Works only with span Length divisible by 8. + /// Implementation adapted from: + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// http://stackoverflow.com/a/536278 + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat)); + VerifySpanInput(source, dest, 8); + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreted value of 32768.0f + var mask = new Vector(255); + + ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsWideOctet); + + int n = dest.Length / 8; + + for (int i = 0; i < n; i++) + { + ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i); + ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i); + d.LoadFrom(ref s); + } + + for (int i = 0; i < n; i++) + { + ref Vector df = ref Unsafe.Add(ref destBaseAsFloat, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + /// + /// Implementation of which is faster on older runtimes. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows)); + VerifySpanInput(source, dest, 8); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = Vector.Max(x, Vector.Zero); + x = Vector.Min(x, Vector.One); + + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + + /// + /// Convert all values normalized into [0..1] from 'source' + /// into 'dest' buffer of . The values are scaled up into [0-255] and rounded. + /// This implementation is SIMD optimized and works only when span Length is divisible by 8. + /// Based on: + /// + /// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions + /// + /// + internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan source, Span dest) + { + VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte)); + VerifySpanInput(source, dest, 8); + + if (source.Length == 0) + { + return; + } + + ref Vector srcBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Octet.OfByte destBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + int n = source.Length / 8; + + Vector magick = new Vector(32768.0f); + Vector scale = new Vector(255f) / new Vector(256f); + + // need to copy to a temporary struct, because + // SimdUtils.Octet.OfUInt32 temp = Unsafe.As, SimdUtils.Octet.OfUInt32>(ref x) + // does not work. TODO: This might be a CoreClr bug, need to ask/report + var temp = default(Octet.OfUInt32); + ref Vector tempRef = ref Unsafe.As>(ref temp); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + Vector x = Unsafe.Add(ref srcBase, i); + x = (x * scale) + magick; + tempRef = x; + + ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i); + d.LoadFrom(ref temp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs new file mode 100644 index 0000000000..9aeb209319 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -0,0 +1,190 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*). + /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) + /// See: + /// https://github.com/dotnet/coreclr/pull/10662 + /// API Proposal: + /// https://github.com/dotnet/corefx/issues/15957 + /// + public static class ExtendedIntrinsics + { + public static bool IsAvailable { get; } = +#if SUPPORTS_EXTENDED_INTRINSICS + Vector.IsHardwareAccelerated; +#else + false; +#endif + + /// + /// Widen and convert a vector of values into 2 vectors of -s. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void ConvertToSingle( + Vector source, + out Vector dest1, + out Vector dest2) + { + Vector.Widen(source, out Vector i1, out Vector i2); + dest1 = Vector.ConvertToSingle(i1); + dest2 = Vector.ConvertToSingle(i2); + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + if (!IsAvailable) + { + return; + } + + int remainder = ImageMaths.ModuloP2(source.Length, Vector.Count); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// Implementation , which is faster on new RyuJIT runtime. + /// + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + VerifySpanInput(source, dest, Vector.Count); + + int n = dest.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToSingle(w0); + Vector f1 = ConvertToSingle(w1); + Vector f2 = ConvertToSingle(w2); + Vector f3 = ConvertToSingle(w3); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + /// + /// Implementation of , which is faster on new .NET runtime. + /// + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + VerifySpanInput(source, dest, Vector.Count); + + int n = dest.Length / Vector.Count; + + ref Vector sourceBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + + for (int i = 0; i < n; i++) + { + ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector f0 = s; + Vector f1 = Unsafe.Add(ref s, 1); + Vector f2 = Unsafe.Add(ref s, 2); + Vector f3 = Unsafe.Add(ref s, 3); + + Vector w0 = ConvertToUInt32(f0); + Vector w1 = ConvertToUInt32(f1); + Vector w2 = ConvertToUInt32(f2); + Vector w3 = ConvertToUInt32(f3); + + Vector u0 = Vector.Narrow(w0, w1); + Vector u1 = Vector.Narrow(w2, w3); + + Vector b = Vector.Narrow(u0, u1); + + Unsafe.Add(ref destBase, i) = b; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToUInt32(Vector vf) + { + Vector maxBytes = new Vector(255f); + vf *= maxBytes; + vf += new Vector(0.5f); + vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes); + Vector vi = Vector.ConvertToInt32(vf); + return Vector.AsVectorUInt32(vi); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToSingle(Vector u) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= new Vector(1f / 255f); + return v; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs new file mode 100644 index 0000000000..565ea08f5d --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -0,0 +1,151 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// ReSharper disable MemberHidesStaticFromOuterClass +namespace SixLabors.ImageSharp +{ + internal static partial class SimdUtils + { + /// + /// Fallback implementation based on (128bit). + /// For , efficient software fallback implementations are present, + /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P + /// + public static class FallbackIntrinsics128 + { + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloatReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertByteToNormalizedFloat( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// as many elements as possible, slicing them down (keeping the remainder). + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce( + ref ReadOnlySpan source, + ref Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + + int remainder = ImageMaths.Modulo4(source.Length); + int adjustedCount = source.Length - remainder; + + if (adjustedCount > 0) + { + BulkConvertNormalizedFloatToByteClampOverflows( + source.Slice(0, adjustedCount), + dest.Slice(0, adjustedCount)); + + source = source.Slice(adjustedCount); + dest = dest.Slice(adjustedCount); + } + } + + /// + /// Implementation of using . + /// + [MethodImpl(InliningOptions.ColdPath)] + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + VerifySpanInput(source, dest, 4); + + int count = dest.Length / 4; + if (count == 0) + { + return; + } + + ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref Vector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + const float Scale = 1f / 255f; + Vector4 d = default; + + for (int i = 0; i < count; i++) + { + ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); + d.X = s.X; + d.Y = s.Y; + d.Z = s.Z; + d.W = s.W; + d *= Scale; + Unsafe.Add(ref dBase, i) = d; + } + } + + /// + /// Implementation of using . + /// + [MethodImpl(InliningOptions.ColdPath)] + internal static void BulkConvertNormalizedFloatToByteClampOverflows( + ReadOnlySpan source, + Span dest) + { + VerifySpanInput(source, dest, 4); + + int count = source.Length / 4; + if (count == 0) + { + return; + } + + ref Vector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref ByteVector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + + var half = new Vector4(0.5f); + var maxBytes = new Vector4(255f); + + for (int i = 0; i < count; i++) + { + Vector4 s = Unsafe.Add(ref sBase, i); + s *= maxBytes; + s += half; + + // I'm not sure if Vector4.Clamp() is properly implemented with intrinsics. + s = Vector4.Max(Vector4.Zero, s); + s = Vector4.Min(maxBytes, s); + + ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); + d.X = (byte)s.X; + d.Y = (byte)s.Y; + d.Z = (byte)s.Z; + d.W = (byte)s.W; + } + } + + [StructLayout(LayoutKind.Sequential)] + private struct ByteVector4 + { + public byte X; + public byte Y; + public byte Z; + public byte W; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs new file mode 100644 index 0000000000..867e7b9de1 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -0,0 +1,185 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp +{ + /// + /// Various extension and utility methods for and utilizing SIMD capabilities + /// + internal static partial class SimdUtils + { + /// + /// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte. + /// + public static bool IsAvx2CompatibleArchitecture { get; } = + Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; + + /// + /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector4 PseudoRound(this Vector4 v) + { + var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); + + return v + (sign * 0.5f); + } + + /// + /// Rounds all values in 'v' to the nearest integer following semantics. + /// Source: + /// + /// https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110 + /// + /// + /// The vector + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector FastRound(this Vector v) + { + Vector magic0 = new Vector(int.MinValue); // 0x80000000 + Vector sgn0 = Vector.AsVectorSingle(magic0); + Vector and0 = Vector.BitwiseAnd(sgn0, v); + Vector or0 = Vector.BitwiseOr(and0, new Vector(8388608.0f)); + Vector add0 = Vector.Add(v, or0); + Vector sub0 = Vector.Subtract(add0, or0); + return sub0; + } + + /// + /// Converts all input -s to -s normalized into [0..1]. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of bytes + /// The destination span of floats + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan source, Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + +#if SUPPORTS_EXTENDED_INTRINSICS + ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#else + BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); +#endif + FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest); + + // Deal with the remainder: + if (source.Length > 0) + { + ConvertByteToNormalizedFloatRemainder(source, dest); + } + } + + /// + /// Convert all values normalized into [0..1] from 'source' into 'dest' buffer of . + /// The values are scaled up into [0-255] and rounded, overflows are clamped. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of floats + /// The destination span of bytes + [MethodImpl(InliningOptions.ShortMethod)] + internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan source, Span dest) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + +#if SUPPORTS_EXTENDED_INTRINSICS + ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#else + BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); +#endif + FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest); + + // Deal with the remainder: + if (source.Length > 0) + { + ConvertNormalizedFloatToByteRemainder(source, dest); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(dest); + + // There are at most 3 elements at this point, having a for loop is overkill. + // Let's minimize the no. of instructions! + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f; + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f; + goto case 1; + case 1: + dBase = sBase / 255f; + break; + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span dest) + { + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(dest); + + switch (source.Length) + { + case 3: + Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2)); + goto case 2; + case 2: + Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1)); + goto case 1; + case 1: + dBase = ConvertToByte(sBase); + break; + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f); + + [Conditional("DEBUG")] + private static void VerifyIsAvx2Compatible(string operation) + { + if (!IsAvx2CompatibleArchitecture) + { + throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); + } + } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisible by {shouldBeDivisibleBy}!"); + } + + [Conditional("DEBUG")] + private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + { + DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue( + ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + nameof(source), + $"length should be divisible by {shouldBeDivisibleBy}!"); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs index 45ef7706dd..fd16a577ab 100644 --- a/src/ImageSharp/Common/Helpers/TestHelpers.cs +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -13,8 +13,12 @@ namespace SixLabors.ImageSharp.Common.Helpers /// Only intended to be used in tests! /// internal const string ImageSharpBuiltAgainst = -#if NETCOREAPP2_1 +#if NET472 + "netfx4.7.2"; +#elif NETCOREAPP2_1 "netcoreapp2.1"; +#elif NETSTANDARD1_3 + "netstandard1.3"; #else "netstandard2.0"; #endif diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs new file mode 100644 index 0000000000..5347efcc09 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -0,0 +1,101 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp +{ + /// + /// Implements basic math operations using tolerant comparison + /// whenever an equality check is needed. + /// + internal readonly struct TolerantMath + { + private readonly double epsilon; + + private readonly double negEpsilon; + + public TolerantMath(double epsilon) + { + DebugGuard.MustBeGreaterThan(epsilon, 0, nameof(epsilon)); + + this.epsilon = epsilon; + this.negEpsilon = -epsilon; + } + + public static TolerantMath Default { get; } = new TolerantMath(1e-8); + + /// + /// == 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsZero(double a) => a > this.negEpsilon && a < this.epsilon; + + /// + /// > 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsPositive(double a) => a > this.epsilon; + + /// + /// < 0 + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsNegative(double a) => a < this.negEpsilon; + + /// + /// == + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool AreEqual(double a, double b) => this.IsZero(a - b); + + /// + /// > + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsGreater(double a, double b) => a > b + this.epsilon; + + /// + /// < + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsLess(double a, double b) => a < b - this.epsilon; + + /// + /// >= + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsGreaterOrEqual(double a, double b) => a >= b - this.epsilon; + + /// + /// <= + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool IsLessOrEqual(double a, double b) => b >= a - this.epsilon; + + [MethodImpl(InliningOptions.ShortMethod)] + public double Ceiling(double a) + { + double rem = Math.IEEERemainder(a, 1); + if (this.IsZero(rem)) + { + return Math.Round(a); + } + + return Math.Ceiling(a); + } + + [MethodImpl(InliningOptions.ShortMethod)] + public double Floor(double a) + { + double rem = Math.IEEERemainder(a, 1); + if (this.IsZero(rem)) + { + return Math.Round(a); + } + + return Math.Floor(a); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Octet.cs b/src/ImageSharp/Common/Tuples/Octet.cs new file mode 100644 index 0000000000..539b74e324 --- /dev/null +++ b/src/ImageSharp/Common/Tuples/Octet.cs @@ -0,0 +1,109 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Tuples +{ + /// + /// Contains 8 element value tuples of various types. + /// + internal static class Octet + { + /// + /// Value tuple of -s + /// + [StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))] + public struct OfUInt32 + { + [FieldOffset(0 * sizeof(uint))] + public uint V0; + + [FieldOffset(1 * sizeof(uint))] + public uint V1; + + [FieldOffset(2 * sizeof(uint))] + public uint V2; + + [FieldOffset(3 * sizeof(uint))] + public uint V3; + + [FieldOffset(4 * sizeof(uint))] + public uint V4; + + [FieldOffset(5 * sizeof(uint))] + public uint V5; + + [FieldOffset(6 * sizeof(uint))] + public uint V6; + + [FieldOffset(7 * sizeof(uint))] + public uint V7; + + public override string ToString() + { + return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfByte src) + { + this.V0 = src.V0; + this.V1 = src.V1; + this.V2 = src.V2; + this.V3 = src.V3; + this.V4 = src.V4; + this.V5 = src.V5; + this.V6 = src.V6; + this.V7 = src.V7; + } + } + + /// + /// Value tuple of -s + /// + [StructLayout(LayoutKind.Explicit, Size = 8)] + public struct OfByte + { + [FieldOffset(0)] + public byte V0; + + [FieldOffset(1)] + public byte V1; + + [FieldOffset(2)] + public byte V2; + + [FieldOffset(3)] + public byte V3; + + [FieldOffset(4)] + public byte V4; + + [FieldOffset(5)] + public byte V5; + + [FieldOffset(6)] + public byte V6; + + [FieldOffset(7)] + public byte V7; + + public override string ToString() + { + return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})"; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref OfUInt32 src) + { + this.V0 = (byte)src.V0; + this.V1 = (byte)src.V1; + this.V2 = (byte)src.V2; + this.V3 = (byte)src.V3; + this.V4 = (byte)src.V4; + this.V5 = (byte)src.V5; + this.V6 = (byte)src.V6; + this.V7 = (byte)src.V7; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs index 309d5e2e56..cae283d628 100644 --- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs +++ b/src/ImageSharp/Common/Tuples/Vector4Pair.cs @@ -2,11 +2,12 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Common.Tuples +namespace SixLabors.ImageSharp.Tuples { /// /// Its faster to process multiple Vector4-s together, so let's pair them! /// On AVX2 this pair should be convertible to of ! + /// TODO: Investigate defining this as union with an Octet.OfSingle type. /// [StructLayout(LayoutKind.Sequential)] internal struct Vector4Pair @@ -15,8 +16,6 @@ namespace SixLabors.ImageSharp.Common.Tuples public Vector4 B; - private static readonly Vector4 Scale = new Vector4(1 / 255f); - [MethodImpl(MethodImplOptions.AggressiveInlining)] public void MultiplyInplace(float value) { @@ -52,8 +51,9 @@ namespace SixLabors.ImageSharp.Common.Tuples b = b.FastRound(); // Downscale by 1/255 - this.A *= Scale; - this.B *= Scale; + var scale = new Vector4(1 / 255f); + this.A *= scale; + this.B *= scale; } /// @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Common.Tuples public override string ToString() { - return $"{this.A}, {this.B}"; + return $"{nameof(Vector4Pair)}({this.A}, {this.B})"; } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 71852acddd..ef3ca24ee8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Looks up color values and builds the image from de-compressed RLE8 data. - /// Compresssed RLE8 stream is uncompressed by + /// Compressed RLE8 stream is uncompressed by /// /// The pixel format. /// The to assign the palette to. @@ -219,8 +219,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp where TPixel : struct, IPixel { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - using (Buffer2D buffer = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean)) { this.UncompressRle8(width, buffer.GetSpan()); @@ -233,8 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int x = 0; x < width; x++) { - rgba.Bgr = Unsafe.As(ref colors[bufferRow[x] * 4]); - color.PackFromRgba32(rgba); + color.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); pixelRow[x] = color; } } @@ -313,9 +310,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp } else { - for (int i = 0; i < cmd[0]; i++) + int max = count + cmd[0]; // as we start at the current count in the following loop, max is count + cmd[0] + byte cmd1 = cmd[1]; // store the value to avoid the repeated indexer access inside the loop + + for (; count < max; count++) { - buffer[count++] = cmd[1]; + buffer[count] = cmd1; } } } @@ -352,8 +352,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean)) { TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); - Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) @@ -363,7 +361,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int offset = 0; Span pixelRow = pixels.GetRowSpan(newY); - // TODO: Could use PixelOperations here! for (int x = 0; x < arrayWidth; x++) { int colOffset = x * ppb; @@ -371,9 +368,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp { int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; - // Stored in b-> g-> r order. - rgba.Bgr = Unsafe.As(ref colors[colorIndex]); - color.PackFromRgba32(rgba); + color.FromBgr24(Unsafe.As(ref colors[colorIndex])); pixelRow[newX] = color; } @@ -397,7 +392,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; TPixel color = default; - var rgba = new Rgba32(0, 0, 0, 255); using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) { @@ -412,11 +406,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp { short temp = BitConverter.ToInt16(buffer.Array, offset); - rgba.R = GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10); - rgba.G = GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5); - rgba.B = GetBytesFrom5BitValue(temp & Rgb16BMask); + var rgb = new Rgb24( + GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10), + GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5), + GetBytesFrom5BitValue(temp & Rgb16BMask)); - color.PackFromRgba32(rgba); + color.FromRgb24(rgb); pixelRow[x] = color; offset += 2; } @@ -444,7 +439,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.PackFromBgr24Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgr24Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } @@ -469,7 +468,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.stream.Read(row); int newY = Invert(y, height, inverted); Span pixelSpan = pixels.GetRowSpan(newY); - PixelOperations.Instance.PackFromBgra32Bytes(row.GetSpan(), pixelSpan, width); + PixelOperations.Instance.FromBgra32Bytes( + this.configuration, + row.GetSpan(), + pixelSpan, + width); } } } @@ -537,7 +540,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.metaData = meta; short bitsPerPixel = this.infoHeader.BitsPerPixel; - var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); + BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); // We can only encode at these bit rates so far. if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 44e42528cf..a67c581eb0 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -3,6 +3,8 @@ using System; using System.IO; + +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; @@ -23,6 +25,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp private readonly MemoryAllocator memoryAllocator; + private Configuration configuration; + private BmpBitsPerPixel? bitsPerPixel; /// @@ -48,6 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); ImageMetaData metaData = image.MetaData; BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance); this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; @@ -101,9 +106,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp var fileHeader = new BmpFileHeader( type: 19778, // BM - offset: 54, + fileSize: 54 + infoHeader.ImageSize, reserved: 0, - fileSize: 54 + infoHeader.ImageSize); + offset: 54); #if NETCOREAPP2_1 Span buffer = stackalloc byte[40]; @@ -163,7 +168,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgra32Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } @@ -183,7 +192,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp for (int y = pixels.Height - 1; y >= 0; y--) { Span pixelSpan = pixels.GetRowSpan(y); - PixelOperations.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length); + PixelOperations.Instance.ToBgr24Bytes( + this.configuration, + pixelSpan, + row.GetSpan(), + pixelSpan.Length); stream.Write(row.Array, 0, row.Length()); } } diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs index c44ca73f2e..219d37ca62 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs @@ -8,6 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// internal interface IBmpDecoderOptions { - // added this for consistancy so we can add stuff as required, no options currently availible + // added this for consistency so we can add stuff as required, no options currently available } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 207f126f9e..bfa91416aa 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private GifGraphicControlExtension graphicsControlExtension; /// - /// The image desciptor. + /// The image descriptor. /// private GifImageDescriptor imageDescriptor; @@ -142,8 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: - int plainLength = stream.ReadByte(); - this.Skip(plainLength); // Not supported by any known decoder. + this.SkipBlock(); // Not supported by any known decoder. break; } } @@ -190,9 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Gif switch (stream.ReadByte()) { case GifConstants.GraphicControlLabel: - - // Skip graphic control extension block - this.Skip(0); + this.SkipBlock(); // Skip graphic control extension block break; case GifConstants.CommentLabel: this.ReadComments(); @@ -201,8 +198,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: - int plainLength = stream.ReadByte(); - this.Skip(plainLength); // Not supported by any known decoder. + this.SkipBlock(); // Not supported by any known decoder. break; } } @@ -288,24 +284,27 @@ namespace SixLabors.ImageSharp.Formats.Gif // Could be XMP or something else not supported yet. // Back up and skip. this.stream.Position -= appLength + 1; - this.Skip(appLength); + this.SkipBlock(appLength); return; } - this.Skip(appLength); // Not supported by any known decoder. + this.SkipBlock(appLength); // Not supported by any known decoder. } /// - /// Skips the designated number of bytes in the stream. + /// Skips over a block or reads its terminator. + /// The length of the block to skip. /// - /// The number of bytes to skip. - private void Skip(int length) + private void SkipBlock(int blockSize = 0) { - this.stream.Skip(length); + if (blockSize > 0) + { + this.stream.Skip(blockSize); + } int flag; - while ((flag = this.stream.ReadByte()) != 0) + while ((flag = this.stream.ReadByte()) > 0) { this.stream.Skip(flag); } @@ -370,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor); // Skip any remaining blocks - this.Skip(0); + this.SkipBlock(); } finally { @@ -481,22 +480,36 @@ namespace SixLabors.ImageSharp.Formats.Gif } ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); - var rgba = new Rgba32(0, 0, 0, 255); + bool transFlag = this.graphicsControlExtension.TransparencyFlag; - // #403 The left + width value can be larger than the image width - for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + if (!transFlag) { - int index = Unsafe.Add(ref indicesRef, i); - - if (!this.graphicsControlExtension.TransparencyFlag - || this.graphicsControlExtension.TransparencyIndex != index) + // #403 The left + width value can be larger than the image width + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) { + int index = Unsafe.Add(ref indicesRef, i); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); - rgba.Rgb = colorTable[index]; - pixel.PackFromRgba32(rgba); + Rgb24 rgb = colorTable[index]; + pixel.FromRgb24(rgb); + + i++; } + } + else + { + byte transIndex = this.graphicsControlExtension.TransparencyIndex; + for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) + { + int index = Unsafe.Add(ref indicesRef, i); + if (transIndex != index) + { + ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); + Rgb24 rgb = colorTable[index]; + pixel.FromRgb24(rgb); + } - i++; + i++; + } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ae0366e6e6..a922f30117 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,11 +2,13 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; @@ -21,10 +23,15 @@ namespace SixLabors.ImageSharp.Formats.Gif internal sealed class GifEncoderCore { /// - /// Used for allocating memory during procesing operations. + /// Used for allocating memory during processing operations. /// private readonly MemoryAllocator memoryAllocator; + /// + /// Configuration bound to the encoding operation. + /// + private Configuration configuration; + /// /// A reusable buffer used to reduce allocations. /// @@ -80,6 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); + ImageMetaData metaData = image.MetaData; this.gifMetaData = metaData.GetFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; @@ -87,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Quantize the image returning a palette. QuantizedFrame quantized = - this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + this.quantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame); // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); @@ -133,7 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel { - var palleteQuantizer = new PaletteQuantizer(this.quantizer.Diffuser); + var palleteQuantizer = new PaletteQuantizer(quantized.Palette, this.quantizer.Diffuser); for (int i = 0; i < image.Frames.Count; i++) { @@ -149,8 +158,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized - = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -170,15 +178,17 @@ namespace SixLabors.ImageSharp.Formats.Gif if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. - if (previousFrame != null - && previousMeta.ColorTableLength != frameMetaData.ColorTableLength - && frameMetaData.ColorTableLength > 0) + if (previousFrame != null && previousMeta.ColorTableLength != frameMetaData.ColorTableLength + && frameMetaData.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer(frameMetaData.ColorTableLength).QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer( + image.GetConfiguration(), + frameMetaData.ColorTableLength).QuantizeFrame(frame); } else { - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(frame); } } @@ -210,16 +220,20 @@ namespace SixLabors.ImageSharp.Formats.Gif { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - Rgba32 trans = default; + int length = quantized.Palette.Length; - ref TPixel paletteRef = ref MemoryMarshal.GetReference(quantized.Palette.AsSpan()); - for (int i = quantized.Palette.Length - 1; i >= 0; i--) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(length)) { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgba32(ref trans); - if (trans.Equals(default)) + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan); + + for (int i = quantized.Palette.Length - 1; i >= 0; i--) { - index = i; + if (Unsafe.Add(ref paletteRef, i).Equals(default)) + { + index = i; + } } } @@ -314,7 +328,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The stream to write to. private void WriteComments(ImageMetaData metadata, Stream stream) { - if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) || string.IsNullOrEmpty(property.Value)) + if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) + || string.IsNullOrEmpty(property.Value)) { return; } @@ -406,24 +421,17 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteColorTable(QuantizedFrame image, Stream stream) where TPixel : struct, IPixel { - int pixelCount = image.Palette.Length; - - // The maximium number of colors for the bit depth + // The maximum number of colors for the bit depth int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; - Rgb24 rgb = default; + int pixelCount = image.Palette.Length; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) { - ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan()); - ref Rgb24 rgb24Ref = ref Unsafe.As(ref MemoryMarshal.GetReference(colorTable.GetSpan())); - for (int i = 0; i < pixelCount; i++) - { - ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); - entry.ToRgb24(ref rgb); - Unsafe.Add(ref rgb24Ref, i) = rgb; - } - - // Write the palette to the stream + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + image.Palette.AsSpan(), + colorTable.GetSpan(), + pixelCount); stream.Write(colorTable.Array, 0, colorTableLength); } } diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index e390dfd54c..2d32fd23aa 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Gif }; /// - /// The maximium number of bits/code. + /// The maximum number of bits/code. /// private const int MaxBits = 12; @@ -210,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// flush the packet to disk. /// /// The character to add. - /// The reference to the storage for packat accumulators + /// The reference to the storage for packet accumulators /// The stream to write to. [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AddCharacter(byte c, ref byte accumulatorsRef, Stream stream) @@ -309,10 +309,10 @@ namespace SixLabors.ImageSharp.Formats.Gif // Non-empty slot if (Unsafe.Add(ref hashTableRef, i) >= 0) { - int disp = hsizeReg - i; - if (i == 0) + int disp = 1; + if (i != 0) { - disp = 1; + disp = hsizeReg - i; } do diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 94191c1493..3cd289df76 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Formats string Name { get; } /// - /// Gets the default mimetype that the image foramt uses + /// Gets the default mimetype that the image format uses /// string DefaultMimeType { get; } /// - /// Gets all the mimetypes that have been used by this image foramt. + /// Gets all the mimetypes that have been used by this image format. /// IEnumerable MimeTypes { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs index 5601a94366..60fec25d29 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs @@ -10,7 +10,7 @@ using System.Text; namespace SixLabors.ImageSharp.Formats.Jpeg.Components { /// - /// Represents a Jpeg block with coefficiens. + /// Represents a Jpeg block with coefficients. /// // ReSharper disable once InconsistentNaming internal unsafe struct Block8x8 : IEquatable @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Gets or sets a value in a row+coulumn of the 8x8 block + /// Gets or sets a value in a row+column of the 8x8 block /// /// The x position index in the row /// The column index @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Calculate the total sum of absoulute differences of elements in 'a' and 'b'. + /// Calculate the total sum of absolute differences of elements in 'a' and 'b'. /// public static long TotalDifference(ref Block8x8 a, ref Block8x8 b) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index b7dd125a88..6bf9c8483a 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -3,64 +3,41 @@ using System.Numerics; using System.Runtime.CompilerServices; - using SixLabors.ImageSharp.Memory; +// ReSharper disable UseObjectOrCollectionInitializer // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Formats.Jpeg.Components { internal partial struct Block8x8F { /// - /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical. + /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors. /// + [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale) { if (horizontalScale == 1 && verticalScale == 1) { - this.CopyTo(area); + this.Copy1x1Scale(area); return; } - else if (horizontalScale == 2 && verticalScale == 2) + + if (horizontalScale == 2 && verticalScale == 2) { - this.CopyTo2x2(area); + this.Copy2x2Scale(area); return; } - ref float destBase = ref area.GetReferenceToOrigin(); - - // TODO: Optimize: implement all the cases with loopless special code! (T4?) - for (int y = 0; y < 8; y++) - { - int yy = y * verticalScale; - int y8 = y * 8; - - for (int x = 0; x < 8; x++) - { - int xx = x * horizontalScale; - - float value = this[y8 + x]; - - for (int i = 0; i < verticalScale; i++) - { - int baseIdx = ((yy + i) * area.Stride) + xx; - - for (int j = 0; j < horizontalScale; j++) - { - // area[xx + j, yy + i] = value; - Unsafe.Add(ref destBase, baseIdx + j) = value; - } - } - } - } + // TODO: Optimize: implement all cases with scale-specific, loopless code! + this.CopyArbitraryScale(area, horizontalScale, verticalScale); } - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(in BufferArea area) + public void Copy1x1Scale(in BufferArea destination) { ref byte selfBase = ref Unsafe.As(ref this); - ref byte destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); - int destStride = area.Stride * sizeof(float); + ref byte destBase = ref Unsafe.As(ref destination.GetReferenceToOrigin()); + int destStride = destination.Stride * sizeof(float); CopyRowImpl(ref selfBase, ref destBase, destStride, 0); CopyRowImpl(ref selfBase, ref destBase, destStride, 1); @@ -80,76 +57,86 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); } - private void CopyTo2x2(in BufferArea area) + private void Copy2x2Scale(in BufferArea area) { - ref float destBase = ref area.GetReferenceToOrigin(); - int destStride = area.Stride; - - this.WidenCopyImpl2x2(ref destBase, 0, destStride); - this.WidenCopyImpl2x2(ref destBase, 1, destStride); - this.WidenCopyImpl2x2(ref destBase, 2, destStride); - this.WidenCopyImpl2x2(ref destBase, 3, destStride); - this.WidenCopyImpl2x2(ref destBase, 4, destStride); - this.WidenCopyImpl2x2(ref destBase, 5, destStride); - this.WidenCopyImpl2x2(ref destBase, 6, destStride); - this.WidenCopyImpl2x2(ref destBase, 7, destStride); + ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); + int destStride = area.Stride / 2; + + this.WidenCopyRowImpl2x2(ref destBase, 0, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 1, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 2, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 3, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 4, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 5, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 6, destStride); + this.WidenCopyRowImpl2x2(ref destBase, 7, destStride); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WidenCopyImpl2x2(ref float destBase, int row, int destStride) + private void WidenCopyRowImpl2x2(ref Vector2 destBase, int row, int destStride) { - ref Vector4 selfLeft = ref Unsafe.Add(ref this.V0L, 2 * row); - ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); - ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); - - Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X; - Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X; - Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y; - Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y; - Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z; - Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z; - Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W; - Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W; - - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W; - Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W; + ref Vector4 sLeft = ref Unsafe.Add(ref this.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + int offset = 2 * row * destStride; + ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); + ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); + + var xyLeft = new Vector4(sLeft.X); + xyLeft.Z = sLeft.Y; + xyLeft.W = sLeft.Y; + + var zwLeft = new Vector4(sLeft.Z); + zwLeft.Z = sLeft.W; + zwLeft.W = sLeft.W; + + var xyRight = new Vector4(sRight.X); + xyRight.Z = sRight.Y; + xyRight.W = sRight.Y; + + var zwRight = new Vector4(sRight.Z); + zwRight.Z = sRight.W; + zwRight.W = sRight.W; + + dTopLeft = xyLeft; + Unsafe.Add(ref dTopLeft, 1) = zwLeft; + Unsafe.Add(ref dTopLeft, 2) = xyRight; + Unsafe.Add(ref dTopLeft, 3) = zwRight; + + dBottomLeft = xyLeft; + Unsafe.Add(ref dBottomLeft, 1) = zwLeft; + Unsafe.Add(ref dBottomLeft, 2) = xyRight; + Unsafe.Add(ref dBottomLeft, 3) = zwRight; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void WidenCopyImpl(ref Vector4 s, ref float destBase) + [MethodImpl(InliningOptions.ColdPath)] + private void CopyArbitraryScale(BufferArea area, int horizontalScale, int verticalScale) { - Unsafe.Add(ref destBase, 0) = s.X; - Unsafe.Add(ref destBase, 1) = s.X; - Unsafe.Add(ref destBase, 2) = s.Y; - Unsafe.Add(ref destBase, 3) = s.Y; - Unsafe.Add(ref destBase, 4) = s.Z; - Unsafe.Add(ref destBase, 5) = s.Z; - Unsafe.Add(ref destBase, 6) = s.W; - Unsafe.Add(ref destBase, 7) = s.W; + ref float destBase = ref area.GetReferenceToOrigin(); + + for (int y = 0; y < 8; y++) + { + int yy = y * verticalScale; + int y8 = y * 8; + + for (int x = 0; x < 8; x++) + { + int xx = x * horizontalScale; + + float value = this[y8 + x]; + + for (int i = 0; i < verticalScale; i++) + { + int baseIdx = ((yy + i) * area.Stride) + xx; + + for (int j = 0; j < horizontalScale; j++) + { + // area[xx + j, yy + i] = value; + Unsafe.Add(ref destBase, baseIdx + j) = value; + } + } + } + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs index e83896f587..09ed6408d7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Transpose the block into the destination block. /// /// The destination block - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void TransposeInto(ref Block8x8F d) { d.V0L.X = V0L.X; @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// AVX2-only variant for executing and in one step. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void NormalizeColorsAndRoundInplaceAvx2() { Vector off = new Vector(128f); @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block from 'source' doing short -> float conversion. /// - public void LoadFrom(ref Block8x8 source) + public void LoadFromInt16Scalar(ref Block8x8 source) { ref short selfRef = ref Unsafe.As(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt index 82d82ef0c2..f93ee6522d 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Transpose the block into the destination block. /// /// The destination block - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void TransposeInto(ref Block8x8F d) { <# @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// AVX2-only variant for executing and in one step. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void NormalizeColorsAndRoundInplaceAvx2() { Vector off = new Vector(128f); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block from 'source' doing short -> float conversion. /// - public void LoadFrom(ref Block8x8 source) + public void LoadFromInt16Scalar(ref Block8x8 source) { ref short selfRef = ref Unsafe.As(ref source); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index 59fc234c42..81393342d6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// The float value at the specified index public float this[int idx] { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get { GuardBlockIndex(idx); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return Unsafe.Add(ref selfRef, idx); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { GuardBlockIndex(idx); @@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Fill the block with defaults (zeroes) /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void Clear() { // The cheapest way to do this in C#: @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Load raw 32bit floating point data from source /// /// Source - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void LoadFrom(Span source) { ref byte s = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Block pointer /// Source - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source) { blockPtr->LoadFrom(source); @@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest /// /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void CopyTo(Span dest) { ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Pointer to block /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) { float* fPtr = (float*)blockPtr; @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Block pointer /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest) { blockPtr->CopyTo(dest); @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Copy raw 32bit floating point data to dest /// /// Destination - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public unsafe void CopyTo(float[] dest) { fixed (void* ptr = &this.V0L) @@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Multiply all elements of the block. /// /// The value to multiply by - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void MultiplyInplace(float value) { this.V0L *= value; @@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Multiply all elements of the block by the corresponding elements of 'other' /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void MultiplyInplace(ref Block8x8F other) { this.V0L *= other.V0L; @@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// Adds a vector to all elements of the block. /// /// The added vector - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public void AddToAllInplace(Vector4 diff) { this.V0L += diff; @@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } /// - /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block. + /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block. /// /// The destination block. /// The source block. @@ -420,7 +420,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static void DivideRoundAll(ref Block8x8F a, ref Block8x8F b) { a.V0L = DivideRound(a.V0L, b.V0L); @@ -493,25 +493,69 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } } + [MethodImpl(InliningOptions.ShortMethod)] + public void LoadFrom(ref Block8x8 source) + { +#if SUPPORTS_EXTENDED_INTRINSICS + if (SimdUtils.IsAvx2CompatibleArchitecture) + { + this.LoadFromInt16ExtendedAvx2(ref source); + return; + } +#endif + this.LoadFromInt16Scalar(ref source); + } + + /// + /// Loads values from using extended AVX2 intrinsics. + /// + /// The source + public void LoadFromInt16ExtendedAvx2(ref Block8x8 source) + { + DebugGuard.IsTrue( + SimdUtils.IsAvx2CompatibleArchitecture, + "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!"); + + ref Vector sRef = ref Unsafe.As>(ref source); + ref Vector dRef = ref Unsafe.As>(ref this); + + // Vector.Count == 16 on AVX2 + // We can process 2 block rows in a single step + SimdUtils.ExtendedIntrinsics.ConvertToSingle(sRef, out Vector top, out Vector bottom); + dRef = top; + Unsafe.Add(ref dRef, 1) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 1), out top, out bottom); + Unsafe.Add(ref dRef, 2) = top; + Unsafe.Add(ref dRef, 3) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 2), out top, out bottom); + Unsafe.Add(ref dRef, 4) = top; + Unsafe.Add(ref dRef, 5) = bottom; + + SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 3), out top, out bottom); + Unsafe.Add(ref dRef, 6) = top; + Unsafe.Add(ref dRef, 7) = bottom; + } + /// public override string ToString() { var sb = new StringBuilder(); sb.Append('['); - for (int i = 0; i < Size; i++) + for (int i = 0; i < Size - 1; i++) { sb.Append(this[i]); - if (i < Size - 1) - { - sb.Append(','); - } + sb.Append(','); } + sb.Append(this[Size - 1]); + sb.Append(']'); return sb.ToString(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Vector NormalizeAndRound(Vector row, Vector off, Vector max) { row += off; @@ -520,13 +564,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components return row.FastRound(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) { // sign(dividend) = max(min(dividend, 1), -1) var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One); - // AlmostRound(dividend/divisor) = dividend/divisior + 0.5*sign(dividend) + // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) return (dividend / divisor) + (sign * Offset); } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs index 5d7a31a12b..7424145c3b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -3,6 +3,8 @@ using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -17,24 +19,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public override void ConvertToRgba(in ComponentValues values, Span result) { - // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! - ReadOnlySpan yVals = values.Component0; - - var v = new Vector4(0, 0, 0, 1); - var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F); + ref float sBase = ref MemoryMarshal.GetReference(values.Component0); + ref Vector4 dBase = ref MemoryMarshal.GetReference(result); + for (int i = 0; i < result.Length; i++) { - float y = yVals[i]; - - v.X = y; - v.Y = y; - v.Z = y; - + var v = new Vector4(Unsafe.Add(ref sBase, i)); + v.W = 1f; v *= scale; - - result[i] = v; + Unsafe.Add(ref dBase, i) = v; } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index 4b2626c582..23aa1acbe6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { @@ -32,11 +32,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// SIMD convert using buffers of sizes divisable by 8. + /// SIMD convert using buffers of sizes divisible by 8. /// internal static void ConvertCore(in ComponentValues values, Span result) { - DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisable by 8!"); + DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisible by 8!"); ref Vector4Pair yBase = ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0)); @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref r, ref g, ref b); + destination.Pack(ref r, ref g, ref b); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index ab4947e65c..f0a70a6f38 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -6,7 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Tuples; +using SixLabors.ImageSharp.Tuples; // ReSharper disable ImpureMethodCallOnReadonlyValueField namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters } /// - /// SIMD convert using buffers of sizes divisable by 8. + /// SIMD convert using buffers of sizes divisible by 8. /// internal static void ConvertCore(in ComponentValues values, Span result) { @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); - destination.Collect(ref rr, ref gg, ref bb); + destination.Pack(ref rr, ref gg, ref bb); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 60abb7fb2c..a44ebf89d1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -6,8 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Tuples; using SixLabors.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters internal abstract partial class JpegColorConverter { /// - /// The avalilable converters + /// The available converters /// private static readonly JpegColorConverter[] Converters = { @@ -157,9 +157,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; /// - /// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. + /// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ... /// - public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) + public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) { this.V0.X = r.A.X; this.V0.Y = g.A.X; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 24d570bf1c..9e134746bc 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // Figure F.15: generate decoding tables for bit-sequential decoding. - // Compute largest code + 1 for this size. preshifted as we needit later. + // Compute largest code + 1 for this size. preshifted as we need it later. Unsafe.Add(ref maxcodeRef, k) = code << (16 - k); code <<= 1; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs index c033980336..2492a985a8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder @@ -43,16 +42,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Gets the storing the "raw" frequency-domain decoded + unzigged blocks. - /// We need to apply IDCT and dequantiazition to transform them into color-space blocks. + /// We need to apply IDCT and dequantization to transform them into color-space blocks. /// Buffer2D SpectralBlocks { get; } - - /// - /// Gets a reference to the at the given row and column index from - /// - /// The column - /// The row - /// The - ref Block8x8 GetBlockReference(int column, int row); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs index dace78b337..1454bb5b12 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Size ImageSizeInPixels { get; } /// - /// Gets the number of coponents. + /// Gets the number of components. /// int ComponentCount { get; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index f153ce062a..4bff492486 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The minor version /// The units for the density values /// The horizontal pixel density - /// The veritcal pixel density + /// The vertical pixel density private JFifMarker(byte majorVersion, byte minorVersion, byte densityUnits, short xDensity, short yDensity) { Guard.MustBeGreaterThan(xDensity, 0, nameof(xDensity)); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 0108e30815..da4b2847b8 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// - Dequantize /// - Applying IDCT /// - Level shift by +128, clip to [0, 255] - /// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in + /// - Copy the resulting color values into 'destArea' scaling up the block by amount defined in /// /// The source block. /// The destination buffer area. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs index 65a584c4f2..ef03582d69 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs @@ -128,21 +128,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors); } - this.SpectralBlocks = this.memoryAllocator.Allocate2D(blocksPerColumnForMcu, blocksPerLineForMcu + 1, AllocationOptions.Clean); - } + int totalNumberOfBlocks = blocksPerColumnForMcu * (blocksPerLineForMcu + 1); + int width = this.WidthInBlocks + 1; + int height = totalNumberOfBlocks / width; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref Block8x8 GetBlockReference(int column, int row) - { - int offset = ((this.WidthInBlocks + 1) * row) + column; - return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.GetSpan()), offset); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref short GetBlockDataReference(int column, int row) - { - ref Block8x8 blockRef = ref this.GetBlockReference(column, row); - return ref Unsafe.As(ref blockRef); + this.SpectralBlocks = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs index 890f402595..94ec600dd5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; using SixLabors.Memory; @@ -20,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private int currentComponentRowInBlocks; /// - /// The size of the area in corrsponding to one 8x8 Jpeg block + /// The size of the area in corresponding to one 8x8 Jpeg block /// private readonly Size blockAreaSize; @@ -88,12 +90,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int yBuffer = y * this.blockAreaSize.Height; - for (int x = 0; x < this.SizeInBlocks.Width; x++) - { - int xBlock = x; - int xBuffer = x * this.blockAreaSize.Width; + Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock); + + ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow); - ref Block8x8 block = ref this.Component.GetBlockReference(xBlock, yBlock); + for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++) + { + ref Block8x8 block = ref Unsafe.Add(ref blockRowBase, xBlock); + int xBuffer = xBlock * this.blockAreaSize.Width; BufferArea destArea = this.ColorBuffer.GetArea( xBuffer, diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs index 94382553ca..7ce86b4c9b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs @@ -26,6 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// internal class JpegImagePostProcessor : IDisposable { + private readonly Configuration configuration; + /// /// The number of block rows to be processed in one Step. /// @@ -49,15 +51,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Initializes a new instance of the class. /// - /// The to use for buffer allocations. + /// The to configure internal operations. /// The representing the uncompressed spectral Jpeg data - public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg) + public JpegImagePostProcessor(Configuration configuration, IRawJpegData rawJpeg) { + this.configuration = configuration; this.RawJpeg = rawJpeg; IJpegComponent c0 = rawJpeg.Components.First(); this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep; this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep); + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray(); this.rgbaBuffer = memoryAllocator.Allocate(rawJpeg.ImageSizeInPixels.Width); this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace); @@ -159,7 +163,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder Span destRow = destination.GetPixelRowSpan(yy); - PixelOperations.Instance.PackFromVector4(this.rgbaBuffer.GetSpan(), destRow, destination.Width); + // TODO: Investigate if slicing is actually necessary + PixelOperations.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 351e453484..48abca2a4e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -1,8 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.IO; +using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { @@ -142,7 +144,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static uint LRot(uint x, int y) => (x << y) | (x >> (32 - y)); private void ParseBaselineData() @@ -179,10 +181,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; + int mcuRow = mcu / mcusPerLine; + // Scan out an mcu's worth of this component; that's just determined // by the basic H and V specified for the component for (int y = 0; y < v; y++) { + int blockRow = (mcuRow * v) + y; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); for (int x = 0; x < h; x++) { if (this.eof) @@ -190,15 +196,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int mcuRow = mcu / mcusPerLine; int mcuCol = mcu % mcusPerLine; - int blockRow = (mcuRow * v) + y; int blockCol = (mcuCol * h) + x; this.DecodeBlockBaseline( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable, ref acHuffmanTable, ref fastACRef); @@ -236,6 +239,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int mcu = 0; for (int j = 0; j < h; j++) { + // TODO: Isn't blockRow == j actually? + int blockRow = mcu / w; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int i = 0; i < w; i++) { if (this.eof) @@ -243,13 +250,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int blockRow = mcu / w; + // TODO: Isn't blockCol == i actually? int blockCol = mcu % w; this.DecodeBlockBaseline( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable, ref acHuffmanTable, ref fastACRef); @@ -299,6 +305,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // by the basic H and V specified for the component for (int y = 0; y < v; y++) { + int mcuRow = mcu / mcusPerLine; + int blockRow = (mcuRow * v) + y; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int x = 0; x < h; x++) { if (this.eof) @@ -306,15 +316,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int mcuRow = mcu / mcusPerLine; int mcuCol = mcu % mcusPerLine; - int blockRow = (mcuRow * v) + y; int blockCol = (mcuCol * h) + x; this.DecodeBlockProgressiveDC( component, - blockRow, - blockCol, + ref blockSpan[blockCol], ref dcHuffmanTable); } } @@ -351,6 +358,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int mcu = 0; for (int j = 0; j < h; j++) { + // TODO: isn't blockRow == j actually? + int blockRow = mcu / w; + Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow); + for (int i = 0; i < w; i++) { if (this.eof) @@ -358,23 +369,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder return; } - int blockRow = mcu / w; + // TODO: isn't blockCol == i actually? int blockCol = mcu % w; + ref Block8x8 block = ref blockSpan[blockCol]; + if (this.spectralStart == 0) { this.DecodeBlockProgressiveDC( component, - blockRow, - blockCol, + ref block, ref dcHuffmanTable); } else { this.DecodeBlockProgressiveAC( - component, - blockRow, - blockCol, + ref block, ref acHuffmanTable, ref fastACRef); } @@ -391,8 +401,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockBaseline( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable dcTable, ref HuffmanTable acTable, ref short fastACRef) @@ -405,7 +414,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder JpegThrowHelper.ThrowBadHuffmanCode(); } - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); int diff = t != 0 ? this.ExtendReceive(t) : 0; int dc = component.DcPredictor + diff; @@ -470,8 +479,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder private void DecodeBlockProgressiveDC( JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable dcTable) { if (this.spectralEnd != 0) @@ -481,7 +489,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.CheckBits(); - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); if (this.successiveHigh == 0) { @@ -505,9 +513,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } private void DecodeBlockProgressiveAC( - JpegComponent component, - int row, - int col, + ref Block8x8 block, ref HuffmanTable acTable, ref short fastACRef) { @@ -516,7 +522,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder JpegThrowHelper.ThrowImageFormatException("Can't merge DC and AC."); } - ref short blockDataRef = ref component.GetBlockDataReference(col, row); + ref short blockDataRef = ref Unsafe.As(ref block); if (this.successiveHigh == 0) { @@ -749,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder [MethodImpl(InliningOptions.ColdPath)] private void FillBuffer() { - // Attempt to load at least the minimum nbumber of required bits into the buffer. + // Attempt to load at least the minimum number of required bits into the buffer. // We fail to do so only if we hit a marker or reach the end of the input stream. do { @@ -906,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // If it's NOT a restart, then just bail, so we get corrupt data rather than no data. - // Reset the stream to before any bad markers to ensure we can read sucessive segments. + // Reset the stream to before any bad markers to ensure we can read successive segments. if (this.badMarker) { this.stream.Position = this.markerPosition; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs index a0cc9ee8e5..cb0810985e 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Initializes the YCbCr tables /// - /// The intialized + /// The initialized public static RgbToYCbCrTables Create() { RgbToYCbCrTables tables = default; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs index 311ffed24b..d775425c5c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// On-stack worker struct to efficiently encapsulate the TPixel -> Rgb24 -> YCbCr conversion chain of 8x8 pixel blocks. /// /// The pixel type to work on - internal struct YCbCrForwardConverter + internal ref struct YCbCrForwardConverter where TPixel : struct, IPixel { /// @@ -53,12 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder /// /// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (, , ) /// - public void Convert(IPixelSource pixels, int x, int y) + public void Convert(ImageFrame frame, int x, int y) { - this.pixelBlock.LoadAndStretchEdges(pixels, x, y); + this.pixelBlock.LoadAndStretchEdges(frame, x, y); Span rgbSpan = this.rgbBlock.AsSpanUnsafe(); - PixelOperations.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan, 64); + PixelOperations.Instance.ToRgb24(frame.Configuration, this.pixelBlock.AsSpanUnsafe(), rgbSpan); ref float yBlockStart = ref Unsafe.As(ref this.Y); ref float cbBlockStart = ref Unsafe.As(ref this.Cb); diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs index 2e20da266b..c795ccc8b5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// FOR TESTING ONLY! - /// Gets or sets a value in a row+coulumn of the 8x8 block + /// Gets or sets a value in a row+column of the 8x8 block /// /// The x position index in the row /// The column index diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 22d9cbdee4..f6da9cb2ec 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -51,12 +51,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private readonly byte[] markerBuffer = new byte[2]; /// - /// The DC HUffman tables + /// The DC Huffman tables /// private HuffmanTables dcHuffmanTables; /// - /// The AC HUffman tables + /// The AC Huffman tables /// private HuffmanTables acHuffmanTables; @@ -856,10 +856,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void ProcessStartOfScanMarker() { int selectorsCount = this.InputStream.ReadByte(); - int componentIndex = -1; for (int i = 0; i < selectorsCount; i++) { - componentIndex = -1; + int componentIndex = -1; int selector = this.InputStream.ReadByte(); for (int j = 0; j < this.Frame.ComponentIds.Length; j++) @@ -913,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The table index /// The codelengths /// The values - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) => tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); @@ -921,7 +920,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// Reads a from the stream advancing it by two bytes /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private ushort ReadUint16() { this.InputStream.Read(this.markerBuffer, 0, 2); @@ -936,12 +935,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private Image PostProcessIntoImage() where TPixel : struct, IPixel { - using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this)) + var image = Image.CreateUninitialized( + this.configuration, + this.ImageWidth, + this.ImageHeight, + this.MetaData); + + using (var postProcessor = new JpegImagePostProcessor(this.configuration, this)) { - var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); postProcessor.PostProcess(image.Frames.RootFrame); - return image; } + + return image; } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index a4677ba2b7..0dcbd8fef7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -822,11 +822,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { for (int i = 0; i < componentCount; i++) { - this.buffer[(3 * i) + 6] = (byte)(i + 1); + int i3 = 3 * i; + this.buffer[i3 + 6] = (byte)(i + 1); // We use 4:2:0 chroma subsampling by default. - this.buffer[(3 * i) + 7] = subsamples[i]; - this.buffer[(3 * i) + 8] = chroma[i]; + this.buffer[i3 + 7] = subsamples[i]; + this.buffer[i3 + 8] = chroma[i]; } } diff --git a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs index 07fc688d50..6ab0dd6576 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks /// /// Constructs the PngPhysicalChunkData from the provided metadata. - /// If the resolution units are not in meters, they are automatically convereted. + /// If the resolution units are not in meters, they are automatically converted. /// /// The metadata. /// The constructed PngPhysicalChunkData instance. diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 4ffc39bdbd..4cd61e043d 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) - int offset = bytesPerPixel + 1; // Add one bcause x starts at one. + int offset = bytesPerPixel + 1; // Add one because x starts at one. int x = 1; for (; x < offset; x++) { diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs index bd0b932056..5b650ac2a0 100644 --- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs @@ -6,7 +6,7 @@ using System.Text; namespace SixLabors.ImageSharp.Formats.Png { /// - /// The optioas for decoding png images + /// The options for decoding png images /// internal interface IPngDecoderOptions { diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index 7654c17014..1b251a5748 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -56,10 +56,10 @@ namespace SixLabors.ImageSharp.Formats.Png Text = 0x74455874U, /// - /// This chunk specifies that the image uses simple transparency: + /// The tRNS chunk specifies that the image uses simple transparency: /// either alpha values associated with palette entries (for indexed-color images) /// or a single transparent color (for grayscale and true color images). /// - PaletteAlpha = 0x74524E53U + Transparency = 0x74524E53U } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d66ac6c0d2..9ffac5e626 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -124,31 +124,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// private PngColorType pngColorType; - /// - /// Represents any color in an 8 bit Rgb24 encoded png that should be transparent - /// - private Rgb24 rgb24Trans; - - /// - /// Represents any color in a 16 bit Rgb24 encoded png that should be transparent - /// - private Rgb48 rgb48Trans; - - /// - /// Represents any color in an 8 bit grayscale encoded png that should be transparent - /// - private byte luminanceTrans; - - /// - /// Represents any color in a 16 bit grayscale encoded png that should be transparent - /// - private ushort luminance16Trans; - - /// - /// Whether the image has transparency chunk and markers were decoded - /// - private bool hasTrans; - /// /// The next chunk of data to return /// @@ -213,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) { deframeStream.AllocateNewBytes(chunk.Length); - this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); + this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame, pngMetaData); } break; @@ -222,11 +197,11 @@ namespace SixLabors.ImageSharp.Formats.Png Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); this.palette = pal; break; - case PngChunkType.PaletteAlpha: + case PngChunkType.Transparency: byte[] alpha = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha); + this.AssignTransparentMarkers(alpha, pngMetaData); break; case PngChunkType.Text: this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length)); @@ -496,16 +471,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing data. /// The pixel data. - private void ReadScanlines(Stream dataStream, ImageFrame image) + /// The png meta data + private void ReadScanlines(Stream dataStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) { - this.DecodeInterlacedPixelData(dataStream, image); + this.DecodeInterlacedPixelData(dataStream, image, pngMetaData); } else { - this.DecodePixelData(dataStream, image); + this.DecodePixelData(dataStream, image, pngMetaData); } } @@ -515,7 +491,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The image to decode to. - private void DecodePixelData(Stream compressedStream, ImageFrame image) + /// The png meta data + private void DecodePixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { while (this.currentRow < this.header.Height) @@ -555,7 +532,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("Unknown filter type."); } - this.ProcessDefilteredScanline(scanlineSpan, image); + this.ProcessDefilteredScanline(scanlineSpan, image, pngMetaData); this.SwapBuffers(); this.currentRow++; @@ -569,7 +546,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The current image. - private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image) + /// The png meta data + private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData) where TPixel : struct, IPixel { while (true) @@ -626,7 +604,7 @@ namespace SixLabors.ImageSharp.Formats.Png } Span rowSpan = image.GetPixelRowSpan(this.currentRow); - this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); + this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, pngMetaData, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); this.SwapBuffers(); @@ -654,7 +632,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The image - private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels) + /// The png meta data + private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetaData pngMetaData) where TPixel : struct, IPixel { Span rowSpan = pixels.GetPixelRowSpan(this.currentRow); @@ -674,9 +653,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.header, scanlineSpan, rowSpan, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.TransparentGray16.GetValueOrDefault(), + pngMetaData.TransparentGray8.GetValueOrDefault()); break; @@ -702,19 +681,21 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Rgb: PngScanlineProcessor.ProcessRgbScanline( + this.configuration, this.header, scanlineSpan, rowSpan, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.TransparentRgb48.GetValueOrDefault(), + pngMetaData.TransparentRgb24.GetValueOrDefault()); break; case PngColorType.RgbWithAlpha: PngScanlineProcessor.ProcessRgbaScanline( + this.configuration, this.header, scanlineSpan, rowSpan, @@ -733,9 +714,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The current image row. + /// The png meta data /// The column start index. Always 0 for none interlaced images. /// The column increment. Always 1 for none interlaced images. - private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1) + private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, PngMetaData pngMetaData, int pixelOffset = 0, int increment = 1) where TPixel : struct, IPixel { // Trim the first marker byte from the buffer @@ -755,9 +737,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, pixelOffset, increment, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.TransparentGray16.GetValueOrDefault(), + pngMetaData.TransparentGray8.GetValueOrDefault()); break; @@ -794,9 +776,9 @@ namespace SixLabors.ImageSharp.Formats.Png increment, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.TransparentRgb48.GetValueOrDefault(), + pngMetaData.TransparentRgb24.GetValueOrDefault()); break; @@ -820,7 +802,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// Decodes and assigns marker colors that identify transparent pixels in non indexed images /// /// The alpha tRNS array - private void AssignTransparentMarkers(ReadOnlySpan alpha) + /// The png meta data + private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetaData pngMetaData) { if (this.pngColorType == PngColorType.Rgb) { @@ -832,16 +815,16 @@ namespace SixLabors.ImageSharp.Formats.Png ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - this.rgb48Trans = new Rgb48(rc, gc, bc); - this.hasTrans = true; + pngMetaData.TransparentRgb48 = new Rgb48(rc, gc, bc); + pngMetaData.HasTrans = true; return; } byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - this.rgb24Trans = new Rgb24(r, g, b); - this.hasTrans = true; + pngMetaData.TransparentRgb24 = new Rgb24(r, g, b); + pngMetaData.HasTrans = true; } } else if (this.pngColorType == PngColorType.Grayscale) @@ -850,14 +833,14 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - this.luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + pngMetaData.TransparentGray16 = new Gray16(BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2))); } else { - this.luminanceTrans = ReadByteLittleEndian(alpha, 0); + pngMetaData.TransparentGray8 = new Gray8(ReadByteLittleEndian(alpha, 0)); } - this.hasTrans = true; + pngMetaData.HasTrans = true; } } } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a46d83707e..292de007ca 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Buffers.Binary; using System.Collections.Generic; using System.IO; @@ -42,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly MemoryAllocator memoryAllocator; + /// + /// The configuration instance for the decoding operation + /// + private Configuration configuration; + /// /// The maximum block size, defaults at 64k for uncompressed blocks. /// @@ -200,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Png Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.configuration = image.GetConfiguration(); this.width = image.Width; this.height = image.Height; @@ -236,7 +243,8 @@ namespace SixLabors.ImageSharp.Formats.Png } // Create quantized frame returning the palette and set the bit depth. - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); + quantized = this.quantizer.CreateFrameQuantizer(image.GetConfiguration()) + .QuantizeFrame(image.Frames.RootFrame); byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); bits = Math.Max(bits, quantizedBits); @@ -282,6 +290,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePaletteChunk(stream, quantized); } + if (pngMetaData.HasTrans) + { + this.WriteTransparencyChunk(stream, pngMetaData); + } + this.WritePhysicalChunk(stream, metaData); this.WriteGammaChunk(stream); this.WriteExifChunk(stream, metaData); @@ -312,27 +325,27 @@ namespace SixLabors.ImageSharp.Formats.Png private void CollectGrayscaleBytes(ReadOnlySpan rowSpan) where TPixel : struct, IPixel { - // Use ITU-R recommendation 709 to match libpng. - const float RX = .2126F; - const float GX = .7152F; - const float BX = .0722F; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); Span rawScanlineSpan = this.rawScanline.GetSpan(); ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan); if (this.pngColorType.Equals(PngColorType.Grayscale)) { - // TODO: Research and add support for grayscale plus tRNS if (this.use16Bit) { // 16 bit grayscale - Rgb48 rgb = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) + using (IMemoryOwner luminanceBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); - ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + Span luminanceSpan = luminanceBuffer.GetSpan(); + ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan); + PixelOperations.Instance.ToGray16(this.configuration, rowSpan, luminanceSpan); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) + { + Gray16 luminance = Unsafe.Add(ref luminanceRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue); + } } } else @@ -340,30 +353,29 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.bitDepth == 8) { // 8 bit grayscale - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); - } + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + rowSpan.Length); } else { // 1, 2, and 4 bit grayscale - using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean)) + using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer( + rowSpan.Length, + AllocationOptions.Clean)) { int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1); Span tempSpan = temp.GetSpan(); - ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) - { - Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); - float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor; - Unsafe.Add(ref tempSpanRef, x) = (byte)luminance; - this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth); - } + // We need to first create an array of luminance bytes then scale them down to the correct bit depth. + PixelOperations.Instance.ToGray8Bytes( + this.configuration, + rowSpan, + tempSpan, + rowSpan.Length); + this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor); } } } @@ -373,23 +385,33 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.use16Bit) { // 16 bit grayscale + alpha - Rgba64 rgba = default; - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) + // TODO: Should we consider in the future a GrayAlpha32 type. + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); - ushort luminance = (ushort)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + ushort luminance = ImageMaths.Get16BitBT709Luminance(rgba.R, rgba.G, rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); + } } } else { // 8 bit grayscale + alpha + // TODO: Should we consider in the future a GrayAlpha16 type. Rgba32 rgba = default; for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); - Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); + Unsafe.Add(ref rawScanlineSpanRef, o) = + ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } @@ -411,29 +433,43 @@ namespace SixLabors.ImageSharp.Formats.Png case 4: { // 8 bit Rgba - PixelOperations.Instance.ToRgba32Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } case 3: { // 8 bit Rgb - PixelOperations.Instance.ToRgb24Bytes(rowSpan, rawScanlineSpan, this.width); + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + rowSpan, + rawScanlineSpan, + this.width); break; } case 8: { // 16 bit Rgba - Rgba64 rgba = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + using (IMemoryOwner rgbaBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + Span rgbaSpan = rgbaBuffer.GetSpan(); + ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan); + PixelOperations.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) + { + Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); + } } break; @@ -442,14 +478,20 @@ namespace SixLabors.ImageSharp.Formats.Png default: { // 16 bit Rgb - Rgb48 rgb = default; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + using (IMemoryOwner rgbBuffer = this.memoryAllocator.Allocate(rowSpan.Length)) { - Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); - BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + Span rgbSpan = rgbBuffer.GetSpan(); + ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan); + PixelOperations.Instance.ToRgb48(this.configuration, rowSpan, rgbSpan); + + // Can't map directly to byte array as it's big endian. + for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) + { + Rgb48 rgb = Unsafe.Add(ref rgbRef, x); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); + BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); + } } break; @@ -624,7 +666,6 @@ namespace SixLabors.ImageSharp.Formats.Png TPixel[] palette = quantized.Palette; int paletteLength = Math.Min(palette.Length, 256); int colorTableLength = paletteLength * 3; - Rgba32 rgba = default; bool anyAlpha = false; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) @@ -634,6 +675,8 @@ namespace SixLabors.ImageSharp.Formats.Png ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); Span quantizedSpan = quantized.GetPixelSpan(); + Rgba32 rgba = default; + for (int i = 0; i < paletteLength; i++) { if (quantizedSpan.IndexOf((byte)i) > -1) @@ -662,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Write the transparency data if (anyAlpha) { - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength); + this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength); } } } @@ -710,6 +753,51 @@ namespace SixLabors.ImageSharp.Formats.Png } } + /// + /// Writes the transparency chunk to the stream + /// + /// The containing image data. + /// The image meta data. + private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData) + { + Span alpha = this.chunkDataBuffer.AsSpan(); + if (pngMetaData.ColorType.Equals(PngColorType.Rgb)) + { + if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit) + { + Rgb48 rgb = pngMetaData.TransparentRgb48.Value; + BinaryPrimitives.WriteUInt16LittleEndian(alpha, rgb.R); + BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); + BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); + + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); + } + else if (pngMetaData.TransparentRgb24.HasValue) + { + alpha.Clear(); + Rgb24 rgb = pngMetaData.TransparentRgb24.Value; + alpha[1] = rgb.R; + alpha[3] = rgb.G; + alpha[5] = rgb.B; + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); + } + } + else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) + { + if (pngMetaData.TransparentGray16.HasValue && this.use16Bit) + { + BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); + } + else if (pngMetaData.TransparentGray8.HasValue) + { + alpha.Clear(); + alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue; + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); + } + } + } + /// /// Writes the pixel information to the stream. /// @@ -851,20 +939,21 @@ namespace SixLabors.ImageSharp.Formats.Png /// The source span in 8 bits. /// The resultant span in . /// The bit depth. - private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits) + /// The scaling factor. + private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits, float scale = 1) { ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte resultRef = ref MemoryMarshal.GetReference(result); - byte mask = (byte)(0xFF >> (8 - bits)); - byte shift0 = (byte)(8 - bits); int shift = 8 - bits; + byte mask = (byte)(0xFF >> shift); + byte shift0 = (byte)shift; int v = 0; int resultOffset = 0; for (int i = 0; i < source.Length; i++) { - int value = Unsafe.Add(ref sourceRef, i) & mask; + int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask; v |= value << shift; if (shift == 0) @@ -907,4 +996,4 @@ namespace SixLabors.ImageSharp.Formats.Png return scanlineLength / mod; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 9c76765146..d5ab3d2554 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp.Formats.Png { /// @@ -24,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.BitDepth = other.BitDepth; this.ColorType = other.ColorType; this.Gamma = other.Gamma; + this.HasTrans = other.HasTrans; + this.TransparentGray8 = other.TransparentGray8; + this.TransparentGray16 = other.TransparentGray16; + this.TransparentRgb24 = other.TransparentRgb24; + this.TransparentRgb48 = other.TransparentRgb48; } /// @@ -42,6 +49,31 @@ namespace SixLabors.ImageSharp.Formats.Png /// public float Gamma { get; set; } + /// + /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent + /// + public Rgb24? TransparentRgb24 { get; set; } + + /// + /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent + /// + public Rgb48? TransparentRgb48 { get; set; } + + /// + /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent + /// + public Gray8? TransparentGray8 { get; set; } + + /// + /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent + /// + public Gray16? TransparentGray16 { get; set; } + + /// + /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded + /// + public bool HasTrans { get; set; } + /// public IDeepCloneable DeepClone() => new PngMetaData(this); } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 6c81ba76c2..4242b2d554 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png { /// /// Provides methods to allow the decoding of raw scanlines to image rows of different pixel formats. + /// TODO: We should make this a stateful class or struct to reduce the number of arguments on methods (most are invariant). /// internal static class PngScanlineProcessor { @@ -19,8 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan scanlineSpan, Span rowSpan, bool hasTrans, - ushort luminance16Trans, - byte luminanceTrans) + Gray16 luminance16Trans, + Gray8 luminanceTrans) where TPixel : struct, IPixel { TPixel pixel = default; @@ -32,30 +33,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (header.BitDepth == 16) { - Rgb48 rgb48 = default; for (int x = 0, o = 0; x < header.Width; x++, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); + pixel.FromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < header.Width; x++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); + pixel.FromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -72,14 +62,15 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.R = luminance; rgba64.G = luminance; rgba64.B = luminance; - rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { + byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); Rgba32 rgba32 = default; for (int x = 0; x < header.Width; x++) { @@ -87,9 +78,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -102,8 +93,8 @@ namespace SixLabors.ImageSharp.Formats.Png int pixelOffset, int increment, bool hasTrans, - ushort luminance16Trans, - byte luminanceTrans) + Gray16 luminance16Trans, + Gray8 luminanceTrans) where TPixel : struct, IPixel { TPixel pixel = default; @@ -115,30 +106,19 @@ namespace SixLabors.ImageSharp.Formats.Png { if (header.BitDepth == 16) { - Rgb48 rgb48 = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); + pixel.FromGray16(new Gray16(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); + pixel.FromGray8(new Gray8(luminance)); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -155,14 +135,15 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.R = luminance; rgba64.G = luminance; rgba64.B = luminance; - rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { + byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); Rgba32 rgba32 = default; for (int x = pixelOffset; x < header.Width; x += increment) { @@ -170,9 +151,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; - rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -202,26 +183,25 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = alpha; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { Rgba32 rgba32 = default; - int bps = bytesPerSample; for (int x = 0; x < header.Width; x++) { int offset = x * bytesPerPixel; byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); - byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bps); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = alpha; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -253,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = luminance; rgba64.A = alpha; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -270,7 +250,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.B = luminance; rgba32.A = alpha; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -303,20 +283,18 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - // TODO: We should have PackFromRgb24. - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < header.Width; x++) { int index = Unsafe.Add(ref scanlineSpanRef, x); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -350,25 +328,25 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) { int index = Unsafe.Add(ref scanlineSpanRef, o); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); - pixel.PackFromRgba32(rgba); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } } public static void ProcessRgbScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -380,7 +358,6 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { TPixel pixel = default; - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (!hasTrans) @@ -394,13 +371,13 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgb48(rgb48); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgb24Bytes(configuration, scanlineSpan, rowSpan, header.Width); } return; @@ -419,7 +396,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.Rgb = rgb48; rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -434,7 +411,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.Rgb = rgb24; rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba32); + pixel.FromRgba32(rgba32); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -472,7 +449,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.Rgb = rgb48; rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -485,7 +462,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgb48(rgb48); + pixel.FromRgb48(rgb48); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -503,26 +480,27 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + Rgb24 rgb = default; for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + rgb.R = Unsafe.Add(ref scanlineSpanRef, o); + rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.FromRgb24(rgb); Unsafe.Add(ref rowSpanRef, x) = pixel; } } } public static void ProcessRgbaScanline( + Configuration configuration, in PngHeader header, ReadOnlySpan scanlineSpan, Span rowSpan, @@ -543,13 +521,13 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { - PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + PixelOperations.Instance.FromRgba32Bytes(configuration, scanlineSpan, rowSpan, header.Width); } } @@ -577,7 +555,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - pixel.PackFromRgba64(rgba64); + pixel.FromRgba64(rgba64); Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -591,7 +569,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * bytesPerSample)); - pixel.PackFromRgba32(rgba); + pixel.FromRgba32(rgba); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/src/ImageSharp/IImageInfo.cs b/src/ImageSharp/IImageInfo.cs index 25d5ec7cab..6e64aa679a 100644 --- a/src/ImageSharp/IImageInfo.cs +++ b/src/ImageSharp/IImageInfo.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.MetaData; namespace SixLabors.ImageSharp { /// - /// Encapsulates properties that descibe basic image information including dimensions, pixel type information + /// Encapsulates properties that describe basic image information including dimensions, pixel type information /// and additional metadata /// public interface IImageInfo diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 8b9f3fdb5b..ffdab25e24 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -15,6 +16,29 @@ namespace SixLabors.ImageSharp /// public static partial class Image { + /// + /// Creates an instance backed by an uninitialized memory buffer. + /// This is an optimized creation method intended to be used by decoders. + /// The image might be filled with memory garbage. + /// + /// The pixel type + /// The + /// The width of the image + /// The height of the image + /// The + /// The result + internal static Image CreateUninitialized( + Configuration configuration, + int width, + int height, + ImageMetaData metadata) + where TPixel : struct, IPixel + { + Buffer2D uninitializedMemoryBuffer = + configuration.MemoryAllocator.Allocate2D(width, height); + return new Image(configuration, uninitializedMemoryBuffer.MemorySource, width, height, metadata); + } + /// /// By reading the header on the provided stream this calculates the images format. /// diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 07adc03ff6..34927e6e2b 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -198,18 +198,17 @@ namespace SixLabors.ImageSharp return null; } - IImageFormat format = default; foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) { IImageFormat f = detector.DetectFormat(data); if (f != null) { - format = f; + return f; } } - return format; + return default; } /// diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs index e8d9ab7547..c2935bed93 100644 --- a/src/ImageSharp/Image.WrapMemory.cs +++ b/src/ImageSharp/Image.WrapMemory.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp public static partial class Image { /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// /// The pixel type @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. /// The memory is being observed, the caller remains responsible for managing it's lifecycle. /// @@ -79,15 +79,15 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type /// The - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// The @@ -105,15 +105,15 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type /// The - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// An instance @@ -128,14 +128,14 @@ namespace SixLabors.ImageSharp } /// - /// Wraps an existing contigous memory area of 'width'x'height' pixels, + /// Wraps an existing contiguous memory area of 'width' x 'height' pixels, /// allowing to view/manipulate it as an ImageSharp instance. - /// The ownership of the is being transfered to the new instance, + /// The ownership of the is being transferred to the new instance, /// meaning that the caller is not allowed to dispose . /// It will be disposed together with the result image. /// /// The pixel type - /// The that is being transfered to the image + /// The that is being transferred to the image /// The width of the memory image /// The height of the memory image /// An instance diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index e579bec1a6..cbf93275c8 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp if (format is null) { var sb = new StringBuilder(); - sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); + sb.AppendLine($"Can't find a format that is associated with the file extension '{ext}'. Registered formats with there extensions include:"); foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) { sb.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp if (encoder is null) { var sb = new StringBuilder(); - sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); + sb.AppendLine($"Can't find encoder for file extension '{ext}' using image format '{format.Name}'. Registered encoders include:"); foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders) { sb.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index be1792ced1..f69ae37574 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; -using System.Numerics; using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -23,7 +21,6 @@ namespace SixLabors.ImageSharp public sealed class ImageFrame : IPixelSource, IDisposable where TPixel : struct, IPixel { - private readonly Configuration configuration; private bool isDisposed; /// @@ -86,7 +83,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(width, height); this.MetaData = metaData ?? new ImageFrameMetaData(); @@ -120,7 +117,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(metaData, nameof(metaData)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = new Buffer2D(memorySource, width, height); this.MetaData = metaData; @@ -136,7 +133,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); - this.configuration = configuration; + this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); @@ -148,6 +145,11 @@ namespace SixLabors.ImageSharp /// public MemoryAllocator MemoryAllocator { get; } + /// + /// Gets the instance associated with this . + /// + internal Configuration Configuration { get; } + /// /// Gets the image pixels. Not private as Buffer2D requires an array in its constructor. /// @@ -250,13 +252,13 @@ namespace SixLabors.ImageSharp } /// - public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>({this.Width}x{this.Height})"; /// /// Clones the current instance. /// /// The - internal ImageFrame Clone() => this.Clone(this.configuration); + internal ImageFrame Clone() => this.Clone(this.Configuration); /// /// Clones the current instance. @@ -271,7 +273,7 @@ namespace SixLabors.ImageSharp /// The pixel format. /// The internal ImageFrame CloneAs() - where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); + where TPixel2 : struct, IPixel => this.CloneAs(this.Configuration); /// /// Returns a copy of the image frame in the given pixel format. @@ -289,22 +291,16 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.DeepClone()); - ParallelHelper.IterateRowsWithTempBuffer( + ParallelHelper.IterateRows( this.Bounds(), configuration, - (rows, tempRowBuffer) => + (rows) => { for (int y = rows.Min; y < rows.Max; y++) { Span sourceRow = this.GetPixelRowSpan(y); Span targetRow = target.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.Span; - - PixelOperations.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length); - PixelOperations.Instance.PackFromScaledVector4( - tempRowSpan, - targetRow, - targetRow.Length); + PixelOperations.Instance.To(configuration, sourceRow, targetRow); } }); diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 83b2b12604..c19c92426f 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.3;netstandard2.0;netcoreapp2.1 + netstandard1.3;netstandard2.0;netcoreapp2.1;net472 true true SixLabors.ImageSharp @@ -31,27 +31,32 @@ IOperation Latest + + + $(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS + + + - + All - - - + + ..\..\ImageSharp.ruleset SixLabors.ImageSharp @@ -72,14 +77,46 @@ TextTemplatingFileGenerator Block8x8F.Generated.cs - + TextTemplatingFileGenerator PixelOperations{TPixel}.Generated.cs - + + TextTemplatingFileGenerator + Argb32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgr24.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Bgra32.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray8.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Gray16.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgb24.PixelOperations.Generated.cs + + TextTemplatingFileGenerator Rgba32.PixelOperations.Generated.cs + + TextTemplatingFileGenerator + Rgb48.PixelOperations.Generated.cs + + + TextTemplatingFileGenerator + Rgba64.PixelOperations.Generated.cs + PorterDuffFunctions.Generated.cs TextTemplatingFileGenerator @@ -105,16 +142,56 @@ True Block8x8F.Generated.tt - + True True PixelOperations{TPixel}.Generated.tt - + + True + True + Argb32.PixelOperations.Generated.tt + + + True + True + Bgr24.PixelOperations.Generated.tt + + + True + True + Bgra32.PixelOperations.Generated.tt + + + True + True + Gray8.PixelOperations.Generated.tt + + + True + True + Gray16.PixelOperations.Generated.tt + + + True + True + Rgb24.PixelOperations.Generated.tt + + True True Rgba32.PixelOperations.Generated.tt + + True + True + Rgb48.PixelOperations.Generated.tt + + + True + True + Rgba64.PixelOperations.Generated.tt + True True diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings index 8b2e1bcf07..a7337240a5 100644 --- a/src/ImageSharp/ImageSharp.csproj.DotSettings +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -1,3 +1,10 @@  True - True \ No newline at end of file + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 9d4c1ef0b3..178194b21e 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp public Image Clone() => this.Clone(this.configuration); /// - /// Clones the current image with the given configueation. + /// Clones the current image with the given configuration. /// /// The configuration providing initialization code which allows extending the library. /// Returns a new with all the same pixel data as the original. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index b48b146f11..37ceaf10f6 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { this.Parts = ExifParts.All; this.data = data; - this.InvalidTags = new List(); + this.InvalidTags = Array.Empty(); } /// @@ -63,7 +63,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - this.InvalidTags = new List(other.InvalidTags); + + this.InvalidTags = other.InvalidTags.Count > 0 + ? new List(other.InvalidTags) + : (IReadOnlyList)Array.Empty(); + if (other.values != null) { this.values = new List(other.Values.Count); @@ -289,7 +293,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - this.InvalidTags = new List(reader.InvalidTags); + this.InvalidTags = reader.InvalidTags.Count > 0 + ? new List(reader.InvalidTags) + : (IReadOnlyList)Array.Empty(); + this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 5f95499088..100649c0fd 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Primitives; @@ -19,7 +18,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// internal sealed class ExifReader { - private readonly List invalidTags = new List(); + private List invalidTags; private readonly byte[] exifData; private int position; private Endianness endianness = Endianness.BigEndian; @@ -38,7 +37,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the invalid tags. /// - public IReadOnlyList InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags => this.invalidTags ?? (IReadOnlyList)Array.Empty(); /// /// Gets the thumbnail length in the byte stream @@ -125,7 +124,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0]; - private unsafe string ConvertToString(ReadOnlySpan buffer) + private string ConvertToString(ReadOnlySpan buffer) { int nullCharIndex = buffer.IndexOf((byte)0); @@ -338,7 +337,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif // Ensure that the new index does not overrun the data if (newIndex > int.MaxValue) { - this.invalidTags.Add(tag); + this.AddInvalidTag(tag); exifValue = default; @@ -349,7 +348,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (this.RemainingLength < size) { - this.invalidTags.Add(tag); + this.AddInvalidTag(tag); + this.position = oldIndex; exifValue = default; @@ -372,13 +372,23 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return true; } + private void AddInvalidTag(ExifTag tag) + { + if (this.invalidTags == null) + { + this.invalidTags = new List(); + } + + this.invalidTags.Add(tag); + } + + [MethodImpl(InliningOptions.ShortMethod)] private TEnum ToEnum(int value, TEnum defaultValue) where TEnum : struct { - var enumValue = (TEnum)(object)value; - if (Enum.GetValues(typeof(TEnum)).Cast().Any(v => v.Equals(enumValue))) + if (EnumHelper.IsDefined(value)) { - return enumValue; + return Unsafe.As(ref value); } return defaultValue; @@ -547,5 +557,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif ? BinaryPrimitives.ReadInt16BigEndian(buffer) : BinaryPrimitives.ReadInt16LittleEndian(buffer); } + + private class EnumHelper + where TEnum : struct + { + private static readonly int[] Values = Enum.GetValues(typeof(TEnum)).Cast() + .Select(e => Convert.ToInt32(e)).OrderBy(e => e).ToArray(); + + [MethodImpl(InliningOptions.ShortMethod)] + public static bool IsDefined(int value) + { + return Array.BinarySearch(Values, value) >= 0; + } + } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs index ade373341e..9079526d5a 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs @@ -17,8 +17,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Which parts will be written. /// - private ExifParts allowedParts; - private IList values; + private readonly ExifParts allowedParts; + private readonly IList values; private List dataOffsets; private readonly List ifdIndexes; private readonly List exifIndexes; diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs index ee91ad7a18..b27083dc49 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs @@ -41,10 +41,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc public IccResponseCurve ReadResponseCurve(int channelCount) { var type = (IccCurveMeasurementEncodings)this.ReadUInt32(); - uint[] measurment = new uint[channelCount]; + uint[] measurement = new uint[channelCount]; for (int i = 0; i < channelCount; i++) { - measurment[i] = this.ReadUInt32(); + measurement[i] = this.ReadUInt32(); } Vector3[] xyzValues = new Vector3[channelCount]; @@ -56,8 +56,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc IccResponseNumber[][] response = new IccResponseNumber[channelCount][]; for (int i = 0; i < channelCount; i++) { - response[i] = new IccResponseNumber[measurment[i]]; - for (uint j = 0; j < measurment[i]; j++) + response[i] = new IccResponseNumber[measurement[i]]; + for (uint j = 0; j < measurement[i]; j++) { response[i][j] = this.ReadResponseNumber(); } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs index e41d9b3b8c..c572b7f210 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs @@ -628,16 +628,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { int start = this.currentIndex - 8; // 8 is the tag header size ushort channelCount = this.ReadUInt16(); - ushort measurmentCount = this.ReadUInt16(); + ushort measurementCount = this.ReadUInt16(); - uint[] offset = new uint[measurmentCount]; - for (int i = 0; i < measurmentCount; i++) + uint[] offset = new uint[measurementCount]; + for (int i = 0; i < measurementCount; i++) { offset[i] = this.ReadUInt32(); } - var curves = new IccResponseCurve[measurmentCount]; - for (int i = 0; i < measurmentCount; i++) + var curves = new IccResponseCurve[measurementCount]; + for (int i = 0; i < measurementCount; i++) { this.currentIndex = (int)(start + offset[i]); curves[i] = this.ReadResponseCurve(channelCount); diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs index 71c27ca611..8f0427db27 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs @@ -39,15 +39,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// This profile provides the relevant information to perform a transformation - /// between colour encodings and the PCS. This type of profile is based on - /// modelling rather than device measurement or characterization data. + /// between color encodings and the PCS. This type of profile is based on + /// modeling rather than device measurement or characterization data. /// ColorSpace profiles may be embedded in images. /// ColorSpace = 0x73706163, // spac /// /// This profile represents abstract transforms and does not represent any - /// device model. Colour transformations using Abstract profiles are performed + /// device model. Color transformations using Abstract profiles are performed /// from PCS to PCS. Abstract profiles cannot be embedded in images. /// Abstract = 0x61627374, // abst @@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// NamedColor profiles can be thought of as sibling profiles to device profiles. /// For a given device there would be one or more device profiles to handle - /// process colour conversions and one or more named colour profiles to handle - /// named colours. + /// process color conversions and one or more named color profiles to handle + /// named colors. /// NamedColor = 0x6E6D636C, // nmcl } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs index 3758be34b7..1e9ec18e89 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs @@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc NotEmbedded = 0, /// - /// Profile cannot be used independently of the embedded colour data + /// Profile cannot be used independently of the embedded color data /// NotIndependent = 1 << 1, /// - /// Profile can be used independently of the embedded colour data + /// Profile can be used independently of the embedded color data /// Independent = 0, } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs index 82b2969003..61d34dca10 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs @@ -19,18 +19,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc Unknown, /// - /// A2B0 - This tag defines a colour transform from Device, Colour Encoding or PCS, to PCS, or a colour transform + /// A2B0 - This tag defines a color transform from Device, Color Encoding or PCS, to PCS, or a color transform /// from Device 1 to Device 2, using lookup table tag element structures /// AToB0 = 0x41324230, /// - /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures + /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures /// AToB1 = 0x41324231, /// - /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures + /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures /// AToB2 = 0x41324232, @@ -46,40 +46,40 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc BlueTrc = 0x62545243, /// - /// B2A0 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures + /// B2A0 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures /// BToA0 = 0x42324130, /// - /// B2A1 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures. + /// B2A1 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures. /// BToA1 = 0x42324131, /// - /// B2A2 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures. + /// B2A2 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures. /// BToA2 = 0x42324132, /// - /// B2D0 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D0 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA0 tag. /// BToD0 = 0x42324430, /// - /// B2D1 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D1 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA1 tag. /// BToD1 = 0x42324431, /// - /// B2D2 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D2 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA2 tag. /// BToD2 = 0x42324432, /// - /// B2D3 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and + /// B2D3 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and /// provides a means to override the BToA1 tag. /// BToD3 = 0x42324433, @@ -97,8 +97,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc CharTarget = 0x74617267, /// - /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ colour, measured using the actual illumination - /// conditions and relative to the actual adopted white, to an nCIEXYZ colour relative to the PCS adopted white + /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ color, measured using the actual illumination + /// conditions and relative to the actual adopted white, to an nCIEXYZ color relative to the PCS adopted white /// ChromaticAdaptation = 0x63686164, @@ -166,33 +166,33 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc DeviceSettings = 0x64657673, /// - /// D2B0 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B0 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB0 tag /// DToB0 = 0x44324230, /// - /// D2B1 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B1 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB1 = 0x44324230, /// - /// D2B2 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B2 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB2 = 0x44324230, /// - /// D2B3 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded + /// D2B3 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded /// input range, output range and transform, and provides a means to override the AToB1 tag /// DToB3 = 0x44324230, /// /// gamt - This tag provides a table in which PCS values are the input and a single - /// output value for each input value is the output. If the output value is 0, the PCS colour is in-gamut. - /// If the output is non-zero, the PCS colour is out-of-gamut + /// output value for each input value is the output. If the output value is 0, the PCS color is in-gamut. + /// If the output is non-zero, the PCS color is out-of-gamut /// Gamut = 0x67616D74, @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc GreenTrc = 0x67545243, /// - /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel. + /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square meter as described by the Y channel. /// Luminance = 0x6C756d69, @@ -240,8 +240,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc NamedColor = 0x6E636f6C, /// - /// ncl2 - This tag contains the named colour information providing a PCS and optional device representation - /// for a list of named colours. + /// ncl2 - This tag contains the named color information providing a PCS and optional device representation + /// for a list of named colors. /// NamedColor2 = 0x6E636C32, diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs index e0504b24cb..7cb9c00f39 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs @@ -10,11 +10,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { /// /// In perceptual transforms the PCS values represent hypothetical - /// measurements of a colour reproduction on the reference reflective + /// measurements of a color reproduction on the reference reflective /// medium. By extension, for the perceptual intent, the PCS represents /// the appearance of that reproduction as viewed in the reference viewing /// environment by a human observer adapted to that environment. The exact - /// colour rendering of the perceptual intent is vendor specific. + /// color rendering of the perceptual intent is vendor specific. /// Perceptual = 0, @@ -27,15 +27,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MediaRelativeColorimetric = 1, /// - /// The exact colour rendering of the saturation intent is vendor + /// The exact color rendering of the saturation intent is vendor /// specific and involves compromises such as trading off - /// preservation of hue in order to preserve the vividness of pure colours. + /// preservation of hue in order to preserve the vividness of pure colors. /// Saturation = 2, /// /// Transformations for this intent shall leave the chromatically - /// adapted nCIEXYZ tristimulus values of the in-gamut colours unchanged. + /// adapted nCIEXYZ tristimulus values of the in-gamut colors unchanged. /// AbsoluteColorimetric = 3, } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs index 1493ecc6bb..ad0db4df93 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// This is an optional tag which specifies the laydown order in which colorants /// will be printed on an n-colorant device. The laydown order may be the same /// as the channel generation order listed in the colorantTableTag or the channel - /// order of a colour encoding type such as CMYK, in which case this tag is not + /// order of a color encoding type such as CMYK, in which case this tag is not /// needed. When this is not the case (for example, ink-towers sometimes use /// the order KCMY), this tag may be used to specify the laydown order of the /// colorants @@ -59,25 +59,25 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc DateTime = 0x6474696D, /// - /// This structure represents a colour transform using tables with 16-bit + /// This structure represents a color transform using tables with 16-bit /// precision. This type contains four processing elements: a 3 × 3 matrix - /// (which shall be the identity matrix unless the input colour space is + /// (which shall be the identity matrix unless the input color space is /// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional /// lookup table, and a set of one-dimensional output tables /// Lut16 = 0x6D667432, /// - /// This structure represents a colour transform using tables of 8-bit + /// This structure represents a color transform using tables of 8-bit /// precision. This type contains four processing elements: a 3 × 3 matrix - /// (which shall be the identity matrix unless the input colour space is + /// (which shall be the identity matrix unless the input color space is /// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional /// lookup table, and a set of one-dimensional output tables. /// Lut8 = 0x6D667431, /// - /// This structure represents a colour transform. The type contains up + /// This structure represents a color transform. The type contains up /// to five processing elements which are stored in the AToBTag tag /// in the following order: a set of one-dimensional curves, a 3 × 3 /// matrix with offset terms, a set of one-dimensional curves, a @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc LutAToB = 0x6D414220, /// - /// This structure represents a colour transform. The type contains + /// This structure represents a color transform. The type contains /// up to five processing elements which are stored in the BToATag /// in the following order: a set of one-dimensional curves, a 3 × 3 /// matrix with offset terms, a set of one-dimensional curves, a @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MultiLocalizedUnicode = 0x6D6C7563, /// - /// This structure represents a colour transform, containing a sequence + /// This structure represents a color transform, containing a sequence /// of processing elements. The processing elements contained in the /// structure are defined in the structure itself, allowing for a flexible /// structure. Currently supported processing elements are: a set of one @@ -123,15 +123,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc MultiProcessElements = 0x6D706574, /// - /// This type is a count value and array of structures that provide colour - /// coordinates for colour names. For each named colour, a PCS and optional - /// device representation of the colour are given. Both representations are + /// This type is a count value and array of structures that provide color + /// coordinates for color names. For each named color, a PCS and optional + /// device representation of the color are given. Both representations are /// 16-bit values and PCS values shall be relative colorimetric. The device - /// representation corresponds to the header’s "data colour space" field. + /// representation corresponds to the header’s "data color space" field. /// This representation should be consistent with the "number of device /// coordinates" field in the namedColor2Type. If this field is 0, device /// coordinates are not provided. The PCS representation corresponds to the - /// header's PCS field. The PCS representation is always provided. Colour + /// header's PCS field. The PCS representation is always provided. Color /// names are fixed-length, 32-byte fields including null termination. In /// order to maintain maximum portability, it is strongly recommended that /// special characters of the 7-bit ASCII set not be used. @@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// so that corrections can be made for variation in the device without /// having to produce a new profile. The mechanism can be used by applications /// to allow users with relatively inexpensive and readily available - /// instrumentation to apply corrections to individual output colour + /// instrumentation to apply corrections to individual output color /// channels in order to achieve consistent results. /// ResponseCurveSet16 = 0x72637332, diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 72665bc69c..5d75a6df9d 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; using System.Security.Cryptography; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -20,7 +19,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// The backing file for the property /// - private List entries; + private IccTagDataEntry[] entries; /// /// ICC profile header @@ -46,13 +45,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// The profile header /// The actual profile data - internal IccProfile(IccProfileHeader header, IEnumerable entries) + internal IccProfile(IccProfileHeader header, IccTagDataEntry[] entries) { - Guard.NotNull(header, nameof(header)); - Guard.NotNull(entries, nameof(entries)); - - this.header = header; - this.entries = new List(entries); + this.header = header ?? throw new ArgumentNullException(nameof(header)); + this.entries = entries ?? throw new ArgumentNullException(nameof(entries)); } /// @@ -85,7 +81,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Gets the actual profile data /// - public List Entries + public IccTagDataEntry[] Entries { get { @@ -212,12 +208,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc if (this.data is null) { - this.entries = new List(); + this.entries = Array.Empty(); return; } var reader = new IccReader(); - this.entries = new List(reader.ReadTagData(this.data)); + this.entries = reader.ReadTagData(this.data); } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs index da47b565e3..9f9d373ae1 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccReader.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc @@ -126,7 +127,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc // A normal profile usually has 5-15 entries if (tagCount > 100) { - return new IccTagTableEntry[0]; + return Array.Empty(); } var table = new List((int)tagCount); diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs index b476e31955..91a3bba549 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs @@ -68,12 +68,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } } - private IccTagTableEntry[] WriteTagData(IccDataWriter writer, List entries) + private IccTagTableEntry[] WriteTagData(IccDataWriter writer, IccTagDataEntry[] entries) { IEnumerable> grouped = entries.GroupBy(t => t); // (Header size) + (entry count) + (nr of entries) * (size of table entry) - writer.SetIndex(128 + 4 + (entries.Count * 12)); + writer.SetIndex(128 + 4 + (entries.Length * 12)); var table = new List(); foreach (IGrouping group in grouped) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs index 38a2f4522c..77a913b14e 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// Initializes a new instance of the class. /// public IccCurveTagDataEntry() - : this(new float[0], IccProfileTag.Unknown) + : this(Array.Empty(), IccProfileTag.Unknown) { } @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Tag Signature public IccCurveTagDataEntry(IccProfileTag tagSignature) - : this(new float[0], tagSignature) + : this(Array.Empty(), tagSignature) { } @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc public IccCurveTagDataEntry(float[] curveData, IccProfileTag tagSignature) : base(IccTypeSignature.Curve, tagSignature) { - this.CurveData = curveData ?? new float[0]; + this.CurveData = curveData ?? Array.Empty(); } /// diff --git a/src/ImageSharp/PixelFormats/Alpha8.cs b/src/ImageSharp/PixelFormats/Alpha8.cs deleted file mode 100644 index a8d97d31a2..0000000000 --- a/src/ImageSharp/PixelFormats/Alpha8.cs +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing a single 8 bit normalized W values. - /// - /// Ranges from [0, 0, 0, 0] to [0, 0, 0, 1] in vector form. - /// - /// - public struct Alpha8 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// The alpha component - public Alpha8(float alpha) - { - this.PackedValue = Pack(alpha); - } - - /// - public byte PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Alpha8 left, Alpha8 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Alpha8 left, Alpha8 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(0, 0, 0, this.PackedValue / 255F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackedValue = source.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = default(Rgb24); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest = default(Bgr24); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - dest.A = this.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) - { - dest.R = 0; - dest.G = 0; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - /// Compares an object with the packed vector. - /// - /// The object to compare. - /// True if the object is equal to the packed vector. - public override bool Equals(object obj) - { - return obj is Alpha8 other && this.Equals(other); - } - - /// - /// Compares another Alpha8 packed vector with the packed vector. - /// - /// The Alpha8 packed vector to compare. - /// True if the packed vectors are equal. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Alpha8 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. - public override string ToString() - { - return (this.PackedValue / 255F).ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs a into a byte. - /// - /// The float containing the value to pack. - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte Pack(float alpha) - { - return (byte)Math.Round(alpha.Clamp(0, 1) * 255F); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs deleted file mode 100644 index 1f401f1a13..0000000000 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255. - /// The color components are stored in blue, green, red order (least significant to most significant byte). - /// - /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. - /// - /// - [StructLayout(LayoutKind.Explicit)] - public struct Bgr24 : IPixel - { - /// - /// The blue component. - /// - [FieldOffset(0)] - public byte B; - - /// - /// The green component. - /// - [FieldOffset(1)] - public byte G; - - /// - /// The red component. - /// - [FieldOffset(2)] - public byte R; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgr24(byte r, byte g, byte b) - { - this.R = r; - this.G = g; - this.B = b; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } - - /// - public override bool Equals(object obj) - { - return obj is Bgr24 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = source.Bgr; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - public void ToBgr24(ref Bgr24 dest) - { - dest = this; - } - - /// - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() - { - return $"({this.B},{this.G},{this.R})"; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgr565.cs b/src/ImageSharp/PixelFormats/Bgr565.cs deleted file mode 100644 index 570b975dba..0000000000 --- a/src/ImageSharp/PixelFormats/Bgr565.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits. - /// - /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. - /// - /// - public struct Bgr565 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// The x-component - /// The y-component - /// The z-component - public Bgr565(float x, float y, float z) - { - this.PackedValue = Pack(x, y, z); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed value. - /// - public Bgr565(Vector3 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); - } - - /// - public ushort PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgr565 left, Bgr565 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgr565 left, Bgr565 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector3 ToVector3() - { - return new Vector3( - ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), - ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), - (this.PackedValue & 0x1F) * (1F / 31F)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector3(), 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Bgr565 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgr565 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - public override string ToString() - { - return this.ToVector3().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z) - { - return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) - | (((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5) - | ((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F)); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra4444.cs b/src/ImageSharp/PixelFormats/Bgra4444.cs deleted file mode 100644 index 90f967f898..0000000000 --- a/src/ImageSharp/PixelFormats/Bgra4444.cs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing unsigned normalized values, ranging from 0 to 1, using 4 bits each for x, y, z, and w. - /// - /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. - /// - /// - public struct Bgra4444 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - public Bgra4444(float x, float y, float z, float w) - { - this.PackedValue = Pack(x, y, z, w); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components for the packed vector. - public Bgra4444(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - public ushort PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra4444 left, Bgra4444 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - const float Max = 1 / 15F; - - return new Vector4( - ((this.PackedValue >> 8) & 0x0F) * Max, - ((this.PackedValue >> 4) & 0x0F) * Max, - (this.PackedValue & 0x0F) * Max, - ((this.PackedValue >> 12) & 0x0F) * Max); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Bgra4444 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra4444 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - public override string ToString() - { - return this.ToVector4().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) - { - return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | - (((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | - (((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | - ((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); - } - } -} diff --git a/src/ImageSharp/PixelFormats/Bgra5551.cs b/src/ImageSharp/PixelFormats/Bgra5551.cs deleted file mode 100644 index 3a18c03e83..0000000000 --- a/src/ImageSharp/PixelFormats/Bgra5551.cs +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit. - /// - /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. - /// - /// - public struct Bgra5551 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - public Bgra5551(float x, float y, float z, float w) - { - this.PackedValue = Pack(x, y, z, w); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - public Bgra5551(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - public ushort PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Bgra5551 left, Bgra5551 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - ((this.PackedValue >> 10) & 0x1F) / 31F, - ((this.PackedValue >> 5) & 0x1F) / 31F, - ((this.PackedValue >> 0) & 0x1F) / 31F, - (this.PackedValue >> 15) & 0x01); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Bgra5551 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Bgra5551 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. - public override string ToString() - { - return this.ToVector4().ToString(); - } - - /// - /// Gets a hash code of the packed vector. - /// - /// The hash code for the packed vector. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y, float z, float w) - { - return (ushort)( - (((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10) - | (((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5) - | (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) - | (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f; - } -} diff --git a/src/ImageSharp/PixelFormats/Byte4.cs b/src/ImageSharp/PixelFormats/Byte4.cs deleted file mode 100644 index bb1b350f07..0000000000 --- a/src/ImageSharp/PixelFormats/Byte4.cs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing four 8-bit unsigned integer values, ranging from 0 to 255. - /// - /// Ranges from [0, 0, 0, 0] to [255, 255, 255, 255] in vector form. - /// - /// - public struct Byte4 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// - /// A vector containing the initial values for the components of the Byte4 structure. - /// - public Byte4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - public Byte4(float x, float y, float z, float w) - { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Byte4 left, Byte4 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Byte4 left, Byte4 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector * 255F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4() / 255F; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - this.PackedValue & 0xFF, - (this.PackedValue >> 0x8) & 0xFF, - (this.PackedValue >> 0x10) & 0xFF, - (this.PackedValue >> 0x18) & 0xFF); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToByteScaledVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - var vector = this.ToVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Byte4 byte4 && this.Equals(byte4); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Byte4 other) - { - return this == other; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. - public override string ToString() - { - return this.PackedValue.ToString("x8"); - } - - /// - /// Packs a vector into a uint. - /// - /// The vector containing the values to pack. - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(ref Vector4 vector) - { - const float Max = 255F; - const float Min = 0F; - - // Clamp the value between min and max values - // TODO: Use Vector4.Clamp() here! - uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF; - uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8; - uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10; - uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18; - - return byte4 | byte3 | byte2 | byte1; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index cf66f5d5e8..2572b32933 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The hexadecimal representation of the combined color components arranged /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. /// - /// Returns a that represents the color defined by the provided RGBA heax string. + /// Returns a that represents the color defined by the provided RGBA hex string. public static TPixel FromHex(string hex) { Guard.NotNullOrWhiteSpace(hex, nameof(hex)); @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats TPixel result = default; var rgba = new Rgba32(BinaryPrimitives.ReverseEndianness(packedValue)); - result.PackFromRgba32(rgba); + result.FromRgba32(rgba); return result; } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha) { TPixel color = default; - color.PackFromRgba32(new Rgba32(red, green, blue, alpha)); + color.FromRgba32(new Rgba32(red, green, blue, alpha)); return color; } diff --git a/src/ImageSharp/PixelFormats/ColorConstants.cs b/src/ImageSharp/PixelFormats/ColorConstants.cs index bac05c53d2..14df385697 100644 --- a/src/ImageSharp/PixelFormats/ColorConstants.cs +++ b/src/ImageSharp/PixelFormats/ColorConstants.cs @@ -11,157 +11,268 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4. /// - public static readonly Rgba32[] WebSafeColors = GetWebSafeColors(); + public static readonly Rgba32[] WebSafeColors = + { + Rgba32.AliceBlue, + Rgba32.AntiqueWhite, + Rgba32.Aqua, + Rgba32.Aquamarine, + Rgba32.Azure, + Rgba32.Beige, + Rgba32.Bisque, + Rgba32.Black, + Rgba32.BlanchedAlmond, + Rgba32.Blue, + Rgba32.BlueViolet, + Rgba32.Brown, + Rgba32.BurlyWood, + Rgba32.CadetBlue, + Rgba32.Chartreuse, + Rgba32.Chocolate, + Rgba32.Coral, + Rgba32.CornflowerBlue, + Rgba32.Cornsilk, + Rgba32.Crimson, + Rgba32.Cyan, + Rgba32.DarkBlue, + Rgba32.DarkCyan, + Rgba32.DarkGoldenrod, + Rgba32.DarkGray, + Rgba32.DarkGreen, + Rgba32.DarkKhaki, + Rgba32.DarkMagenta, + Rgba32.DarkOliveGreen, + Rgba32.DarkOrange, + Rgba32.DarkOrchid, + Rgba32.DarkRed, + Rgba32.DarkSalmon, + Rgba32.DarkSeaGreen, + Rgba32.DarkSlateBlue, + Rgba32.DarkSlateGray, + Rgba32.DarkTurquoise, + Rgba32.DarkViolet, + Rgba32.DeepPink, + Rgba32.DeepSkyBlue, + Rgba32.DimGray, + Rgba32.DodgerBlue, + Rgba32.Firebrick, + Rgba32.FloralWhite, + Rgba32.ForestGreen, + Rgba32.Fuchsia, + Rgba32.Gainsboro, + Rgba32.GhostWhite, + Rgba32.Gold, + Rgba32.Goldenrod, + Rgba32.Gray, + Rgba32.Green, + Rgba32.GreenYellow, + Rgba32.Honeydew, + Rgba32.HotPink, + Rgba32.IndianRed, + Rgba32.Indigo, + Rgba32.Ivory, + Rgba32.Khaki, + Rgba32.Lavender, + Rgba32.LavenderBlush, + Rgba32.LawnGreen, + Rgba32.LemonChiffon, + Rgba32.LightBlue, + Rgba32.LightCoral, + Rgba32.LightCyan, + Rgba32.LightGoldenrodYellow, + Rgba32.LightGray, + Rgba32.LightGreen, + Rgba32.LightPink, + Rgba32.LightSalmon, + Rgba32.LightSeaGreen, + Rgba32.LightSkyBlue, + Rgba32.LightSlateGray, + Rgba32.LightSteelBlue, + Rgba32.LightYellow, + Rgba32.Lime, + Rgba32.LimeGreen, + Rgba32.Linen, + Rgba32.Magenta, + Rgba32.Maroon, + Rgba32.MediumAquamarine, + Rgba32.MediumBlue, + Rgba32.MediumOrchid, + Rgba32.MediumPurple, + Rgba32.MediumSeaGreen, + Rgba32.MediumSlateBlue, + Rgba32.MediumSpringGreen, + Rgba32.MediumTurquoise, + Rgba32.MediumVioletRed, + Rgba32.MidnightBlue, + Rgba32.MintCream, + Rgba32.MistyRose, + Rgba32.Moccasin, + Rgba32.NavajoWhite, + Rgba32.Navy, + Rgba32.OldLace, + Rgba32.Olive, + Rgba32.OliveDrab, + Rgba32.Orange, + Rgba32.OrangeRed, + Rgba32.Orchid, + Rgba32.PaleGoldenrod, + Rgba32.PaleGreen, + Rgba32.PaleTurquoise, + Rgba32.PaleVioletRed, + Rgba32.PapayaWhip, + Rgba32.PeachPuff, + Rgba32.Peru, + Rgba32.Pink, + Rgba32.Plum, + Rgba32.PowderBlue, + Rgba32.Purple, + Rgba32.RebeccaPurple, + Rgba32.Red, + Rgba32.RosyBrown, + Rgba32.RoyalBlue, + Rgba32.SaddleBrown, + Rgba32.Salmon, + Rgba32.SandyBrown, + Rgba32.SeaGreen, + Rgba32.SeaShell, + Rgba32.Sienna, + Rgba32.Silver, + Rgba32.SkyBlue, + Rgba32.SlateBlue, + Rgba32.SlateGray, + Rgba32.Snow, + Rgba32.SpringGreen, + Rgba32.SteelBlue, + Rgba32.Tan, + Rgba32.Teal, + Rgba32.Thistle, + Rgba32.Tomato, + Rgba32.Transparent, + Rgba32.Turquoise, + Rgba32.Violet, + Rgba32.Wheat, + Rgba32.White, + Rgba32.WhiteSmoke, + Rgba32.Yellow, + Rgba32.YellowGreen + }; /// - /// Returns an array of web safe colors. + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux /// - /// The - private static Rgba32[] GetWebSafeColors() - => new Rgba32[] - { - Rgba32.AliceBlue, - Rgba32.AntiqueWhite, - Rgba32.Aqua, - Rgba32.Aquamarine, - Rgba32.Azure, - Rgba32.Beige, - Rgba32.Bisque, - Rgba32.Black, - Rgba32.BlanchedAlmond, - Rgba32.Blue, - Rgba32.BlueViolet, - Rgba32.Brown, - Rgba32.BurlyWood, - Rgba32.CadetBlue, - Rgba32.Chartreuse, - Rgba32.Chocolate, - Rgba32.Coral, - Rgba32.CornflowerBlue, - Rgba32.Cornsilk, - Rgba32.Crimson, - Rgba32.Cyan, - Rgba32.DarkBlue, - Rgba32.DarkCyan, - Rgba32.DarkGoldenrod, - Rgba32.DarkGray, - Rgba32.DarkGreen, - Rgba32.DarkKhaki, - Rgba32.DarkMagenta, - Rgba32.DarkOliveGreen, - Rgba32.DarkOrange, - Rgba32.DarkOrchid, - Rgba32.DarkRed, - Rgba32.DarkSalmon, - Rgba32.DarkSeaGreen, - Rgba32.DarkSlateBlue, - Rgba32.DarkSlateGray, - Rgba32.DarkTurquoise, - Rgba32.DarkViolet, - Rgba32.DeepPink, - Rgba32.DeepSkyBlue, - Rgba32.DimGray, - Rgba32.DodgerBlue, - Rgba32.Firebrick, - Rgba32.FloralWhite, - Rgba32.ForestGreen, - Rgba32.Fuchsia, - Rgba32.Gainsboro, - Rgba32.GhostWhite, - Rgba32.Gold, - Rgba32.Goldenrod, - Rgba32.Gray, - Rgba32.Green, - Rgba32.GreenYellow, - Rgba32.Honeydew, - Rgba32.HotPink, - Rgba32.IndianRed, - Rgba32.Indigo, - Rgba32.Ivory, - Rgba32.Khaki, - Rgba32.Lavender, - Rgba32.LavenderBlush, - Rgba32.LawnGreen, - Rgba32.LemonChiffon, - Rgba32.LightBlue, - Rgba32.LightCoral, - Rgba32.LightCyan, - Rgba32.LightGoldenrodYellow, - Rgba32.LightGray, - Rgba32.LightGreen, - Rgba32.LightPink, - Rgba32.LightSalmon, - Rgba32.LightSeaGreen, - Rgba32.LightSkyBlue, - Rgba32.LightSlateGray, - Rgba32.LightSteelBlue, - Rgba32.LightYellow, - Rgba32.Lime, - Rgba32.LimeGreen, - Rgba32.Linen, - Rgba32.Magenta, - Rgba32.Maroon, - Rgba32.MediumAquamarine, - Rgba32.MediumBlue, - Rgba32.MediumOrchid, - Rgba32.MediumPurple, - Rgba32.MediumSeaGreen, - Rgba32.MediumSlateBlue, - Rgba32.MediumSpringGreen, - Rgba32.MediumTurquoise, - Rgba32.MediumVioletRed, - Rgba32.MidnightBlue, - Rgba32.MintCream, - Rgba32.MistyRose, - Rgba32.Moccasin, - Rgba32.NavajoWhite, - Rgba32.Navy, - Rgba32.OldLace, - Rgba32.Olive, - Rgba32.OliveDrab, - Rgba32.Orange, - Rgba32.OrangeRed, - Rgba32.Orchid, - Rgba32.PaleGoldenrod, - Rgba32.PaleGreen, - Rgba32.PaleTurquoise, - Rgba32.PaleVioletRed, - Rgba32.PapayaWhip, - Rgba32.PeachPuff, - Rgba32.Peru, - Rgba32.Pink, - Rgba32.Plum, - Rgba32.PowderBlue, - Rgba32.Purple, - Rgba32.RebeccaPurple, - Rgba32.Red, - Rgba32.RosyBrown, - Rgba32.RoyalBlue, - Rgba32.SaddleBrown, - Rgba32.Salmon, - Rgba32.SandyBrown, - Rgba32.SeaGreen, - Rgba32.SeaShell, - Rgba32.Sienna, - Rgba32.Silver, - Rgba32.SkyBlue, - Rgba32.SlateBlue, - Rgba32.SlateGray, - Rgba32.Snow, - Rgba32.SpringGreen, - Rgba32.SteelBlue, - Rgba32.Tan, - Rgba32.Teal, - Rgba32.Thistle, - Rgba32.Tomato, - Rgba32.Transparent, - Rgba32.Turquoise, - Rgba32.Violet, - Rgba32.Wheat, - Rgba32.White, - Rgba32.WhiteSmoke, - Rgba32.Yellow, - Rgba32.YellowGreen - }; + public static readonly Rgba32[] WernerColors = + { + Rgba32.FromHex("#f1e9cd"), + Rgba32.FromHex("#f2e7cf"), + Rgba32.FromHex("#ece6d0"), + Rgba32.FromHex("#f2eacc"), + Rgba32.FromHex("#f3e9ca"), + Rgba32.FromHex("#f2ebcd"), + Rgba32.FromHex("#e6e1c9"), + Rgba32.FromHex("#e2ddc6"), + Rgba32.FromHex("#cbc8b7"), + Rgba32.FromHex("#bfbbb0"), + Rgba32.FromHex("#bebeb3"), + Rgba32.FromHex("#b7b5ac"), + Rgba32.FromHex("#bab191"), + Rgba32.FromHex("#9c9d9a"), + Rgba32.FromHex("#8a8d84"), + Rgba32.FromHex("#5b5c61"), + Rgba32.FromHex("#555152"), + Rgba32.FromHex("#413f44"), + Rgba32.FromHex("#454445"), + Rgba32.FromHex("#423937"), + Rgba32.FromHex("#433635"), + Rgba32.FromHex("#252024"), + Rgba32.FromHex("#241f20"), + Rgba32.FromHex("#281f3f"), + Rgba32.FromHex("#1c1949"), + Rgba32.FromHex("#4f638d"), + Rgba32.FromHex("#383867"), + Rgba32.FromHex("#5c6b8f"), + Rgba32.FromHex("#657abb"), + Rgba32.FromHex("#6f88af"), + Rgba32.FromHex("#7994b5"), + Rgba32.FromHex("#6fb5a8"), + Rgba32.FromHex("#719ba2"), + Rgba32.FromHex("#8aa1a6"), + Rgba32.FromHex("#d0d5d3"), + Rgba32.FromHex("#8590ae"), + Rgba32.FromHex("#3a2f52"), + Rgba32.FromHex("#39334a"), + Rgba32.FromHex("#6c6d94"), + Rgba32.FromHex("#584c77"), + Rgba32.FromHex("#533552"), + Rgba32.FromHex("#463759"), + Rgba32.FromHex("#bfbac0"), + Rgba32.FromHex("#77747f"), + Rgba32.FromHex("#4a475c"), + Rgba32.FromHex("#b8bfaf"), + Rgba32.FromHex("#b2b599"), + Rgba32.FromHex("#979c84"), + Rgba32.FromHex("#5d6161"), + Rgba32.FromHex("#61ac86"), + Rgba32.FromHex("#a4b6a7"), + Rgba32.FromHex("#adba98"), + Rgba32.FromHex("#93b778"), + Rgba32.FromHex("#7d8c55"), + Rgba32.FromHex("#33431e"), + Rgba32.FromHex("#7c8635"), + Rgba32.FromHex("#8e9849"), + Rgba32.FromHex("#c2c190"), + Rgba32.FromHex("#67765b"), + Rgba32.FromHex("#ab924b"), + Rgba32.FromHex("#c8c76f"), + Rgba32.FromHex("#ccc050"), + Rgba32.FromHex("#ebdd99"), + Rgba32.FromHex("#ab9649"), + Rgba32.FromHex("#dbc364"), + Rgba32.FromHex("#e6d058"), + Rgba32.FromHex("#ead665"), + Rgba32.FromHex("#d09b2c"), + Rgba32.FromHex("#a36629"), + Rgba32.FromHex("#a77d35"), + Rgba32.FromHex("#f0d696"), + Rgba32.FromHex("#d7c485"), + Rgba32.FromHex("#f1d28c"), + Rgba32.FromHex("#efcc83"), + Rgba32.FromHex("#f3daa7"), + Rgba32.FromHex("#dfa837"), + Rgba32.FromHex("#ebbc71"), + Rgba32.FromHex("#d17c3f"), + Rgba32.FromHex("#92462f"), + Rgba32.FromHex("#be7249"), + Rgba32.FromHex("#bb603c"), + Rgba32.FromHex("#c76b4a"), + Rgba32.FromHex("#a75536"), + Rgba32.FromHex("#b63e36"), + Rgba32.FromHex("#b5493a"), + Rgba32.FromHex("#cd6d57"), + Rgba32.FromHex("#711518"), + Rgba32.FromHex("#e9c49d"), + Rgba32.FromHex("#eedac3"), + Rgba32.FromHex("#eecfbf"), + Rgba32.FromHex("#ce536b"), + Rgba32.FromHex("#b74a70"), + Rgba32.FromHex("#b7757c"), + Rgba32.FromHex("#612741"), + Rgba32.FromHex("#7a4848"), + Rgba32.FromHex("#3f3033"), + Rgba32.FromHex("#8d746f"), + Rgba32.FromHex("#4d3635"), + Rgba32.FromHex("#6e3b31"), + Rgba32.FromHex("#864735"), + Rgba32.FromHex("#553d3a"), + Rgba32.FromHex("#613936"), + Rgba32.FromHex("#7a4b3a"), + Rgba32.FromHex("#946943"), + Rgba32.FromHex("#c39e6d"), + Rgba32.FromHex("#513e32"), + Rgba32.FromHex("#8b7859"), + Rgba32.FromHex("#9b856b"), + Rgba32.FromHex("#766051"), + Rgba32.FromHex("#453b32") + }; } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/ComponentOrder.cs b/src/ImageSharp/PixelFormats/ComponentOrder.cs deleted file mode 100644 index 868d082599..0000000000 --- a/src/ImageSharp/PixelFormats/ComponentOrder.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Enumerates the various component orders. - /// - internal enum ComponentOrder - { - /// - /// Z-> Y-> X order. Equivalent to B-> G-> R in - /// - Zyx, - - /// - /// Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in - /// - Zyxw, - - /// - /// X-> Y-> Z order. Equivalent to R-> G-> B in - /// - Xyz, - - /// - /// X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in - /// - Xyzw, - } -} diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs deleted file mode 100644 index e8908fe05e..0000000000 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ /dev/null @@ -1,520 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// -namespace SixLabors.ImageSharp.PixelFormats -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - public partial class PixelOperations - { - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromRgba64(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba64(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba64Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromRgba64(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgba64(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba64(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba64Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToRgba64(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromRgb48(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgb48(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb48Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromRgb48(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgb48(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb48(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb48Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToRgb48(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgba32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromRgba32(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgba32(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgba32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToRgba32(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromBgra32(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgra32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromBgra32(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgra32(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgra32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToBgra32(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromRgb24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromRgb24(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToRgb24(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToRgb24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToRgb24(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp.Bgr = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromBgr24Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromBgr24(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToBgr24(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToBgr24Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToBgr24(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - temp = Unsafe.Add(ref sourceRef, i); - dp.PackFromArgb32(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFromArgb32Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFromArgb32(MemoryMarshal.Cast(sourceBytes), destPixels, count); - } - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - sp.ToArgb32(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void ToArgb32Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.ToArgb32(sourceColors, MemoryMarshal.Cast(destBytes), count); - } - - } - -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt deleted file mode 100644 index 5c762c7df1..0000000000 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ /dev/null @@ -1,136 +0,0 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> -<#@ import namespace="System.Runtime.InteropServices" #> -<#@ output extension=".cs" #> -<# - - void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! - var temp = NamedColors<<#=tempPixelType#>>.Black; - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=assignToTempCode#> - dp.PackFrom<#=tempPixelType#>(temp); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GenerateToDestFormatMethods(string pixelType) - { - #> - - /// - /// Converts 'count' pixels in 'sourcePixels` span to a span of -s. - /// Bulk version of . - /// - /// The span of source pixels - /// The destination span of data. - /// The number of pixels to convert. - internal virtual void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - sp.To<#=pixelType#>(ref dp); - } - } - - /// - /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. - /// - /// The to the source colors. - /// The to the destination bytes. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void To<#=pixelType#>Bytes(ReadOnlySpan sourceColors, Span destBytes, int count) - { - this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast>(destBytes), count); - } - <# - } - -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// -namespace SixLabors.ImageSharp.PixelFormats -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - public partial class PixelOperations - { - <# - GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba64"); - - GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb48"); - - GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgba32"); - - GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Bgra32"); - - GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Rgb24"); - - GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Bgr24"); - - GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); - GenerateToDestFormatMethods("Argb32"); - #> - - } - -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs deleted file mode 100644 index e68efba252..0000000000 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// -namespace SixLabors.ImageSharp.PixelFormats -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - /// - /// Provides optimized overrides for bulk operations. - /// - public partial struct Rgba32 - { - internal partial class PixelOperations - { - - /// - internal override void PackFromRgb24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - Unsafe.As(ref dp) = sp; dp.A = 255; - } - } - - /// - internal override void ToRgb24(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - dp = Unsafe.As(ref sp); - } - } - - /// - internal override void PackFromBgr24(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp.Bgr = sp; dp.A = 255; - } - } - - /// - internal override void ToBgr24(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.Bgr; - } - } - - /// - internal override void PackFromBgra32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); - } - } - - /// - internal override void ToBgra32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToBgra32(); - } - } - - /// - internal override void PackFromArgb32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToRgba32(); - } - } - - /// - internal override void ToArgb32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToArgb32(); - } - } - - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt deleted file mode 100644 index a734333390..0000000000 --- a/src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt +++ /dev/null @@ -1,89 +0,0 @@ -<# -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. -#> -<#@ template debug="false" hostspecific="false" language="C#" #> -<#@ assembly name="System.Core" #> -<#@ import namespace="System.Linq" #> -<#@ import namespace="System.Text" #> -<#@ import namespace="System.Collections.Generic" #> -<#@ output extension=".cs" #> -<# - void GeneratePackFromMethod(string pixelType, string converterCode) - { - #> - - /// - internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); - - for (int i = 0; i < count; i++) - { - ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> - } - } - <# - } - - void GenerateConvertToMethod(string pixelType, string converterCode) - { - #> - - /// - internal override void To<#=pixelType#>(ReadOnlySpan sourcePixels, Span<<#=pixelType#>> dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(dest); - - for (int i = 0; i < count; i++) - { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); - <#=converterCode#> - } - } - <# - } -#> -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// -namespace SixLabors.ImageSharp.PixelFormats -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - /// - /// Provides optimized overrides for bulk operations. - /// - public partial struct Rgba32 - { - internal partial class PixelOperations - { - <# - GeneratePackFromMethod("Rgb24", "Unsafe.As(ref dp) = sp; dp.A = 255;"); - GenerateConvertToMethod("Rgb24", "dp = Unsafe.As(ref sp);"); - - GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); - GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); - - GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); - - GeneratePackFromMethod("Argb32", "dp = sp.ToRgba32();"); - GenerateConvertToMethod("Argb32", "dp = sp.ToArgb32();"); - #> - - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfSingle.cs b/src/ImageSharp/PixelFormats/HalfSingle.cs deleted file mode 100644 index 09b4636492..0000000000 --- a/src/ImageSharp/PixelFormats/HalfSingle.cs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing a single 16 bit floating point value. - /// - /// Ranges from [-1, 0, 0, 1] to [1, 0, 0, 1] in vector form. - /// - /// - public struct HalfSingle : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The single component. - public HalfSingle(float single) - { - this.PackedValue = HalfTypeHelper.Pack(single); - } - - /// - public ushort PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfSingle left, HalfSingle right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfSingle left, HalfSingle right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float ToSingle() - { - return HalfTypeHelper.Unpack(this.PackedValue); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - float scaled = vector.X; - scaled *= 2F; - scaled -= 1F; - this.PackedValue = HalfTypeHelper.Pack(scaled); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - float single = this.ToSingle() + 1F; - single /= 2F; - return new Vector4(single, 0, 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = HalfTypeHelper.Pack(vector.X); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToSingle(), 0, 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is HalfSingle other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfSingle other) - { - return this.PackedValue == other.PackedValue; - } - - /// - public override string ToString() - { - return this.ToSingle().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs index cf8b9f4a23..e8cfaa462e 100644 --- a/src/ImageSharp/PixelFormats/HalfTypeHelper.cs +++ b/src/ImageSharp/PixelFormats/HalfTypeHelper.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Helper methods for packing and unpacking floating point values /// - internal class HalfTypeHelper + internal static class HalfTypeHelper { /// /// Packs a into an @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats return (ushort)s; } - m = m | 0x00800000; + m |= 0x00800000; int t = 14 - e; int a = (1 << (t - 1)) - 1; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.PixelFormats if ((m & 0x00800000) != 0) { m = 0; - e += 1; + e++; } if (e > 30) @@ -97,11 +97,11 @@ namespace SixLabors.ImageSharp.PixelFormats while ((mantissa & 1024) == 0) { exponent--; - mantissa = mantissa << 1; + mantissa <<= 1; } mantissa &= 0xfffffbff; - result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13); } else { @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats } else { - result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); + result = (((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23) | (mantissa << 13); } var uif = new Uif { U = result }; diff --git a/src/ImageSharp/PixelFormats/HalfVector2.cs b/src/ImageSharp/PixelFormats/HalfVector2.cs deleted file mode 100644 index befa49736c..0000000000 --- a/src/ImageSharp/PixelFormats/HalfVector2.cs +++ /dev/null @@ -1,273 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing two 16-bit floating-point values. - /// - /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. - /// - /// - public struct HalfVector2 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - public HalfVector2(float x, float y) - { - this.PackedValue = Pack(x, y); - } - - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components. - public HalfVector2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector2 left, HalfVector2 right) - { - return left.Equals(right); - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector2 left, HalfVector2 right) - { - return !left.Equals(right); - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - /// Expands the packed representation into a . - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - Vector2 vector; - vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); - vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); - return vector; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - var vector = this.ToVector2(); - return new Vector4(vector.X, vector.Y, 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() - { - return this.ToVector2().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - public override bool Equals(object obj) - { - return obj is HalfVector2 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector2 other) - { - return this.PackedValue.Equals(other.PackedValue); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) - { - uint num2 = HalfTypeHelper.Pack(x); - uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); - return num2 | num; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/HalfVector4.cs b/src/ImageSharp/PixelFormats/HalfVector4.cs deleted file mode 100644 index 885e022921..0000000000 --- a/src/ImageSharp/PixelFormats/HalfVector4.cs +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing four 16-bit floating-point values. - /// - /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. - /// - /// - public struct HalfVector4 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - /// The z-component. - /// The w-component. - public HalfVector4(float x, float y, float z, float w) - { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); - } - - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components - public HalfVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } - - /// - public ulong PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(HalfVector4 left, HalfVector4 right) - { - return left.Equals(right); - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HalfVector4 left, HalfVector4 right) - { - return !left.Equals(right); - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector4(); - scaled += Vector4.One; - scaled /= 2F; - return scaled; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(ref vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - HalfTypeHelper.Unpack((ushort)this.PackedValue), - HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)), - HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x20)), - HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30))); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() - { - return this.ToVector4().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - public override bool Equals(object obj) - { - return obj is HalfVector4 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(HalfVector4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } - - /// - /// Packs a into a . - /// - /// The vector containing the values to pack. - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(ref Vector4 vector) - { - ulong num4 = HalfTypeHelper.Pack(vector.X); - ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10; - ulong num2 = (ulong)HalfTypeHelper.Pack(vector.Z) << 0x20; - ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; - return num4 | num3 | num2 | num1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= MaxBytes; - vector += Half; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index ae09af626c..1277406869 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -24,107 +24,95 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - /// An interface that represents a pixel type. + /// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. /// public interface IPixel { /// - /// Sets the packed representation from a . + /// Initializes the pixel instance from a generic ("scaled") . /// - /// The vector to create the packed representation from. - void PackFromVector4(Vector4 vector); + /// The vector to load the pixel from. + void FromScaledVector4(Vector4 vector); /// - /// Sets the packed representation from a scaled . - /// - /// The vector to create the packed representation from. - void PackFromScaledVector4(Vector4 vector); - - /// - /// Expands the packed representation into a scaled - /// with values clamped between 0 and 1. + /// Expands the pixel into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. /// The vector components are typically expanded in least to greatest significance order. /// /// The . Vector4 ToScaledVector4(); /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. + /// Initializes the pixel instance from a which is specific to the current pixel type. /// - /// The . - Vector4 ToVector4(); + /// The vector to load the pixel from. + void FromVector4(Vector4 vector); /// - /// Packs the pixel from an value. - /// - /// The value. - void PackFromRgba32(Rgba32 source); - - /// - /// Packs the pixel from an value. + /// Expands the pixel into a which is specific to the current pixel type. + /// The vector components are typically expanded in least to greatest significance order. /// - /// The value. - void PackFromRgb48(Rgb48 source); + /// The . + Vector4 ToVector4(); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// - /// The value. - void PackFromRgba64(Rgba64 source); + /// The value. + void FromArgb32(Argb32 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// - /// The value. - void PackFromArgb32(Argb32 source); + /// The value. + void FromBgr24(Bgr24 source); /// - /// Packs the pixel from an value. + /// Initializes the pixel instance from an value. /// /// The value. - void PackFromBgra32(Bgra32 source); + void FromBgra32(Bgra32 source); /// - /// Converts the pixel to format. + /// Initializes the pixel instance from an value. /// - /// The destination pixel to write to - void ToRgb24(ref Rgb24 dest); + /// The value. + void FromGray8(Gray8 source); /// - /// Converts the pixel to format. + /// Initializes the pixel instance from an value. /// - /// The destination pixel to write to - void ToRgba32(ref Rgba32 dest); + /// The value. + void FromGray16(Gray16 source); /// - /// Converts the pixel to format. + /// Initializes the pixel instance from an value. /// - /// The destination pixel to write to - void ToRgb48(ref Rgb48 dest); + /// The value. + void FromRgb24(Rgb24 source); /// - /// Converts the pixel to format. + /// Initializes the pixel instance from an value. /// - /// The destination pixel to write to - void ToRgba64(ref Rgba64 dest); + /// The value. + void FromRgba32(Rgba32 source); /// - /// Converts the pixel to format. + /// Convert the pixel instance into representation. /// - /// The destination pixel to write to - void ToArgb32(ref Argb32 dest); + /// The reference to the destination pixel + void ToRgba32(ref Rgba32 dest); /// - /// Converts the pixel to format. + /// Initializes the pixel instance from an value. /// - /// The destination pixel to write to - void ToBgr24(ref Bgr24 dest); + /// The value. + void FromRgb48(Rgb48 source); /// - /// Converts the pixel to format. + /// Initializes the pixel instance from an value. /// - /// The destination pixel to write to - void ToBgra32(ref Bgra32 dest); + /// The value. + void FromRgba64(Rgba64 source); } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs index 0f42e182c5..7e093de042 100644 --- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs @@ -14,9 +14,10 @@ namespace SixLabors.ImageSharp.PixelFormats where TPixel : struct, IPixel { /// - /// Thread-safe backing field for . + /// Thread-safe backing field for the constant palettes. /// private static readonly Lazy WebSafePaletteLazy = new Lazy(GetWebSafePalette, true); + private static readonly Lazy WernerPaletteLazy = new Lazy(GetWernerPalette, true); /// /// Represents a matching the W3C definition that has an hex value of #F0F8FF. @@ -729,18 +730,32 @@ namespace SixLabors.ImageSharp.PixelFormats public static readonly TPixel YellowGreen = ColorBuilder.FromRGBA(154, 205, 50, 255); /// - /// Gets a matching the W3C definition of web safe colors. + /// Gets a collection of web safe, colors as defined in the CSS Color Module Level 4. /// public static TPixel[] WebSafePalette => WebSafePaletteLazy.Value; - private static TPixel[] GetWebSafePalette() + /// + /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public static TPixel[] WernerPalette => WernerPaletteLazy.Value; + + private static TPixel[] GetWebSafePalette() => GetPalette(ColorConstants.WebSafeColors); + + private static TPixel[] GetWernerPalette() => GetPalette(ColorConstants.WernerColors); + + private static TPixel[] GetPalette(Rgba32[] palette) { - Rgba32[] constants = ColorConstants.WebSafeColors; - var safe = new TPixel[constants.Length + 1]; + var converted = new TPixel[palette.Length]; + + Span constantsBytes = MemoryMarshal.Cast(palette.AsSpan()); + PixelOperations.Instance.FromRgba32Bytes( + Configuration.Default, + constantsBytes, + converted, + palette.Length); - Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan()); - PixelOperations.Instance.PackFromRgba32Bytes(constantsBytes, safe, constants.Length); - return safe; + return converted; } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/NormalizedByte2.cs deleted file mode 100644 index 8592fdd6a7..0000000000 --- a/src/ImageSharp/PixelFormats/NormalizedByte2.cs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed packed pixel type containing two 8-bit signed normalized values, ranging from −1 to 1. - /// - /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. - /// - /// - public struct NormalizedByte2 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - public NormalizedByte2(float x, float y) - { - this.PackedValue = Pack(x, y); - } - - /// - public ushort PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is NormalizedByte2 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte2 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - public override string ToString() - { - return this.PackedValue.ToString("X"); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ushort Pack(float x, float y) - { - int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; - - return (ushort)(byte2 | byte1); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/NormalizedByte4.cs deleted file mode 100644 index 293d536e53..0000000000 --- a/src/ImageSharp/PixelFormats/NormalizedByte4.cs +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing four 8-bit signed normalized values, ranging from −1 to 1. - /// - /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. - /// - /// - public struct NormalizedByte4 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - /// The z-component. - /// The w-component. - public NormalizedByte4(float x, float y, float z, float w) - { - this.PackedValue = Pack(x, y, z, w); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector4(); - scaled += Vector4.One; - scaled /= 2F; - return scaled; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 16) & 0xFF) / 127F, - (sbyte)((this.PackedValue >> 24) & 0xFF) / 127F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is NormalizedByte4 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedByte4 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - public override string ToString() - { - return this.PackedValue.ToString("X"); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) - { - uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; - uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8; - uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16; - uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24; - - return byte4 | byte3 | byte2 | byte1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/NormalizedShort2.cs deleted file mode 100644 index 1ced412d06..0000000000 --- a/src/ImageSharp/PixelFormats/NormalizedShort2.cs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing two 16-bit signed normalized values, ranging from −1 to 1. - /// - /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. - /// - /// - public struct NormalizedShort2 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - public NormalizedShort2(float x, float y) - { - this.PackedValue = Pack(x, y); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) - { - return left.Equals(right); - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) - { - return !left.Equals(right); - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - const float MaxVal = 0x7FFF; - - return new Vector2( - (short)(this.PackedValue & 0xFFFF) / MaxVal, - (short)(this.PackedValue >> 0x10) / MaxVal); - } - - /// - public override bool Equals(object obj) - { - return obj is NormalizedShort2 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort2 other) - { - return this.PackedValue.Equals(other.PackedValue); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } - - /// - public override string ToString() - { - return this.PackedValue.ToString("X"); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) - { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; - - // Clamp the value between min and max values - // Round rather than truncate. - uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); - uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); - - return word2 | word1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/NormalizedShort4.cs deleted file mode 100644 index 25b26fa7f7..0000000000 --- a/src/ImageSharp/PixelFormats/NormalizedShort4.cs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing four 16-bit signed normalized values, ranging from −1 to 1. - /// - /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. - /// - /// - public struct NormalizedShort4 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - /// The z-component. - /// The w-component. - public NormalizedShort4(float x, float y, float z, float w) - { - this.PackedValue = Pack(x, y, z, w); - } - - /// - public ulong PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) - { - return left.Equals(right); - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) - { - return !left.Equals(right); - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector4(); - scaled += Vector4.One; - scaled /= 2F; - return scaled; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - const float MaxVal = 0x7FFF; - - return new Vector4( - (short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxVal, - (short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxVal, - (short)((this.PackedValue >> 0x20) & 0xFFFF) / MaxVal, - (short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxVal); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector4 vector = source.ToByteScaledVector4(); - vector -= Round; - vector -= Half; - vector -= Round; - vector /= Half; - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is NormalizedShort4 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(NormalizedShort4 other) - { - return this.PackedValue.Equals(other.PackedValue); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } - - /// - public override string ToString() - { - return this.PackedValue.ToString("X"); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) - { - const float MaxPos = 0x7FFF; - const float MinNeg = -MaxPos; - - // Clamp the value between min and max values - ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; - - return word4 | word3 | word2 | word1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector *= Half; - vector += Round; - vector += Half; - vector += Round; - vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - return vector; - } - } -} diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 2ca58c461a..0cf8d6bbbf 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -1,11 +1,4 @@ - - - - - - - -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // @@ -33,7 +26,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders where TPixel : struct, IPixel { - internal class NormalSrc : PixelBlender { /// @@ -45,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -69,7 +61,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrc : PixelBlender { /// @@ -81,7 +72,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -105,7 +96,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrc : PixelBlender { /// @@ -117,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -141,7 +131,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrc : PixelBlender { /// @@ -153,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -177,7 +166,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrc : PixelBlender { /// @@ -189,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -213,7 +201,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrc : PixelBlender { /// @@ -225,7 +212,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -249,7 +236,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrc : PixelBlender { /// @@ -261,7 +247,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -285,7 +271,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrc : PixelBlender { /// @@ -297,7 +282,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -321,7 +306,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrc : PixelBlender { /// @@ -333,7 +317,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -357,7 +341,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcAtop : PixelBlender { /// @@ -369,7 +352,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -393,7 +376,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcAtop : PixelBlender { /// @@ -405,7 +387,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -429,7 +411,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcAtop : PixelBlender { /// @@ -441,7 +422,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -465,7 +446,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcAtop : PixelBlender { /// @@ -477,7 +457,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -501,7 +481,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcAtop : PixelBlender { /// @@ -513,7 +492,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -537,7 +516,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcAtop : PixelBlender { /// @@ -549,7 +527,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -573,7 +551,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcAtop : PixelBlender { /// @@ -585,7 +562,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -609,7 +586,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcAtop : PixelBlender { /// @@ -621,7 +597,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -645,7 +621,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcAtop : PixelBlender { /// @@ -657,7 +632,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -681,7 +656,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcOver : PixelBlender { /// @@ -693,7 +667,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -717,7 +691,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcOver : PixelBlender { /// @@ -729,7 +702,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -753,7 +726,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcOver : PixelBlender { /// @@ -765,7 +737,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -789,7 +761,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcOver : PixelBlender { /// @@ -801,7 +772,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -825,7 +796,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcOver : PixelBlender { /// @@ -837,7 +807,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -861,7 +831,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcOver : PixelBlender { /// @@ -873,7 +842,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -897,7 +866,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcOver : PixelBlender { /// @@ -909,7 +877,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -933,7 +901,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcOver : PixelBlender { /// @@ -945,7 +912,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -969,7 +936,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcOver : PixelBlender { /// @@ -981,7 +947,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1005,7 +971,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcIn : PixelBlender { /// @@ -1017,7 +982,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1041,7 +1006,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcIn : PixelBlender { /// @@ -1053,7 +1017,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1077,7 +1041,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcIn : PixelBlender { /// @@ -1089,7 +1052,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1113,7 +1076,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcIn : PixelBlender { /// @@ -1125,7 +1087,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1149,7 +1111,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcIn : PixelBlender { /// @@ -1161,7 +1122,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1185,7 +1146,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcIn : PixelBlender { /// @@ -1197,7 +1157,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1221,7 +1181,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcIn : PixelBlender { /// @@ -1233,7 +1192,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1257,7 +1216,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcIn : PixelBlender { /// @@ -1269,7 +1227,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1293,7 +1251,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcIn : PixelBlender { /// @@ -1305,7 +1262,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1329,7 +1286,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalSrcOut : PixelBlender { /// @@ -1341,7 +1297,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1365,7 +1321,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplySrcOut : PixelBlender { /// @@ -1377,7 +1332,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1401,7 +1356,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddSrcOut : PixelBlender { /// @@ -1413,7 +1367,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1437,7 +1391,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractSrcOut : PixelBlender { /// @@ -1449,7 +1402,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1473,7 +1426,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenSrcOut : PixelBlender { /// @@ -1485,7 +1437,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1509,7 +1461,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenSrcOut : PixelBlender { /// @@ -1521,7 +1472,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1545,7 +1496,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenSrcOut : PixelBlender { /// @@ -1557,7 +1507,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1581,7 +1531,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlaySrcOut : PixelBlender { /// @@ -1593,7 +1542,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1617,7 +1566,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightSrcOut : PixelBlender { /// @@ -1629,7 +1577,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1653,7 +1601,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDest : PixelBlender { /// @@ -1665,7 +1612,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1689,7 +1636,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDest : PixelBlender { /// @@ -1701,7 +1647,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1725,7 +1671,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDest : PixelBlender { /// @@ -1737,7 +1682,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1761,7 +1706,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDest : PixelBlender { /// @@ -1773,7 +1717,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1797,7 +1741,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDest : PixelBlender { /// @@ -1809,7 +1752,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1833,7 +1776,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDest : PixelBlender { /// @@ -1845,7 +1787,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1869,7 +1811,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDest : PixelBlender { /// @@ -1881,7 +1822,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1905,7 +1846,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDest : PixelBlender { /// @@ -1917,7 +1857,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1941,7 +1881,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDest : PixelBlender { /// @@ -1953,7 +1892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -1977,7 +1916,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestAtop : PixelBlender { /// @@ -1989,7 +1927,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2013,7 +1951,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestAtop : PixelBlender { /// @@ -2025,7 +1962,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2049,7 +1986,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestAtop : PixelBlender { /// @@ -2061,7 +1997,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2085,7 +2021,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestAtop : PixelBlender { /// @@ -2097,7 +2032,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2121,7 +2056,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestAtop : PixelBlender { /// @@ -2133,7 +2067,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2157,7 +2091,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestAtop : PixelBlender { /// @@ -2169,7 +2102,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2193,7 +2126,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestAtop : PixelBlender { /// @@ -2205,7 +2137,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2229,7 +2161,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestAtop : PixelBlender { /// @@ -2241,7 +2172,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2265,7 +2196,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestAtop : PixelBlender { /// @@ -2277,7 +2207,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2301,7 +2231,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestOver : PixelBlender { /// @@ -2313,7 +2242,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2337,7 +2266,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestOver : PixelBlender { /// @@ -2349,7 +2277,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2373,7 +2301,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestOver : PixelBlender { /// @@ -2385,7 +2312,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2409,7 +2336,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestOver : PixelBlender { /// @@ -2421,7 +2347,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2445,7 +2371,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestOver : PixelBlender { /// @@ -2457,7 +2382,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2481,7 +2406,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestOver : PixelBlender { /// @@ -2493,7 +2417,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2517,7 +2441,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestOver : PixelBlender { /// @@ -2529,7 +2452,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2553,7 +2476,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestOver : PixelBlender { /// @@ -2565,7 +2487,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2589,7 +2511,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestOver : PixelBlender { /// @@ -2601,7 +2522,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2625,7 +2546,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestIn : PixelBlender { /// @@ -2637,7 +2557,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2661,7 +2581,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestIn : PixelBlender { /// @@ -2673,7 +2592,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2697,7 +2616,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestIn : PixelBlender { /// @@ -2709,7 +2627,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2733,7 +2651,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestIn : PixelBlender { /// @@ -2745,7 +2662,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2769,7 +2686,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestIn : PixelBlender { /// @@ -2781,7 +2697,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2805,7 +2721,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestIn : PixelBlender { /// @@ -2817,7 +2732,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2841,7 +2756,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestIn : PixelBlender { /// @@ -2853,7 +2767,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2877,7 +2791,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestIn : PixelBlender { /// @@ -2889,7 +2802,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2913,7 +2826,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestIn : PixelBlender { /// @@ -2925,7 +2837,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2949,7 +2861,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalDestOut : PixelBlender { /// @@ -2961,7 +2872,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -2985,7 +2896,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyDestOut : PixelBlender { /// @@ -2997,7 +2907,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3021,7 +2931,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddDestOut : PixelBlender { /// @@ -3033,7 +2942,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3057,7 +2966,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractDestOut : PixelBlender { /// @@ -3069,7 +2977,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3093,7 +3001,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenDestOut : PixelBlender { /// @@ -3105,7 +3012,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3129,7 +3036,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenDestOut : PixelBlender { /// @@ -3141,7 +3047,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3165,7 +3071,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenDestOut : PixelBlender { /// @@ -3177,7 +3082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3201,7 +3106,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayDestOut : PixelBlender { /// @@ -3213,7 +3117,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3237,7 +3141,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightDestOut : PixelBlender { /// @@ -3249,7 +3152,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3273,7 +3176,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalClear : PixelBlender { /// @@ -3285,7 +3187,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3309,7 +3211,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyClear : PixelBlender { /// @@ -3321,7 +3222,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3345,7 +3246,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddClear : PixelBlender { /// @@ -3357,7 +3257,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3381,7 +3281,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractClear : PixelBlender { /// @@ -3393,7 +3292,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3417,7 +3316,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenClear : PixelBlender { /// @@ -3429,7 +3327,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3453,7 +3351,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenClear : PixelBlender { /// @@ -3465,7 +3362,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3489,7 +3386,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenClear : PixelBlender { /// @@ -3501,7 +3397,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3525,7 +3421,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayClear : PixelBlender { /// @@ -3537,7 +3432,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3561,7 +3456,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightClear : PixelBlender { /// @@ -3573,7 +3467,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3597,7 +3491,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class NormalXor : PixelBlender { /// @@ -3609,7 +3502,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3633,7 +3526,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class MultiplyXor : PixelBlender { /// @@ -3645,7 +3537,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3669,7 +3561,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class AddXor : PixelBlender { /// @@ -3681,7 +3572,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3705,7 +3596,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class SubtractXor : PixelBlender { /// @@ -3717,7 +3607,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3741,7 +3631,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class ScreenXor : PixelBlender { /// @@ -3753,7 +3642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3777,7 +3666,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class DarkenXor : PixelBlender { /// @@ -3789,7 +3677,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3813,7 +3701,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class LightenXor : PixelBlender { /// @@ -3825,7 +3712,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3849,7 +3736,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class OverlayXor : PixelBlender { /// @@ -3861,7 +3747,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3885,7 +3771,6 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - internal class HardLightXor : PixelBlender { /// @@ -3897,7 +3782,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } @@ -3921,6 +3806,5 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } } - } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index ca7031df28..2cca55e4c3 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 0a6ef60eca..64148746e0 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -356,7 +356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -368,7 +368,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -392,7 +392,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -404,7 +404,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -416,7 +416,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -428,7 +428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -464,7 +464,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -476,7 +476,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -488,7 +488,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -594,7 +594,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -606,7 +606,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -618,7 +618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -630,7 +630,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -642,7 +642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -654,7 +654,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -666,7 +666,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -678,7 +678,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -690,7 +690,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -702,7 +702,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -714,7 +714,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -726,7 +726,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -832,7 +832,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -844,7 +844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -856,7 +856,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -868,7 +868,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -880,7 +880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -892,7 +892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -904,7 +904,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -916,7 +916,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -928,7 +928,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -940,7 +940,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -952,7 +952,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -964,7 +964,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1070,7 +1070,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1082,7 +1082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1094,7 +1094,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1106,7 +1106,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1118,7 +1118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1130,7 +1130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1142,7 +1142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1154,7 +1154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1166,7 +1166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1178,7 +1178,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1190,7 +1190,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1202,7 +1202,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1308,7 +1308,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1320,7 +1320,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1332,7 +1332,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1344,7 +1344,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1356,7 +1356,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1368,7 +1368,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1380,7 +1380,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1392,7 +1392,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1404,7 +1404,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1416,7 +1416,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1428,7 +1428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1440,7 +1440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1546,7 +1546,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1558,7 +1558,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1570,7 +1570,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1582,7 +1582,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1594,7 +1594,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1606,7 +1606,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1618,7 +1618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1630,7 +1630,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1642,7 +1642,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1654,7 +1654,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1666,7 +1666,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1678,7 +1678,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1784,7 +1784,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1796,7 +1796,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1808,7 +1808,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1820,7 +1820,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1832,7 +1832,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1844,7 +1844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1856,7 +1856,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1868,7 +1868,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1880,7 +1880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1892,7 +1892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1904,7 +1904,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1916,7 +1916,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2022,7 +2022,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2034,7 +2034,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2046,7 +2046,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2058,7 +2058,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2070,7 +2070,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2082,7 +2082,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2094,7 +2094,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2106,7 +2106,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2118,7 +2118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2130,7 +2130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2142,7 +2142,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2154,7 +2154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 73c835e606..e21a78031f 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); + dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index a531716117..e5109fd424 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -4,8 +4,8 @@ using System; using System.Buffers; using System.Numerics; + using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats { @@ -38,7 +38,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount); /// /// Blend 2 rows together. @@ -50,12 +54,16 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount); + protected abstract void BlendFunction( + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount); /// /// Blends 2 rows together /// - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -63,16 +71,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) { - this.Blend(memoryManager, destination, background, source, amount); + this.Blend(configuration, destination, background, source, amount); } /// /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -80,25 +93,40 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + ReadOnlySpan amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } @@ -106,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Blends 2 rows together /// /// the pixel format of the source span - /// memory manager to use internally + /// to use internally /// the destination span /// the background span /// the source span @@ -114,26 +142,41 @@ namespace SixLabors.ImageSharp.PixelFormats /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + public void Blend( + Configuration configuration, + Span destination, + ReadOnlySpan background, + ReadOnlySpan source, + float amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + using (IMemoryOwner buffer = + configuration.MemoryAllocator.Allocate(destination.Length * 3)) { Span destinationSpan = buffer.Slice(0, destination.Length); Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4( + configuration, + background.Slice(0, background.Length), + backgroundSpan); + PixelOperations.Instance.ToScaledVector4( + configuration, + source.Slice(0, background.Length), + sourceSpan); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromScaledVector4( + configuration, + destinationSpan.Slice(0, background.Length), + destination); } } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs new file mode 100644 index 0000000000..75b7ede827 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Alpha8.cs @@ -0,0 +1,155 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 8 bit normalized W values. + /// + /// Ranges from [0, 0, 0, 0] to [0, 0, 0, 1] in vector form. + /// + /// + public struct Alpha8 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The alpha component. + public Alpha8(byte alpha) => this.PackedValue = alpha; + + /// + /// Initializes a new instance of the struct. + /// + /// The alpha component. + public Alpha8(float alpha) => this.PackedValue = Pack(alpha); + + /// + public byte PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// + /// The on the left side of the operand. + /// + /// + /// The on the right side of the operand. + /// + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.PackedValue = source.A; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.PackedValue = source.A; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.PackedValue = byte.MaxValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.PackedValue = byte.MaxValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.PackedValue = source.A; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest = default; + dest.A = this.PackedValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Compares an object with the packed vector. + /// + /// The object to compare. + /// True if the object is equal to the packed vector. + public override bool Equals(object obj) => obj is Alpha8 other && this.Equals(other); + + /// + /// Compares another Alpha8 packed vector with the packed vector. + /// + /// The Alpha8 packed vector to compare. + /// True if the packed vectors are equal. + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue); + + /// + /// Gets a string representation of the packed vector. + /// + /// A string representation of the packed vector. + public override string ToString() => $"Alpha8({this.PackedValue})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + /// Packs a into a byte. + /// + /// The float containing the value to pack. + /// The containing the packed values. + [MethodImpl(InliningOptions.ShortMethod)] + private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1F) * 255F); + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs similarity index 56% rename from src/ImageSharp/PixelFormats/Argb32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 51d3964ef8..8fc3016314 100644 --- a/src/ImageSharp/PixelFormats/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// as it avoids the need to create new values for modification operations. /// [StructLayout(LayoutKind.Sequential)] - public struct Argb32 : IPixel, IPackedVector + public partial struct Argb32 : IPixel, IPackedVector { /// /// Gets or sets the alpha component. @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b) { this.R = r; @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(byte r, byte g, byte b, byte a) { this.R = r; @@ -89,12 +89,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(float r, float g, float b, float a = 1) - : this() - { - this.Pack(r, g, b, a); - } + : this() => this.Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -102,12 +99,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -115,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(Vector4 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -128,22 +119,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Argb32(uint packed) - : this() - { - this.Argb = packed; - } + : this() => this.Argb = packed; /// /// Gets or sets the packed representation of the Argb32 struct. /// public uint Argb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -157,20 +145,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Argb32 left, Argb32 right) - { - return left.Argb == right.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -180,63 +161,45 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Argb32 left, Argb32 right) - { - return left.Argb != right.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.Pack(ref vector); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) { this.R = source.R; this.G = source.G; this.B = source.B; - this.A = source.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackedValue = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -244,44 +207,50 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) { - dest = this; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) { dest.R = this.R; dest.G = this.G; @@ -289,91 +258,43 @@ namespace SixLabors.ImageSharp.PixelFormats dest.A = this.A; } - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Argb32 argb32 && this.Equals(argb32); - } + public override bool Equals(object obj) => obj is Argb32 argb32 && this.Equals(argb32); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Argb32 other) - { - return this.Argb == other.Argb; - } + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Argb32 other) => this.Argb == other.Argb; /// /// Gets a string representation of the packed vector. /// /// A string representation of the packed vector. - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Argb.GetHashCode(); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } - /// /// Packs the four floats into a color. /// @@ -381,7 +302,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -392,7 +313,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { var value = new Vector4(vector, 1); @@ -403,7 +324,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs new file mode 100644 index 0000000000..9207f046c4 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -0,0 +1,198 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255. + /// The color components are stored in blue, green, red order (least significant to most significant byte). + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + [StructLayout(LayoutKind.Explicit)] + public partial struct Bgr24 : IPixel + { + /// + /// The blue component. + /// + [FieldOffset(0)] + public byte B; + + /// + /// The green component. + /// + [FieldOffset(1)] + public byte G; + + /// + /// The red component. + /// + [FieldOffset(2)] + public byte R; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(InliningOptions.ShortMethod)] + public Bgr24(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + Rgba32 rgba = default; + rgba.FromVector4(vector); + this.FromRgba32(rgba); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this = source; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) + { + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this = source.Bgr; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) + { + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) + { + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); + + /// + public override bool Equals(object obj) => obj is Bgr24 other && this.Equals(other); + + /// + public override string ToString() => $"Bgra({this.B}, {this.G}, {this.R})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() + { + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs new file mode 100644 index 0000000000..a2e4dc8802 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -0,0 +1,171 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x and z components use 5 bits, and the y component uses 6 bits. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Bgr565 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The x-component + /// The y-component + /// The z-component + public Bgr565(float x, float y, float z) + : this(new Vector3(x, y, z)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The vector containing the components for the packed value. + /// + public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector); + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + var vector3 = new Vector3(vector.X, vector.Y, vector.Z); + this.PackedValue = Pack(ref vector3); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromVector4(source.ToVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromVector4(source.ToVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector3 ToVector3() + { + return new Vector3( + ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), + ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), + (this.PackedValue & 0x1F) * (1F / 31F)); + } + + /// + public override bool Equals(object obj) => obj is Bgr565 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() + { + var vector = this.ToVector3(); + return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector3 vector) + { + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + + return (ushort)((((int)Math.Round(vector.X * 31F) & 0x1F) << 11) + | (((int)Math.Round(vector.Y * 63F) & 0x3F) << 5) + | ((int)Math.Round(vector.Z * 31F) & 0x1F)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs similarity index 51% rename from src/ImageSharp/PixelFormats/Bgra32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index ff52600081..1d156222ff 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// [StructLayout(LayoutKind.Sequential)] - public struct Bgra32 : IPixel, IPackedVector + public partial struct Bgra32 : IPixel, IPackedVector { /// /// Gets or sets the blue component. @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b) { this.R = r; @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Bgra32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint Bgra { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -98,62 +98,95 @@ namespace SixLabors.ImageSharp.PixelFormats set => this.Bgra = value; } + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); + /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); + public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - public bool Equals(Bgra32 other) - { - return this.Bgra == other.Bgra; - } + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); /// - public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); /// - public override int GetHashCode() => this.Bgra.GetHashCode(); + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.Pack(ref vector); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) { - this.PackFromVector4(vector); + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) { - return this.ToVector4(); + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this = source; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) { - this.Pack(ref vector); + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) { this.R = source.R; this.G = source.G; @@ -162,33 +195,17 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) { this.R = source.R; this.G = source.G; this.B = source.B; - this.A = source.A; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackedValue = source.PackedValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + /// + [MethodImpl(InliningOptions.ShortMethod)] public void ToRgba32(ref Rgba32 dest) { dest.R = this.R; @@ -198,77 +215,42 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As(ref this); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) => dest = this; - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); - - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = byte.MaxValue; + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); - } + public bool Equals(Bgra32 other) => this.Bgra.Equals(other.Bgra); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + public override int GetHashCode() => this.Bgra.GetHashCode(); + + /// + public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})"; /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; @@ -280,11 +262,5 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = (byte)vector.Z; this.A = (byte)vector.W; } - - /// - public override string ToString() - { - return $"({this.B},{this.G},{this.R},{this.A})"; - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs new file mode 100644 index 0000000000..110b51822d --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -0,0 +1,160 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing unsigned normalized values, ranging from 0 to 1, using 4 bits each for x, y, z, and w. + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Bgra4444 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + public Bgra4444(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the components for the packed vector. + public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + const float Max = 1 / 15F; + + return new Vector4( + (this.PackedValue >> 8) & 0x0F, + (this.PackedValue >> 4) & 0x0F, + this.PackedValue & 0x0F, + (this.PackedValue >> 12) & 0x0F) * Max; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) + | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) + | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) + | ((int)Math.Round(vector.Z * 15F) & 0x0F)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs new file mode 100644 index 0000000000..dcfb25a64b --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -0,0 +1,162 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing unsigned normalized values ranging from 0 to 1. + /// The x , y and z components use 5 bits, and the w component uses 1 bit. + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Bgra5551 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + public Bgra5551(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// + /// The vector containing the components for the packed vector. + /// + public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + return new Vector4( + ((this.PackedValue >> 10) & 0x1F) / 31F, + ((this.PackedValue >> 5) & 0x1F) / 31F, + ((this.PackedValue >> 0) & 0x1F) / 31F, + (this.PackedValue >> 15) & 0x01); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(ref Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + return (ushort)( + (((int)Math.Round(vector.X * 31F) & 0x1F) << 10) + | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) + | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0) + | (((int)Math.Round(vector.W) & 0x1) << 15)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs new file mode 100644 index 0000000000..43a03dc5d1 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -0,0 +1,172 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing four 8-bit unsigned integer values, ranging from 0 to 255. + /// + /// Ranges from [0, 0, 0, 0] to [255, 255, 255, 255] in vector form. + /// + /// + public struct Byte4 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// + /// A vector containing the initial values for the components of the Byte4 structure. + /// + public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + public Byte4(float x, float y, float z, float w) + { + var vector = new Vector4(x, y, z, w); + this.PackedValue = Pack(ref vector); + } + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector * 255F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4() / 255F; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + return new Vector4( + this.PackedValue & 0xFF, + (this.PackedValue >> 0x8) & 0xFF, + (this.PackedValue >> 0x10) & 0xFF, + (this.PackedValue >> 0x18) & 0xFF); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } + + /// + /// Packs a vector into a uint. + /// + /// The vector containing the values to pack. + /// The containing the packed values. + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) + { + const float Max = 255F; + + // Clamp the value between min and max values + vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); + + uint byte4 = (uint)Math.Round(vector.X) & 0xFF; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18; + + return byte4 | byte3 | byte2 | byte1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..2ec965dfb0 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs @@ -0,0 +1,240 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); + } + } + + /// + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); + } + } + + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromArgb32(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromArgb32(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromArgb32(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromArgb32(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromArgb32(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromArgb32(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..0a58504e15 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Argb32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Argb32"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..711a9d1c16 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs @@ -0,0 +1,214 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgr24(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..84b89aa32c --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgr24 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Bgr24"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..b669dd5348 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs @@ -0,0 +1,240 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); + } + } + + /// + internal override void FromRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp); + } + } + + /// + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra32(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra32(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra32(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra32(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra32(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromBgra32(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..004ceff51e --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Bgra32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Bgra32"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs new file mode 100644 index 0000000000..288c5d92e4 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs @@ -0,0 +1,190 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray16(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt new file mode 100644 index 0000000000..3cbc01e88c --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray16 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Gray16"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs new file mode 100644 index 0000000000..f7e94788e3 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs @@ -0,0 +1,190 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromGray8(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt new file mode 100644 index 0000000000..d35843ccda --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Gray8 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Gray8"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs new file mode 100644 index 0000000000..dbf3102c4a --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs @@ -0,0 +1,214 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb24(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt new file mode 100644 index 0000000000..d96c3684b5 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb24 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Rgb24"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs new file mode 100644 index 0000000000..30c9972bbf --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs @@ -0,0 +1,190 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgb48(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt new file mode 100644 index 0000000000..7bff336386 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgb48 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Rgb48"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs new file mode 100644 index 0000000000..da2ce3770b --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs @@ -0,0 +1,216 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal partial class PixelOperations : PixelOperations + { + /// + internal override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp); + } + } + + /// + internal override void FromArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp); + } + } + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp); + } + } + + /// + internal override void FromBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba32(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba32(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba32(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba32(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba32(sp); + } + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba32(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt new file mode 100644 index 0000000000..6b9e2d1248 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba32 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal partial class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Rgba32"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs new file mode 100644 index 0000000000..42c40ad5d7 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs @@ -0,0 +1,190 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + + + /// + internal override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + + /// + internal override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); + + dp.FromRgba64(sp); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt new file mode 100644 index 0000000000..d15945f947 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.tt @@ -0,0 +1,19 @@ +<#@include file="_Common.ttinclude" #> +<#@ output extension=".cs" #> + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba64 + { + /// + /// Provides optimized overrides for bulk operations. + /// + internal class PixelOperations : PixelOperations + { + <# GenerateAllDefaultConversionMethods("Rgba64"); #> + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude new file mode 100644 index 0000000000..f0675cb5b3 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude @@ -0,0 +1,167 @@ +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// + +using SixLabors.ImageSharp.PixelFormats.Utils; +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +<#+ + static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" }; + + static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" }; + + // Types with Rgba32-combatible to/from Vector4 conversion + static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" }; + + void GenerateDefaultSelfConversionMethods(string pixelType) + { +#> +/// + internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + source.CopyTo(destPixels); + } + + /// + internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + sourcePixels.CopyTo(destPixels); + } + +<#+ + } + + void GenerateDefaultConvertToMethod(string fromPixelType, string toPixelType) + { +#> + + /// + internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); + ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); + + dp.From<#=fromPixelType#>(sp); + } + } +<#+ + } + + void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType) + { +#> + /// + internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=otherPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sp); + } + } + + /// + internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels)); + ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels)); + + for (int i = 0; i < sourcePixels.Length; i++) + { + uint sp = Unsafe.Add(ref sourceRef, i); + Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp); + } + } +<#+ + } + + void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType) + { +#> + /// + internal override void FromVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false); + } + + /// + internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false); + } + + /// + internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan sourceVectors, Span<<#=pixelType#>> destPixels) + { + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true); + } + + /// + internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span destVectors) + { + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true); + } + +<#+ + } + + void GenerateAllDefaultConversionMethods(string pixelType) + { + GenerateDefaultSelfConversionMethods(pixelType); + + if (Rgba32CompatibleTypes.Contains(pixelType)) + { + GenerateRgba32CompatibleVector4ConversionMethods(pixelType); + } + + var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ? + Optimized32BitTypes.Where(p => p != pixelType) : + Enumerable.Empty(); + + foreach (string destPixelType in matching32BitTypes) + { + GenerateOptimized32BitConversionMethods(pixelType, destPixelType); + } + + var otherCommonNon32Types = CommonPixelTypes + .Where(p => p != pixelType) + .Except(matching32BitTypes); + + foreach (string destPixelType in otherCommonNon32Types) + { + GenerateDefaultConvertToMethod(pixelType, destPixelType); + } + } +#> \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs new file mode 100644 index 0000000000..2e98a28ada --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray16.cs @@ -0,0 +1,180 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 16 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public partial struct Gray16 : IPixel, IPackedVector + { + private const float Max = ushort.MaxValue; + private const float Average = 1 / 3F; + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component + public Gray16(ushort luminance) => this.PackedValue = luminance; + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray16 left, Gray16 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average; + this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + float scaled = this.PackedValue / Max; + return new Vector4(scaled, scaled, scaled, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.PackedValue = source.PackedValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) + { + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + ImageMaths.UpscaleFrom8BitTo16Bit(source.R), + ImageMaths.UpscaleFrom8BitTo16Bit(source.G), + ImageMaths.UpscaleFrom8BitTo16Bit(source.B)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue); + dest.R = rgb; + dest.G = rgb; + dest.B = rgb; + dest.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B); + + /// + public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray16 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => $"Gray16({this.PackedValue})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.PackedValue = ImageMaths.Get16BitBT709Luminance( + (ushort)MathF.Round(vector.X), + (ushort)MathF.Round(vector.Y), + (ushort)MathF.Round(vector.Z)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs new file mode 100644 index 0000000000..512bee39de --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs @@ -0,0 +1,165 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 8 bit normalized gray values. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + public partial struct Gray8 : IPixel, IPackedVector + { + private static readonly Vector4 MaxBytes = new Vector4(255F); + private static readonly Vector4 Half = new Vector4(0.5F); + private const float Average = 1 / 3F; + + private static readonly Vector4 Min = new Vector4(0, 0, 0, 1f); + private static readonly Vector4 Max = Vector4.One; + + private static readonly Vector4 Accumulator = new Vector4(255f * Average, 255f * Average, 255f * Average, 0.5f); + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component. + public Gray8(byte luminance) => this.PackedValue = luminance; + + /// + public byte PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Gray8 left, Gray8 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + vector = Vector4.Max(Min, vector); + vector = Vector4.Min(Max, vector); + + float roundedSum = Vector4.Dot(vector, Accumulator); + + this.PackedValue = (byte)roundedSum; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + float rgb = this.PackedValue / 255F; + return new Vector4(rgb, rgb, rgb, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.PackedValue = source.PackedValue; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.PackedValue; + dest.G = this.PackedValue; + dest.B = this.PackedValue; + dest.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) + => this.PackedValue = ImageMaths.Get8BitBT709Luminance( + ImageMaths.DownScaleFrom16BitTo8Bit(source.R), + ImageMaths.DownScaleFrom16BitTo8Bit(source.G), + ImageMaths.DownScaleFrom16BitTo8Bit(source.B)); + + /// + public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => $"Gray8({this.PackedValue})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + internal void ConvertFromRgbaScaledVector4(Vector4 vector) + { + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs new file mode 100644 index 0000000000..8323cf3e8a --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -0,0 +1,143 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing a single 16 bit floating point value. + /// + /// Ranges from [-1, 0, 0, 1] to [1, 0, 0, 1] in vector form. + /// + /// + public struct HalfSingle : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The single component. + public HalfSingle(float single) => this.PackedValue = HalfTypeHelper.Pack(single); + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + float scaled = vector.X; + scaled *= 2F; + scaled--; + this.PackedValue = HalfTypeHelper.Pack(scaled); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + float single = this.ToSingle() + 1F; + single /= 2F; + return new Vector4(single, 0, 0, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue); + + /// + public override bool Equals(object obj) => obj is HalfSingle other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})"); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs new file mode 100644 index 0000000000..cb915459bc --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -0,0 +1,172 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing two 16-bit floating-point values. + /// + /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. + /// + /// + public struct HalfVector2 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + public HalfVector2(float x, float y) => this.PackedValue = Pack(x, y); + + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components. + public HalfVector2(Vector2 vector) => this.PackedValue = Pack(vector.X, vector.Y); + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; + scaled -= Vector2.One; + this.PackedValue = Pack(scaled.X, scaled.Y); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector2(); + scaled += Vector2.One; + scaled /= 2F; + return new Vector4(scaled, 0F, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + var vector = this.ToVector2(); + return new Vector4(vector.X, vector.Y, 0F, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() + { + Vector2 vector; + vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue); + vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)); + return vector; + } + + /// + public override bool Equals(object obj) => obj is HalfVector2 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() + { + var vector = this.ToVector2(); + return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(float x, float y) + { + uint num2 = HalfTypeHelper.Pack(x); + uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); + return num2 | num; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs new file mode 100644 index 0000000000..9f60ca8c77 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -0,0 +1,174 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing four 16-bit floating-point values. + /// + /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct HalfVector4 : IPixel, IPackedVector + { + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + /// The z-component. + /// The w-component. + public HalfVector4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components + public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public ulong PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + vector *= 2F; + vector -= Vector4.One; + this.FromVector4(vector); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector4(); + scaled += Vector4.One; + scaled /= 2F; + return scaled; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + return new Vector4( + HalfTypeHelper.Unpack((ushort)this.PackedValue), + HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)), + HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x20)), + HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30))); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + /// Packs a into a . + /// + /// The vector containing the values to pack. + /// The containing the packed values. + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) + { + ulong num4 = HalfTypeHelper.Pack(vector.X); + ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10; + ulong num2 = (ulong)HalfTypeHelper.Pack(vector.Z) << 0x20; + ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; + return num4 | num3 | num2 | num1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs new file mode 100644 index 0000000000..d39cfd402e --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -0,0 +1,181 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed packed pixel type containing two 8-bit signed normalized values, ranging from −1 to 1. + /// + /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. + /// + /// + public struct NormalizedByte2 : IPixel, IPackedVector + { + private static readonly Vector2 Half = new Vector2(127); + private static readonly Vector2 MinusOne = new Vector2(-1F); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + public NormalizedByte2(float x, float y) + : this(new Vector2(x, y)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector); + + /// + public ushort PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; + scaled -= Vector2.One; + this.PackedValue = Pack(scaled); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector2(); + scaled += Vector2.One; + scaled /= 2F; + return new Vector4(scaled, 0F, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() + { + return new Vector2( + (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F); + } + + /// + public override bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector2(); + return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static ushort Pack(Vector2 vector) + { + vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half; + + int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0; + int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8; + + return (ushort)(byte2 | byte1); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs new file mode 100644 index 0000000000..82698d5085 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -0,0 +1,175 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing four 8-bit signed normalized values, ranging from −1 to 1. + /// + /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct NormalizedByte4 : IPixel, IPackedVector + { + private static readonly Vector4 Half = new Vector4(127); + private static readonly Vector4 MinusOne = new Vector4(-1F); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + /// The z-component. + /// The w-component. + public NormalizedByte4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + vector *= 2F; + vector -= Vector4.One; + this.FromVector4(vector); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector4(); + scaled += Vector4.One; + scaled /= 2F; + return scaled; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + return new Vector4( + (sbyte)((this.PackedValue >> 0) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 8) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 16) & 0xFF) / 127F, + (sbyte)((this.PackedValue >> 24) & 0xFF) / 127F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) + { + vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; + + uint byte4 = ((uint)Math.Round(vector.X) & 0xFF) << 0; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 16; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 24; + + return byte4 | byte3 | byte2 | byte1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs new file mode 100644 index 0000000000..b9cab1e7d3 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -0,0 +1,185 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing two 16-bit signed normalized values, ranging from −1 to 1. + /// + /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. + /// + /// + public struct NormalizedShort2 : IPixel, IPackedVector + { + private static readonly Vector2 Max = new Vector2(0x7FFF); + private static readonly Vector2 Min = Vector2.Negate(Max); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + public NormalizedShort2(float x, float y) + : this(new Vector2(x, y)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector); + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; + scaled -= Vector2.One; + this.PackedValue = Pack(scaled); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector2(); + scaled += Vector2.One; + scaled /= 2F; + return new Vector4(scaled, 0F, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() + { + const float MaxVal = 0x7FFF; + + return new Vector2( + (short)(this.PackedValue & 0xFFFF) / MaxVal, + (short)(this.PackedValue >> 0x10) / MaxVal); + } + + /// + public override bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector2(); + return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) + { + vector *= Max; + vector = Vector2.Clamp(vector, Min, Max); + + // Round rather than truncate. + uint word2 = (uint)((int)MathF.Round(vector.X) & 0xFFFF); + uint word1 = (uint)(((int)MathF.Round(vector.Y) & 0xFFFF) << 0x10); + + return word2 | word1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs new file mode 100644 index 0000000000..3bc74e6c67 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -0,0 +1,179 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing four 16-bit signed normalized values, ranging from −1 to 1. + /// + /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. + /// + /// + public struct NormalizedShort4 : IPixel, IPackedVector + { + private static readonly Vector4 Max = new Vector4(0x7FFF); + private static readonly Vector4 Min = Vector4.Negate(Max); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + /// The z-component. + /// The w-component. + public NormalizedShort4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public ulong PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + vector *= 2F; + vector -= Vector4.One; + this.FromVector4(vector); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector4(); + scaled += Vector4.One; + scaled /= 2F; + return scaled; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + const float MaxVal = 0x7FFF; + + return new Vector4( + (short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxVal, + (short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxVal, + (short)((this.PackedValue >> 0x20) & 0xFFFF) / MaxVal, + (short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxVal); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) + { + vector *= Max; + vector = Vector4.Clamp(vector, Min, Max); + + // Round rather than truncate. + ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30; + + return word4 | word3 | word2 | word1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs new file mode 100644 index 0000000000..6dc623518d --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -0,0 +1,160 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing two 16-bit unsigned normalized values ranging from 0 to 1. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 0, 1] in vector form. + /// + /// + public struct Rg32 : IPixel, IPackedVector + { + private static readonly Vector2 Max = new Vector2(ushort.MaxValue); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component + /// The y-component + public Rg32(float x, float y) + : this(new Vector2(x, y)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public Rg32(Vector2 vector) => this.PackedValue = Pack(vector); + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max; + + /// + public override bool Equals(object obj) => obj is Rg32 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() + { + var vector = this.ToVector2(); + return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) + { + vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max; + return (uint)(((int)Math.Round(vector.X) & 0xFFFF) | (((int)Math.Round(vector.Y) & 0xFFFF) << 16)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs new file mode 100644 index 0000000000..293fe0acbf --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -0,0 +1,228 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255. + /// The color components are stored in red, green, blue order (least significant to most significant byte). + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + [StructLayout(LayoutKind.Explicit)] + public partial struct Rgb24 : IPixel + { + /// + /// The red component. + /// + [FieldOffset(0)] + public byte R; + + /// + /// The green component. + /// + [FieldOffset(1)] + public byte G; + + /// + /// The blue component. + /// + [FieldOffset(2)] + public byte B; + + private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue); + private static readonly Vector4 Half = new Vector4(0.5F); + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(InliningOptions.ShortMethod)] + public Rgb24(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + } + + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// The instance of to convert. + /// An instance of . + [MethodImpl(InliningOptions.ShortMethod)] + public static implicit operator Rgb24(ColorSpaces.Rgb color) + { + var vector = new Vector4(color.ToVector3(), 1F); + + Rgb24 rgb = default; + rgb.FromScaledVector4(vector); + return rgb; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.R = source.R; + this.G = source.G; + this.B = source.B; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) + { + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this = source; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this = source.Rgb; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) + { + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) + { + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + } + + /// + public override bool Equals(object obj) => obj is Rgb24 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() + { + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); + } + + /// + public override string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})"; + + /// + /// Packs a into a color. + /// + /// The vector containing the values to pack. + [MethodImpl(InliningOptions.ShortMethod)] + private void Pack(ref Vector4 vector) + { + vector *= MaxBytes; + vector += Half; + vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); + + this.R = (byte)vector.X; + this.G = (byte)vector.Y; + this.B = (byte)vector.Z; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs new file mode 100644 index 0000000000..81497e5f18 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -0,0 +1,199 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing three 16-bit unsigned normalized values ranging from 0 to 635535. + /// + /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public partial struct Rgb48 : IPixel + { + private const float Max = ushort.MaxValue; + + /// + /// Gets or sets the red component. + /// + public ushort R; + + /// + /// Gets or sets the green component. + /// + public ushort G; + + /// + /// Gets or sets the blue component. + /// + public ushort B; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + public Rgb48(ushort r, ushort g, ushort b) + : this() + { + this.R = r; + this.G = g; + this.B = b; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.R = (ushort)MathF.Round(vector.X); + this.G = (ushort)MathF.Round(vector.Y); + this.B = (ushort)MathF.Round(vector.Z); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this = source.Rgb; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) + { + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + dest.G = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + dest.B = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + dest.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this = source; + + /// + public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); + + /// + public override string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() + { + return HashHelpers.Combine( + this.R.GetHashCode(), + HashHelpers.Combine(this.G.GetHashCode(), this.B.GetHashCode())); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs new file mode 100644 index 0000000000..895added1b --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -0,0 +1,163 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed vector type containing unsigned normalized values ranging from 0 to 1. + /// The x, y and z components use 10 bits, and the w component uses 2 bits. + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + public struct Rgba1010102 : IPixel, IPackedVector + { + private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component + /// The y-component + /// The z-component + /// The w-component + public Rgba1010102(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + return new Vector4( + (this.PackedValue >> 0) & 0x03FF, + (this.PackedValue >> 10) & 0x03FF, + (this.PackedValue >> 20) & 0x03FF, + (this.PackedValue >> 30) & 0x03) / Multiplier; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(ref Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; + + return (uint)( + (((int)Math.Round(vector.X) & 0x03FF) << 0) + | (((int)Math.Round(vector.Y) & 0x03FF) << 10) + | (((int)Math.Round(vector.Z) & 0x03FF) << 20) + | (((int)Math.Round(vector.W) & 0x03) << 30)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.Definitions.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs similarity index 100% rename from src/ImageSharp/PixelFormats/Rgba32.Definitions.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.Definitions.cs diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs new file mode 100644 index 0000000000..004b25cd33 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct Rgba32 + { + /// + /// implementation optimized for . + /// + internal partial class PixelOperations : PixelOperations + { + /// + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + destVectors = destVectors.Slice(0, sourcePixels.Length); + + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(sourcePixels), + MemoryMarshal.Cast(destVectors)); + } + + /// + internal override void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + destPixels = destPixels.Slice(0, sourceVectors.Length); + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(destPixels)); + } + + /// + internal override void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) + { + this.ToVector4(configuration, sourceColors, destinationVectors); + } + + /// + internal override void FromScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) + { + this.FromVector4(configuration, sourceVectors, destinationColors); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs similarity index 61% rename from src/ImageSharp/PixelFormats/Rgba32.cs rename to src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 7349639fdc..5a16704ef0 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -41,34 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// public byte A; - /// - /// The shift count for the red component - /// - private const int RedShift = 0; - - /// - /// The shift count for the green component - /// - private const int GreenShift = 8; - - /// - /// The shift count for the blue component - /// - private const int BlueShift = 16; - - /// - /// The shift count for the alpha component - /// - private const int AlphaShift = 24; - - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// + private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue); private static readonly Vector4 Half = new Vector4(0.5F); /// @@ -77,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The red component. /// The green component. /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b) { this.R = r; @@ -93,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; @@ -109,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(float r, float g, float b, float a = 1) : this() => this.Pack(r, g, b, a); @@ -119,7 +92,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector3 vector) : this() => this.Pack(ref vector); @@ -129,7 +102,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The vector containing the components for the packed vector. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(Vector4 vector) : this() => this = PackNew(ref vector); @@ -139,7 +112,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The packed value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgba32(uint packed) : this() => this.Rgba = packed; @@ -148,10 +121,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint Rgba { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -160,10 +133,12 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Rgb24 Rgb { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + // If this is changed to ShortMethod then several jpeg encoding tests fail + // on 32 bit Net 4.6.2 and NET 4.7.1 + [MethodImpl(InliningOptions.ColdPath)] get => Unsafe.As(ref this); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; } @@ -172,10 +147,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public Bgr24 Bgr { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => new Bgr24(this.R, this.G, this.B); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set { this.R = value.R; @@ -187,10 +162,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// public uint PackedValue { - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] get => this.Rgba; - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] set => this.Rgba = value; } @@ -200,12 +175,13 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The instance of to convert. /// An instance of . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator Rgba32(ColorSpaces.Rgb color) { - var vector = new Vector4(color.ToVector3(), 1); + var vector = new Vector4(color.ToVector3(), 1F); + Rgba32 rgba = default; - rgba.PackFromScaledVector4(vector); + rgba.FromScaledVector4(vector); return rgba; } @@ -217,8 +193,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba32 left, Rgba32 right) => left.Rgba == right.Rgba; + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right); /// /// Compares two objects for equality. @@ -228,8 +204,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba32 left, Rgba32 right) => left.Rgba != right.Rgba; + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right); /// /// Creates a new instance of the struct. @@ -247,12 +223,24 @@ namespace SixLabors.ImageSharp.PixelFormats public PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) => this = source; + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) { this.R = source.R; this.G = source.G; @@ -261,8 +249,16 @@ namespace SixLabors.ImageSharp.PixelFormats } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.Bgr = source; + this.A = byte.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) { this.R = source.R; this.G = source.G; @@ -270,148 +266,96 @@ namespace SixLabors.ImageSharp.PixelFormats this.A = source.A; } - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); - return hexOrder.ToString("X8"); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = Unsafe.As(ref this); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) => dest = this; - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; + byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = byte.MaxValue; } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.Rgb = source; + this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A); - - /// - /// Gets the value of this struct as . - /// Useful for changing the component order. - /// - /// A value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A); + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this = source; - /// - /// Converts the pixel to format. - /// - /// The RGBA value - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() => this; + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest = this; + } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); this.A = byte.MaxValue; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) { - // Taken from libpng pngtran.c line: 2419 - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - this.A = (byte)(((source.A * 255) + 32895) >> 16); + this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R); + this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G); + this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B); + this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() + { + uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24); + return hexOrder.ToString("X8"); + } /// public override bool Equals(object obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba32 other) => this.Rgba == other.Rgba; + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba); /// - public override string ToString() => $"({this.R},{this.G},{this.B},{this.A})"; + public override string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => this.Rgba.GetHashCode(); - /// - /// Gets the representation without normalizing to [0, 1] - /// - /// A of values in [0, 255] - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); - /// /// Packs a into a color returning a new instance as a result. /// /// The vector containing the values to pack. /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static Rgba32 PackNew(ref Vector4 vector) { vector *= MaxBytes; @@ -428,7 +372,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The y-component /// The z-component /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(float x, float y, float z, float w) { var value = new Vector4(x, y, z, w); @@ -439,10 +383,10 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector3 vector) { - var value = new Vector4(vector, 1); + var value = new Vector4(vector, 1F); this.Pack(ref value); } @@ -450,7 +394,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private void Pack(ref Vector4 vector) { vector *= MaxBytes; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs new file mode 100644 index 0000000000..5ae5492e23 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -0,0 +1,234 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing four 16-bit unsigned normalized values ranging from 0 to 635535. + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public partial struct Rgba64 : IPixel, IPackedVector + { + private const float Max = ushort.MaxValue; + + /// + /// Gets or sets the red component. + /// + public ushort R; + + /// + /// Gets or sets the green component. + /// + public ushort G; + + /// + /// Gets or sets the blue component. + /// + public ushort B; + + /// + /// Gets or sets the alpha component. + /// + public ushort A; + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + public Rgba64(ushort r, ushort g, ushort b, ushort a) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + + /// + /// Gets or sets the RGB components of this struct as + /// + public Rgb48 Rgb + { + [MethodImpl(InliningOptions.ShortMethod)] + get => Unsafe.As(ref this); + + [MethodImpl(InliningOptions.ShortMethod)] + set => Unsafe.As(ref this) = value; + } + + /// + public ulong PackedValue + { + [MethodImpl(InliningOptions.ShortMethod)] + get => Unsafe.As(ref this); + + [MethodImpl(InliningOptions.ShortMethod)] + set => Unsafe.As(ref this) = value; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue; + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; + this.R = (ushort)MathF.Round(vector.X); + this.G = (ushort)MathF.Round(vector.Y); + this.B = (ushort)MathF.Round(vector.Z); + this.A = (ushort)MathF.Round(vector.W); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) + { + ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue); + this.R = rgb; + this.G = rgb; + this.B = rgb; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) + { + this.R = source.PackedValue; + this.G = source.PackedValue; + this.B = source.PackedValue; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) + { + this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R); + this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G); + this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B); + this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.R = ImageMaths.DownScaleFrom16BitTo8Bit(this.R); + dest.G = ImageMaths.DownScaleFrom16BitTo8Bit(this.G); + dest.B = ImageMaths.DownScaleFrom16BitTo8Bit(this.B); + dest.A = ImageMaths.DownScaleFrom16BitTo8Bit(this.A); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) + { + this.Rgb = source; + this.A = ushort.MaxValue; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this = source; + + /// + public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue); + + /// + public override string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})"; + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs new file mode 100644 index 0000000000..bffaf57ddd --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Provides optimized overrides for bulk operations. + /// + public partial struct RgbaVector + { + /// + /// implementation optimized for . + /// + internal class PixelOperations : PixelOperations + { + /// + internal override void FromScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) + { + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); + + MemoryMarshal.Cast(sourceVectors).CopyTo(destinationColors); + } + + /// + internal override void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) + => this.ToVector4(configuration, sourceColors, destinationVectors); + + /// + internal override void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + MemoryMarshal.Cast(sourcePixels).CopyTo(destVectors); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs new file mode 100644 index 0000000000..ff4c69d701 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -0,0 +1,207 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Unpacked pixel type containing four 16-bit floating-point values typically ranging from 0 to 1. + /// The color components are stored in red, green, blue, and alpha order. + /// + /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. + /// + /// + /// + /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, + /// as it avoids the need to create new values for modification operations. + /// + [StructLayout(LayoutKind.Sequential)] + public partial struct RgbaVector : IPixel + { + /// + /// Gets or sets the red component. + /// + public float R; + + /// + /// Gets or sets the green component. + /// + public float G; + + /// + /// Gets or sets the blue component. + /// + public float B; + + /// + /// Gets or sets the alpha component. + /// + public float A; + + private const float MaxBytes = byte.MaxValue; + private static readonly Vector4 Max = new Vector4(MaxBytes); + private static readonly Vector4 Half = new Vector4(0.5F); + + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [MethodImpl(InliningOptions.ShortMethod)] + public RgbaVector(float r, float g, float b, float a = 1) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); + + /// + /// Creates a new instance of the struct. + /// + /// + /// The hexadecimal representation of the combined color components arranged + /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. + /// + /// + /// The . + /// + public static RgbaVector FromHex(string hex) => ColorBuilder.FromHex(hex); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; + this.A = vector.W; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Converts the value of this instance to a hexadecimal string. + /// + /// A hexadecimal string representation of the value. + public string ToHex() + { + // Hex is RRGGBBAA + Vector4 vector = this.ToVector4() * Max; + vector += Half; + uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); + return hexOrder.ToString("X8"); + } + + /// + public override bool Equals(object obj) => obj is RgbaVector other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(RgbaVector other) => + this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B) + && this.A.Equals(other.A); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"); + } + + /// + public override int GetHashCode() + { + int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.A.GetHashCode()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs new file mode 100644 index 0000000000..96fe15ed61 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -0,0 +1,181 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing two 16-bit signed integer values. + /// + /// Ranges from [-32767, -32767, 0, 1] to [32767, 32767, 0, 1] in vector form. + /// + /// + public struct Short2 : IPixel, IPackedVector + { + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; + + // Two's complement + private const float MinNeg = ~(int)MaxPos; + + private static readonly Vector2 Max = new Vector2(MaxPos); + private static readonly Vector2 Min = new Vector2(MinNeg); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + public Short2(float x, float y) + : this(new Vector2(x, y)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public Short2(Vector2 vector) => this.PackedValue = Pack(vector); + + /// + public uint PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short2 left, Short2 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; + scaled -= new Vector2(32767F); + this.PackedValue = Pack(scaled); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector2(); + scaled += new Vector2(32767F); + scaled /= 65534F; + return new Vector4(scaled, 0F, 1F); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + var vector2 = new Vector2(vector.X, vector.Y); + this.PackedValue = Pack(vector2); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() => new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + /// Expands the packed representation into a . + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public Vector2 ToVector2() => new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); + + /// + public override bool Equals(object obj) => obj is Short2 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector2(); + return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})"); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static uint Pack(Vector2 vector) + { + vector = Vector2.Clamp(vector, Min, Max); + uint word2 = (uint)Math.Round(vector.X) & 0xFFFF; + uint word1 = ((uint)Math.Round(vector.Y) & 0xFFFF) << 0x10; + + return word2 | word1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs new file mode 100644 index 0000000000..d224f8eb4e --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -0,0 +1,185 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats +{ + /// + /// Packed pixel type containing four 16-bit signed integer values. + /// + /// Ranges from [-37267, -37267, -37267, -37267] to [37267, 37267, 37267, 37267] in vector form. + /// + /// + public struct Short4 : IPixel, IPackedVector + { + // Largest two byte positive number 0xFFFF >> 1; + private const float MaxPos = 0x7FFF; + + // Two's complement + private const float MinNeg = ~(int)MaxPos; + + private static readonly Vector4 Max = new Vector4(MaxPos); + private static readonly Vector4 Min = new Vector4(MinNeg); + + /// + /// Initializes a new instance of the struct. + /// + /// The x-component. + /// The y-component. + /// The z-component. + /// The w-component. + public Short4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) + { + } + + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components. + public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + public ulong PackedValue { get; set; } + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(Short4 left, Short4 right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); + + /// + public PixelOperations CreatePixelOperations() => new PixelOperations(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) + { + vector *= 65534F; + vector -= new Vector4(32767F); + this.FromVector4(vector); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToScaledVector4() + { + var scaled = this.ToVector4(); + scaled += new Vector4(32767F); + scaled /= 65534F; + return scaled; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public Vector4 ToVector4() + { + return new Vector4( + (short)(this.PackedValue & 0xFFFF), + (short)((this.PackedValue >> 0x10) & 0xFFFF), + (short)((this.PackedValue >> 0x20) & 0xFFFF), + (short)((this.PackedValue >> 0x30) & 0xFFFF)); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray8(Gray8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromGray16(Gray16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) + { + dest.FromScaledVector4(this.ToScaledVector4()); + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override bool Equals(object obj) => obj is Short4 other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(Short4 other) => this.PackedValue.Equals(other); + + /// + /// Gets the hash code for the current instance. + /// + /// Hash code for the instance. + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => this.PackedValue.GetHashCode(); + + /// + public override string ToString() + { + var vector = this.ToVector4(); + return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); + } + + [MethodImpl(InliningOptions.ShortMethod)] + private static ulong Pack(ref Vector4 vector) + { + vector = Vector4.Clamp(vector, Min, Max); + + // Clamp the value between min and max values + ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)Math.Round(vector.Y) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)Math.Round(vector.Z) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)Math.Round(vector.W) & 0xFFFF) << 0x30; + + return word4 | word3 | word2 | word1; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs new file mode 100644 index 0000000000..207a8767d6 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -0,0 +1,661 @@ +// 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.PixelFormats +{ + public partial class PixelOperations + { + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromArgb32(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromBgr24(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromBgra32(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromGray8(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromGray8(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromGray8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromGray8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToGray8(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray8Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToGray8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromGray16(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromGray16(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromGray16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromGray16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToGray16(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToGray16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToGray16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromRgb24(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromRgba32(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromRgb48(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromRgba64(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destPixels); + } + + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt new file mode 100644 index 0000000000..8579423b34 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -0,0 +1,140 @@ +<# +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +#> +<#@ template debug="false" hostspecific="false" language="C#" #> +<#@ assembly name="System.Core" #> +<#@ import namespace="System.Linq" #> +<#@ import namespace="System.Text" #> +<#@ import namespace="System.Collections.Generic" #> +<#@ import namespace="System.Runtime.InteropServices" #> +<#@ output extension=".cs" #> +<# + + void GenerateFromMethods(string pixelType) + { + #> + + /// + /// Converts all pixels in 'source` span of into a span of -s. + /// + /// A to configure internal operations + /// The source of data. + /// The to the destination pixels. + internal virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destPixels) + { + Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels)); + + ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); + ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < source.Length; i++) + { + ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.From<#=pixelType#>(sp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destPixels); + } + +<# + } + + void GenerateToDestFormatMethods(string pixelType) + { + #> + /// + /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// + /// A to configure internal operations + /// The span of source pixels + /// The destination span of data. + internal virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destPixels) + { + Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels)); + + ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); + ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); + ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); + + dp.FromScaledVector4(sp.ToScaledVector4()); + } + } + + /// + /// A helper for that expects a byte span as destination. + /// The layout of the data in 'destBytes' must be compatible with layout. + /// + /// A to configure internal operations + /// The to the source pixels. + /// The to the destination bytes. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + { + this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); + } +<# + } + +#> +// 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.PixelFormats +{ + public partial class PixelOperations + {<# + + GenerateFromMethods("Argb32"); + GenerateToDestFormatMethods("Argb32"); + + GenerateFromMethods("Bgr24"); + GenerateToDestFormatMethods("Bgr24"); + + GenerateFromMethods("Bgra32"); + GenerateToDestFormatMethods("Bgra32"); + + GenerateFromMethods("Gray8"); + GenerateToDestFormatMethods("Gray8"); + + GenerateFromMethods("Gray16"); + GenerateToDestFormatMethods("Gray16"); + + GenerateFromMethods("Rgb24"); + GenerateToDestFormatMethods("Rgb24"); + + GenerateFromMethods("Rgba32"); + GenerateToDestFormatMethods("Rgba32"); + + GenerateFromMethods("Rgb48"); + GenerateToDestFormatMethods("Rgb48"); + + GenerateFromMethods("Rgba64"); + GenerateToDestFormatMethods("Rgba64"); + +#> } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index b12a2bfa58..115dd7a43d 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -22,109 +23,130 @@ namespace SixLabors.ImageSharp.PixelFormats public static PixelOperations Instance { get; } = default(TPixel).CreatePixelOperations(); /// - /// Bulk version of + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + /// The to the destination colors. + internal virtual void FromVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destPixels) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); - for (int i = 0; i < count; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromVector4(sp); - } + Utils.Vector4Converters.Default.DangerousFromVector4(sourceVectors, destPixels); } /// - /// Bulk version of . + /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// - /// The to the source colors. - /// The to the destination vectors. - /// The number of pixels to convert. - internal virtual void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + /// A to configure internal operations + /// The to the source colors. + /// The to the destination vectors. + internal virtual void ToVector4( + Configuration configuration, + ReadOnlySpan sourcePixels, + Span destVectors) { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); - ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); - - for (int i = 0; i < count; i++) - { - ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToVector4(); - } + Utils.Vector4Converters.Default.DangerousToVector4(sourcePixels, destVectors); } /// - /// Bulk version of + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// + /// A to configure internal operations /// The to the source vectors. /// The to the destination colors. - /// The number of pixels to convert. - internal virtual void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) + internal virtual void FromScaledVector4( + Configuration configuration, + ReadOnlySpan sourceVectors, + Span destinationColors) { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors)); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); - - for (int i = 0; i < count; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - dp.PackFromScaledVector4(sp); - } + Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destinationColors); } /// - /// Bulk version of . + /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// + /// A to configure internal operations /// The to the source colors. /// The to the destination vectors. - /// The number of pixels to convert. - internal virtual void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) + internal virtual void ToScaledVector4( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationVectors) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors)); + + Utils.Vector4Converters.Default.DangerousToScaledVector4(sourceColors, destinationVectors); + } + + /// + /// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'. + /// + /// The destination pixel type. + /// A to configure internal operations + /// The to the source colors. + /// The to the destination colors. + internal virtual void To( + Configuration configuration, + ReadOnlySpan sourceColors, + Span destinationColors) + where TDestinationPixel : struct, IPixel { - GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count); + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors)); + int count = sourceColors.Length; ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + // Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the + // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 algorithm. + // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and + // packs/unpacks the pixel without and conversion so we employ custom methods do do this. + if (typeof(TDestinationPixel) == typeof(Gray16)) + { + ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray16 dp = ref Unsafe.Add(ref gray16Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + if (typeof(TDestinationPixel) == typeof(Gray8)) + { + ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationColors)); + for (int i = 0; i < count; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Gray8 dp = ref Unsafe.Add(ref gray8Ref, i); + dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + } + + return; + } + + // Normal conversion + ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationColors); for (int i = 0; i < count; i++) { ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); - ref Vector4 dp = ref Unsafe.Add(ref destRef, i); - dp = sp.ToScaledVector4(); + ref TDestinationPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp.ToScaledVector4()); } } - - /// - /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. - /// Throwing an if the condition is not met. - /// - /// The source element type - /// The destination element type - /// The source span - /// The source parameter name - /// The destination span - /// The destination parameter name - /// The minimum length - protected internal static void GuardSpans( - ReadOnlySpan source, - string sourceParamName, - Span destination, - string destinationParamName, - int minLength) - { - Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); - Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName); - } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rg32.cs b/src/ImageSharp/PixelFormats/Rg32.cs deleted file mode 100644 index e5ceeacec2..0000000000 --- a/src/ImageSharp/PixelFormats/Rg32.cs +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing two 16-bit unsigned normalized values ranging from 0 to 1. - /// - /// Ranges from [0, 0, 0, 1] to [1, 1, 0, 1] in vector form. - /// - /// - public struct Rg32 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// The x-component - /// The y-component - public Rg32(float x, float y) - { - this.PackedValue = Pack(x, y); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public Rg32(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rg32 left, Rg32 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rg32 left, Rg32 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2( - (this.PackedValue & 0xFFFF) / 65535F, - ((this.PackedValue >> 16) & 0xFFFF) / 65535F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.ToVector2(), 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)vector.X; - dest.G = (byte)vector.Y; - dest.B = (byte)vector.Z; - dest.A = (byte)vector.W; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Rg32 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rg32 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - public override string ToString() - { - return this.ToVector2().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) - { - return (uint)( - ((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | - (((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F; - } -} diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs deleted file mode 100644 index 24c311d0d3..0000000000 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255. - /// The color components are stored in red, green, blue order (least significant to most significant byte). - /// - /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. - /// - /// - [StructLayout(LayoutKind.Explicit)] - public struct Rgb24 : IPixel - { - /// - /// The red component. - /// - [FieldOffset(0)] - public byte R; - - /// - /// The green component. - /// - [FieldOffset(1)] - public byte G; - - /// - /// The blue component. - /// - [FieldOffset(2)] - public byte B; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgb24(byte r, byte g, byte b) - { - this.R = r; - this.G = g; - this.B = b; - } - - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// The instance of to convert. - /// An instance of . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static implicit operator Rgb24(ColorSpaces.Rgb color) - { - var vector = new Vector4(color.ToVector3(), 1); - Rgb24 rgb = default; - rgb.PackFromScaledVector4(vector); - return rgb; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb24 other) - { - return this.R == other.R && this.G == other.G && this.B == other.B; - } - - /// - public override bool Equals(object obj) - { - return obj is Rgb24 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); - return HashHelpers.Combine(hash, this.B.GetHashCode()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - Rgba32 rgba = default; - rgba.PackFromVector4(vector); - this.PackFromRgba32(rgba); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) => dest = this; - - /// - public void ToRgba32(ref Rgba32 dest) - { - dest.Rgb = this; - dest.A = byte.MaxValue; - } - - /// - public void ToArgb32(ref Argb32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - public void ToBgr24(ref Bgr24 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - } - - /// - public void ToBgra32(ref Bgra32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) - { - this.R = (byte)(((source.R * 255) + 32895) >> 16); - this.G = (byte)(((source.G * 255) + 32895) >> 16); - this.B = (byte)(((source.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B})"; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgb48.cs b/src/ImageSharp/PixelFormats/Rgb48.cs deleted file mode 100644 index 2d92b0e4e3..0000000000 --- a/src/ImageSharp/PixelFormats/Rgb48.cs +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing three 16-bit unsigned normalized values ranging from 0 to 635535. - /// - /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. - /// - /// - [StructLayout(LayoutKind.Sequential)] - public struct Rgb48 : IPixel - { - private const float Max = 65535F; - - /// - /// Gets or sets the red component. - /// - public ushort R; - - /// - /// Gets or sets the green component. - /// - public ushort G; - - /// - /// Gets or sets the blue component. - /// - public ushort B; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - public Rgb48(ushort r, ushort g, ushort b) - : this() - { - this.R = r; - this.G = g; - this.B = b; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - public Rgb48(float r, float g, float b) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgb48(Vector3 vector) - : this(vector.X, vector.Y, vector.Z) - { - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgb48 left, Rgb48 right) - { - return left.R == right.R - && left.G == right.G - && left.B == right.B; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgb48 left, Rgb48 right) - { - return left.R != right.R - || left.G != right.G - || left.B != right.B; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R / Max, this.G / Max, this.B / Max, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.R = (ushort)MathF.Round(vector.X); - this.G = (ushort)MathF.Round(vector.Y); - this.B = (ushort)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this = source.Rgb; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this = source; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) - { - dest.Rgb = this; - dest.A = ushort.MaxValue; - } - - /// - public override bool Equals(object obj) - { - return obj is Rgb48 rgb48 && this.Equals(rgb48); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgb48 other) - { - return this.R == other.R - && this.G == other.G - && this.B == other.B; - } - - /// - public override string ToString() => this.ToVector4().ToString(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return HashHelpers.Combine( - this.R.GetHashCode(), - HashHelpers.Combine(this.G.GetHashCode(), this.B.GetHashCode())); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba1010102.cs b/src/ImageSharp/PixelFormats/Rgba1010102.cs deleted file mode 100644 index 94fb7a41e6..0000000000 --- a/src/ImageSharp/PixelFormats/Rgba1010102.cs +++ /dev/null @@ -1,248 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed vector type containing unsigned normalized values ranging from 0 to 1. - /// The x, y and z components use 10 bits, and the w component uses 2 bits. - /// - /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. - /// - /// - public struct Rgba1010102 : IPixel, IPackedVector - { - /// - /// Initializes a new instance of the struct. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - public Rgba1010102(float x, float y, float z, float w) - { - this.PackedValue = Pack(x, y, z, w); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public Rgba1010102(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba1010102 left, Rgba1010102 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - ((this.PackedValue >> 0) & 0x03FF) / 1023F, - ((this.PackedValue >> 10) & 0x03FF) / 1023F, - ((this.PackedValue >> 20) & 0x03FF) / 1023F, - ((this.PackedValue >> 30) & 0x03) / 3F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToVector4() * 255F; - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Rgba1010102 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba1010102 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - public override string ToString() - { - return this.ToVector4().ToString(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.PackedValue.GetHashCode(); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y, float z, float w) - { - return (uint)( - (((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) | - (((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) | - (((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) | - (((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30)); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs deleted file mode 100644 index 2629ce3f79..0000000000 --- a/src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.Memory; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Provides optimized overrides for bulk operations. - /// - public partial struct Rgba32 - { - /// - /// implementation optimized for . - /// - internal partial class PixelOperations : PixelOperations - { - /// - /// SIMD optimized bulk implementation of - /// that works only with `count` divisible by . - /// - /// The to the source colors. - /// The to the dstination vectors. - /// The number of pixels to convert. - /// - /// Implementation adapted from: - /// - /// http://stackoverflow.com/a/5362789 - /// - /// TODO: We can replace this implementation in the future using new Vector API-s: - /// - /// https://github.com/dotnet/corefx/issues/15957 - /// - /// - internal static void ToVector4SimdAligned(ReadOnlySpan sourceColors, Span destVectors, int count) - { - if (!Vector.IsHardwareAccelerated) - { - throw new InvalidOperationException( - "Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!"); - } - - DebugGuard.IsTrue( - count % Vector.Count == 0, - nameof(count), - "Argument 'count' should divisible by Vector.Count!"); - - var bVec = new Vector(256.0f / 255.0f); - var magicFloat = new Vector(32768.0f); - var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f - var mask = new Vector(255); - - int unpackedRawCount = count * 4; - - ref uint sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(sourceColors)); - ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As(ref MemoryMarshal.GetReference(destVectors)); - ref Vector destBaseAsUInt = ref Unsafe.As>(ref destBaseAsUnpacked); - ref Vector destBaseAsFloat = ref Unsafe.As>(ref destBaseAsUnpacked); - - for (int i = 0; i < count; i++) - { - uint sVal = Unsafe.Add(ref sourceBase, i); - ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i); - - // This call is the bottleneck now: - dst.Load(sVal); - } - - int numOfVectors = unpackedRawCount / Vector.Count; - - for (int i = 0; i < numOfVectors; i++) - { - Vector vi = Unsafe.Add(ref destBaseAsUInt, i); - - vi &= mask; - vi |= magicInt; - - var vf = Vector.AsVectorSingle(vi); - vf = (vf - magicFloat) * bVec; - - Unsafe.Add(ref destBaseAsFloat, i) = vf; - } - } - - /// - internal override void ToVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) - { - Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); - Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); - - if (count < 256 || !Vector.IsHardwareAccelerated) - { - // Doesn't worth to bother with SIMD: - base.ToVector4(sourceColors, destinationVectors, count); - return; - } - - int remainder = count % Vector.Count; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount); - } - - if (remainder > 0) - { - sourceColors = sourceColors.Slice(alignedCount); - destinationVectors = destinationVectors.Slice(alignedCount); - base.ToVector4(sourceColors, destinationVectors, remainder); - } - } - - /// - internal override void PackFromVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); - - if (!SimdUtils.IsAvx2CompatibleArchitecture) - { - base.PackFromVector4(sourceVectors, destinationColors, count); - return; - } - - int remainder = count % 2; - int alignedCount = count - remainder; - - if (alignedCount > 0) - { - ReadOnlySpan flatSrc = MemoryMarshal.Cast(sourceVectors.Slice(0, alignedCount)); - Span flatDest = MemoryMarshal.Cast(destinationColors); - - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); - } - - if (remainder > 0) - { - // actually: remainder == 1 - int lastIdx = count - 1; - destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]); - } - } - - /// - internal override void ToScaledVector4(ReadOnlySpan sourceColors, Span destinationVectors, int count) - { - this.ToVector4(sourceColors, destinationVectors, count); - } - - /// - internal override void PackFromScaledVector4(ReadOnlySpan sourceVectors, Span destinationColors, int count) - { - this.PackFromVector4(sourceVectors, destinationColors, count); - } - - /// - internal override void PackFromRgba32(ReadOnlySpan source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - source.Slice(0, count).CopyTo(destPixels); - } - - /// - internal override void ToRgba32(ReadOnlySpan sourcePixels, Span dest, int count) - { - GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); - - sourcePixels.Slice(0, count).CopyTo(dest); - } - - /// - /// Value type to store -s unpacked into multiple -s. - /// - [StructLayout(LayoutKind.Sequential)] - private struct UnpackedRGBA - { - private uint r; - - private uint g; - - private uint b; - - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> GreenShift; - this.b = p >> BlueShift; - this.a = p >> AlphaShift; - } - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Rgba64.cs b/src/ImageSharp/PixelFormats/Rgba64.cs deleted file mode 100644 index 8e6be1e8c4..0000000000 --- a/src/ImageSharp/PixelFormats/Rgba64.cs +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing four 16-bit unsigned normalized values ranging from 0 to 635535. - /// - /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. - /// - /// - [StructLayout(LayoutKind.Sequential)] - public struct Rgba64 : IPixel, IPackedVector - { - private const float Max = 65535F; - - /// - /// Gets or sets the red component. - /// - public ushort R; - - /// - /// Gets or sets the green component. - /// - public ushort G; - - /// - /// Gets or sets the blue component. - /// - public ushort B; - - /// - /// Gets or sets the alpha component. - /// - public ushort A; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - public Rgba64(ushort r, ushort g, ushort b, ushort a) - : this() - { - this.R = r; - this.G = g; - this.B = b; - this.A = a; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - public Rgba64(float r, float g, float b, float a) - : this() - { - this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max); - this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max); - this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max); - this.A = (ushort)MathF.Round(a.Clamp(0, 1) * Max); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components values. - public Rgba64(Vector4 vector) - : this(vector.X, vector.Y, vector.Z, vector.W) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The packed value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba64(ulong packed) - : this() - { - this.PackedValue = packed; - } - - /// - /// Gets or sets the RGB components of this struct as - /// - public Rgb48 Rgb - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Unsafe.As(ref this); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Unsafe.As(ref this) = value; - } - - /// - public ulong PackedValue - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Unsafe.As(ref this); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set => Unsafe.As(ref this) = value; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba64 left, Rgba64 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba64 left, Rgba64 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / Max; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.R = (ushort)MathF.Round(vector.X); - this.G = (ushort)MathF.Round(vector.Y); - this.B = (ushort)MathF.Round(vector.Z); - this.A = (ushort)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.PackFromVector4(source.ToVector4()); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this = source; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - // Taken from libpng pngtran.c line: 2419 - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) - { - this.Rgb = source; - this.A = ushort.MaxValue; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest = this.Rgb; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest = this; - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - dest.R = (byte)(((this.R * 255) + 32895) >> 16); - dest.G = (byte)(((this.G * 255) + 32895) >> 16); - dest.B = (byte)(((this.B * 255) + 32895) >> 16); - dest.A = (byte)(((this.A * 255) + 32895) >> 16); - } - - /// - public override bool Equals(object obj) - { - return obj is Rgba64 rgba64 && this.Equals(rgba64); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba64 other) - { - return this.PackedValue == other.PackedValue; - } - - /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs b/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs deleted file mode 100644 index 2ef37c43ae..0000000000 --- a/src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Provides operators and composition algorithms. - /// - public partial struct RgbaVector - { - /// - /// Represents a matching the W3C definition that has an hex value of #F0F8FF. - /// - public static readonly RgbaVector AliceBlue = NamedColors.AliceBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAEBD7. - /// - public static readonly RgbaVector AntiqueWhite = NamedColors.AntiqueWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Aqua = NamedColors.Aqua; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFFD4. - /// - public static readonly RgbaVector Aquamarine = NamedColors.Aquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFFF. - /// - public static readonly RgbaVector Azure = NamedColors.Azure; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5DC. - /// - public static readonly RgbaVector Beige = NamedColors.Beige; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4C4. - /// - public static readonly RgbaVector Bisque = NamedColors.Bisque; - - /// - /// Represents a matching the W3C definition that has an hex value of #000000. - /// - public static readonly RgbaVector Black = NamedColors.Black; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEBCD. - /// - public static readonly RgbaVector BlanchedAlmond = NamedColors.BlanchedAlmond; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000FF. - /// - public static readonly RgbaVector Blue = NamedColors.Blue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8A2BE2. - /// - public static readonly RgbaVector BlueViolet = NamedColors.BlueViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #A52A2A. - /// - public static readonly RgbaVector Brown = NamedColors.Brown; - - /// - /// Represents a matching the W3C definition that has an hex value of #DEB887. - /// - public static readonly RgbaVector BurlyWood = NamedColors.BurlyWood; - - /// - /// Represents a matching the W3C definition that has an hex value of #5F9EA0. - /// - public static readonly RgbaVector CadetBlue = NamedColors.CadetBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #7FFF00. - /// - public static readonly RgbaVector Chartreuse = NamedColors.Chartreuse; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2691E. - /// - public static readonly RgbaVector Chocolate = NamedColors.Chocolate; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF7F50. - /// - public static readonly RgbaVector Coral = NamedColors.Coral; - - /// - /// Represents a matching the W3C definition that has an hex value of #6495ED. - /// - public static readonly RgbaVector CornflowerBlue = NamedColors.CornflowerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF8DC. - /// - public static readonly RgbaVector Cornsilk = NamedColors.Cornsilk; - - /// - /// Represents a matching the W3C definition that has an hex value of #DC143C. - /// - public static readonly RgbaVector Crimson = NamedColors.Crimson; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FFFF. - /// - public static readonly RgbaVector Cyan = NamedColors.Cyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #00008B. - /// - public static readonly RgbaVector DarkBlue = NamedColors.DarkBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #008B8B. - /// - public static readonly RgbaVector DarkCyan = NamedColors.DarkCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #B8860B. - /// - public static readonly RgbaVector DarkGoldenrod = NamedColors.DarkGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #A9A9A9. - /// - public static readonly RgbaVector DarkGray = NamedColors.DarkGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #006400. - /// - public static readonly RgbaVector DarkGreen = NamedColors.DarkGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #BDB76B. - /// - public static readonly RgbaVector DarkKhaki = NamedColors.DarkKhaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B008B. - /// - public static readonly RgbaVector DarkMagenta = NamedColors.DarkMagenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #556B2F. - /// - public static readonly RgbaVector DarkOliveGreen = NamedColors.DarkOliveGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF8C00. - /// - public static readonly RgbaVector DarkOrange = NamedColors.DarkOrange; - - /// - /// Represents a matching the W3C definition that has an hex value of #9932CC. - /// - public static readonly RgbaVector DarkOrchid = NamedColors.DarkOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B0000. - /// - public static readonly RgbaVector DarkRed = NamedColors.DarkRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #E9967A. - /// - public static readonly RgbaVector DarkSalmon = NamedColors.DarkSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #8FBC8B. - /// - public static readonly RgbaVector DarkSeaGreen = NamedColors.DarkSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #483D8B. - /// - public static readonly RgbaVector DarkSlateBlue = NamedColors.DarkSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #2F4F4F. - /// - public static readonly RgbaVector DarkSlateGray = NamedColors.DarkSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #00CED1. - /// - public static readonly RgbaVector DarkTurquoise = NamedColors.DarkTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #9400D3. - /// - public static readonly RgbaVector DarkViolet = NamedColors.DarkViolet; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF1493. - /// - public static readonly RgbaVector DeepPink = NamedColors.DeepPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #00BFFF. - /// - public static readonly RgbaVector DeepSkyBlue = NamedColors.DeepSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #696969. - /// - public static readonly RgbaVector DimGray = NamedColors.DimGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #1E90FF. - /// - public static readonly RgbaVector DodgerBlue = NamedColors.DodgerBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #B22222. - /// - public static readonly RgbaVector Firebrick = NamedColors.Firebrick; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAF0. - /// - public static readonly RgbaVector FloralWhite = NamedColors.FloralWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #228B22. - /// - public static readonly RgbaVector ForestGreen = NamedColors.ForestGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Fuchsia = NamedColors.Fuchsia; - - /// - /// Represents a matching the W3C definition that has an hex value of #DCDCDC. - /// - public static readonly RgbaVector Gainsboro = NamedColors.Gainsboro; - - /// - /// Represents a matching the W3C definition that has an hex value of #F8F8FF. - /// - public static readonly RgbaVector GhostWhite = NamedColors.GhostWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFD700. - /// - public static readonly RgbaVector Gold = NamedColors.Gold; - - /// - /// Represents a matching the W3C definition that has an hex value of #DAA520. - /// - public static readonly RgbaVector Goldenrod = NamedColors.Goldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #808080. - /// - public static readonly RgbaVector Gray = NamedColors.Gray; - - /// - /// Represents a matching the W3C definition that has an hex value of #008000. - /// - public static readonly RgbaVector Green = NamedColors.Green; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADFF2F. - /// - public static readonly RgbaVector GreenYellow = NamedColors.GreenYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0FFF0. - /// - public static readonly RgbaVector Honeydew = NamedColors.Honeydew; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF69B4. - /// - public static readonly RgbaVector HotPink = NamedColors.HotPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD5C5C. - /// - public static readonly RgbaVector IndianRed = NamedColors.IndianRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #4B0082. - /// - public static readonly RgbaVector Indigo = NamedColors.Indigo; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFF0. - /// - public static readonly RgbaVector Ivory = NamedColors.Ivory; - - /// - /// Represents a matching the W3C definition that has an hex value of #F0E68C. - /// - public static readonly RgbaVector Khaki = NamedColors.Khaki; - - /// - /// Represents a matching the W3C definition that has an hex value of #E6E6FA. - /// - public static readonly RgbaVector Lavender = NamedColors.Lavender; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF0F5. - /// - public static readonly RgbaVector LavenderBlush = NamedColors.LavenderBlush; - - /// - /// Represents a matching the W3C definition that has an hex value of #7CFC00. - /// - public static readonly RgbaVector LawnGreen = NamedColors.LawnGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFACD. - /// - public static readonly RgbaVector LemonChiffon = NamedColors.LemonChiffon; - - /// - /// Represents a matching the W3C definition that has an hex value of #ADD8E6. - /// - public static readonly RgbaVector LightBlue = NamedColors.LightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F08080. - /// - public static readonly RgbaVector LightCoral = NamedColors.LightCoral; - - /// - /// Represents a matching the W3C definition that has an hex value of #E0FFFF. - /// - public static readonly RgbaVector LightCyan = NamedColors.LightCyan; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAFAD2. - /// - public static readonly RgbaVector LightGoldenrodYellow = NamedColors.LightGoldenrodYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #D3D3D3. - /// - public static readonly RgbaVector LightGray = NamedColors.LightGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #90EE90. - /// - public static readonly RgbaVector LightGreen = NamedColors.LightGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFB6C1. - /// - public static readonly RgbaVector LightPink = NamedColors.LightPink; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA07A. - /// - public static readonly RgbaVector LightSalmon = NamedColors.LightSalmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #20B2AA. - /// - public static readonly RgbaVector LightSeaGreen = NamedColors.LightSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEFA. - /// - public static readonly RgbaVector LightSkyBlue = NamedColors.LightSkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #778899. - /// - public static readonly RgbaVector LightSlateGray = NamedColors.LightSlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0C4DE. - /// - public static readonly RgbaVector LightSteelBlue = NamedColors.LightSteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFE0. - /// - public static readonly RgbaVector LightYellow = NamedColors.LightYellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF00. - /// - public static readonly RgbaVector Lime = NamedColors.Lime; - - /// - /// Represents a matching the W3C definition that has an hex value of #32CD32. - /// - public static readonly RgbaVector LimeGreen = NamedColors.LimeGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FAF0E6. - /// - public static readonly RgbaVector Linen = NamedColors.Linen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF00FF. - /// - public static readonly RgbaVector Magenta = NamedColors.Magenta; - - /// - /// Represents a matching the W3C definition that has an hex value of #800000. - /// - public static readonly RgbaVector Maroon = NamedColors.Maroon; - - /// - /// Represents a matching the W3C definition that has an hex value of #66CDAA. - /// - public static readonly RgbaVector MediumAquamarine = NamedColors.MediumAquamarine; - - /// - /// Represents a matching the W3C definition that has an hex value of #0000CD. - /// - public static readonly RgbaVector MediumBlue = NamedColors.MediumBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #BA55D3. - /// - public static readonly RgbaVector MediumOrchid = NamedColors.MediumOrchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #9370DB. - /// - public static readonly RgbaVector MediumPurple = NamedColors.MediumPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #3CB371. - /// - public static readonly RgbaVector MediumSeaGreen = NamedColors.MediumSeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #7B68EE. - /// - public static readonly RgbaVector MediumSlateBlue = NamedColors.MediumSlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FA9A. - /// - public static readonly RgbaVector MediumSpringGreen = NamedColors.MediumSpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #48D1CC. - /// - public static readonly RgbaVector MediumTurquoise = NamedColors.MediumTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #C71585. - /// - public static readonly RgbaVector MediumVioletRed = NamedColors.MediumVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #191970. - /// - public static readonly RgbaVector MidnightBlue = NamedColors.MidnightBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5FFFA. - /// - public static readonly RgbaVector MintCream = NamedColors.MintCream; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4E1. - /// - public static readonly RgbaVector MistyRose = NamedColors.MistyRose; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFE4B5. - /// - public static readonly RgbaVector Moccasin = NamedColors.Moccasin; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDEAD. - /// - public static readonly RgbaVector NavajoWhite = NamedColors.NavajoWhite; - - /// - /// Represents a matching the W3C definition that has an hex value of #000080. - /// - public static readonly RgbaVector Navy = NamedColors.Navy; - - /// - /// Represents a matching the W3C definition that has an hex value of #FDF5E6. - /// - public static readonly RgbaVector OldLace = NamedColors.OldLace; - - /// - /// Represents a matching the W3C definition that has an hex value of #808000. - /// - public static readonly RgbaVector Olive = NamedColors.Olive; - - /// - /// Represents a matching the W3C definition that has an hex value of #6B8E23. - /// - public static readonly RgbaVector OliveDrab = NamedColors.OliveDrab; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFA500. - /// - public static readonly RgbaVector Orange = NamedColors.Orange; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF4500. - /// - public static readonly RgbaVector OrangeRed = NamedColors.OrangeRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #DA70D6. - /// - public static readonly RgbaVector Orchid = NamedColors.Orchid; - - /// - /// Represents a matching the W3C definition that has an hex value of #EEE8AA. - /// - public static readonly RgbaVector PaleGoldenrod = NamedColors.PaleGoldenrod; - - /// - /// Represents a matching the W3C definition that has an hex value of #98FB98. - /// - public static readonly RgbaVector PaleGreen = NamedColors.PaleGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #AFEEEE. - /// - public static readonly RgbaVector PaleTurquoise = NamedColors.PaleTurquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #DB7093. - /// - public static readonly RgbaVector PaleVioletRed = NamedColors.PaleVioletRed; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFEFD5. - /// - public static readonly RgbaVector PapayaWhip = NamedColors.PapayaWhip; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFDAB9. - /// - public static readonly RgbaVector PeachPuff = NamedColors.PeachPuff; - - /// - /// Represents a matching the W3C definition that has an hex value of #CD853F. - /// - public static readonly RgbaVector Peru = NamedColors.Peru; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFC0CB. - /// - public static readonly RgbaVector Pink = NamedColors.Pink; - - /// - /// Represents a matching the W3C definition that has an hex value of #DDA0DD. - /// - public static readonly RgbaVector Plum = NamedColors.Plum; - - /// - /// Represents a matching the W3C definition that has an hex value of #B0E0E6. - /// - public static readonly RgbaVector PowderBlue = NamedColors.PowderBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #800080. - /// - public static readonly RgbaVector Purple = NamedColors.Purple; - - /// - /// Represents a matching the W3C definition that has an hex value of #663399. - /// - public static readonly RgbaVector RebeccaPurple = NamedColors.RebeccaPurple; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF0000. - /// - public static readonly RgbaVector Red = NamedColors.Red; - - /// - /// Represents a matching the W3C definition that has an hex value of #BC8F8F. - /// - public static readonly RgbaVector RosyBrown = NamedColors.RosyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #4169E1. - /// - public static readonly RgbaVector RoyalBlue = NamedColors.RoyalBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #8B4513. - /// - public static readonly RgbaVector SaddleBrown = NamedColors.SaddleBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #FA8072. - /// - public static readonly RgbaVector Salmon = NamedColors.Salmon; - - /// - /// Represents a matching the W3C definition that has an hex value of #F4A460. - /// - public static readonly RgbaVector SandyBrown = NamedColors.SandyBrown; - - /// - /// Represents a matching the W3C definition that has an hex value of #2E8B57. - /// - public static readonly RgbaVector SeaGreen = NamedColors.SeaGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFF5EE. - /// - public static readonly RgbaVector SeaShell = NamedColors.SeaShell; - - /// - /// Represents a matching the W3C definition that has an hex value of #A0522D. - /// - public static readonly RgbaVector Sienna = NamedColors.Sienna; - - /// - /// Represents a matching the W3C definition that has an hex value of #C0C0C0. - /// - public static readonly RgbaVector Silver = NamedColors.Silver; - - /// - /// Represents a matching the W3C definition that has an hex value of #87CEEB. - /// - public static readonly RgbaVector SkyBlue = NamedColors.SkyBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #6A5ACD. - /// - public static readonly RgbaVector SlateBlue = NamedColors.SlateBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #708090. - /// - public static readonly RgbaVector SlateGray = NamedColors.SlateGray; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFAFA. - /// - public static readonly RgbaVector Snow = NamedColors.Snow; - - /// - /// Represents a matching the W3C definition that has an hex value of #00FF7F. - /// - public static readonly RgbaVector SpringGreen = NamedColors.SpringGreen; - - /// - /// Represents a matching the W3C definition that has an hex value of #4682B4. - /// - public static readonly RgbaVector SteelBlue = NamedColors.SteelBlue; - - /// - /// Represents a matching the W3C definition that has an hex value of #D2B48C. - /// - public static readonly RgbaVector Tan = NamedColors.Tan; - - /// - /// Represents a matching the W3C definition that has an hex value of #008080. - /// - public static readonly RgbaVector Teal = NamedColors.Teal; - - /// - /// Represents a matching the W3C definition that has an hex value of #D8BFD8. - /// - public static readonly RgbaVector Thistle = NamedColors.Thistle; - - /// - /// Represents a matching the W3C definition that has an hex value of #FF6347. - /// - public static readonly RgbaVector Tomato = NamedColors.Tomato; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector Transparent = NamedColors.Transparent; - - /// - /// Represents a matching the W3C definition that has an hex value of #40E0D0. - /// - public static readonly RgbaVector Turquoise = NamedColors.Turquoise; - - /// - /// Represents a matching the W3C definition that has an hex value of #EE82EE. - /// - public static readonly RgbaVector Violet = NamedColors.Violet; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5DEB3. - /// - public static readonly RgbaVector Wheat = NamedColors.Wheat; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFFFF. - /// - public static readonly RgbaVector White = NamedColors.White; - - /// - /// Represents a matching the W3C definition that has an hex value of #F5F5F5. - /// - public static readonly RgbaVector WhiteSmoke = NamedColors.WhiteSmoke; - - /// - /// Represents a matching the W3C definition that has an hex value of #FFFF00. - /// - public static readonly RgbaVector Yellow = NamedColors.Yellow; - - /// - /// Represents a matching the W3C definition that has an hex value of #9ACD32. - /// - public static readonly RgbaVector YellowGreen = NamedColors.YellowGreen; - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs deleted file mode 100644 index ce40665cd4..0000000000 --- a/src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Provides optimized overrides for bulk operations. - /// - public partial struct RgbaVector - { - /// - /// implementation optimized for . - /// - internal class PixelOperations : PixelOperations - { - /// - internal override unsafe void ToVector4(ReadOnlySpan sourceColors, Span destVectors, int count) - { - GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); - - MemoryMarshal.Cast(sourceColors).Slice(0, count).CopyTo(destVectors); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/RgbaVector.cs b/src/ImageSharp/PixelFormats/RgbaVector.cs deleted file mode 100644 index dd5f77b80f..0000000000 --- a/src/ImageSharp/PixelFormats/RgbaVector.cs +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Unpacked pixel type containing four 16-bit floating-point values typically ranging from 0 to 1. - /// The color components are stored in red, green, blue, and alpha order. - /// - /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. - /// - /// - /// - /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, - /// as it avoids the need to create new values for modification operations. - /// - public partial struct RgbaVector : IPixel - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new Vector4(0.5F); - - /// - /// The backing vector for SIMD support. - /// - private Vector4 backingVector; - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(byte r, byte g, byte b, byte a = 255) - : this() - { - this.backingVector = new Vector4(r, g, b, a) / MaxBytes; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(float r, float g, float b, float a = 1) - : this() - { - this.backingVector = new Vector4(r, g, b, a); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector3 vector) - : this() - { - this.backingVector = new Vector4(vector, 1); - } - - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public RgbaVector(Vector4 vector) - : this() - { - this.backingVector = vector; - } - - /// - /// Gets or sets the red component. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.X; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.X = value; - } - } - - /// - /// Gets or sets the green component. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Y; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Y = value; - } - } - - /// - /// Gets or sets the blue component. - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.Z; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.Z = value; - } - } - - /// - /// Gets or sets the alpha component. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return this.backingVector.W; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.backingVector.W = value; - } - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(RgbaVector left, RgbaVector right) - { - return left.backingVector == right.backingVector; - } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(RgbaVector left, RgbaVector right) - { - return left.backingVector != right.backingVector; - } - - /// - /// Creates a new instance of the struct. - /// - /// - /// The hexadecimal representation of the combined color components arranged - /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. - /// - /// - /// The . - /// - public static RgbaVector FromHex(string hex) - { - return ColorBuilder.FromHex(hex); - } - - /// - public PixelOperations CreatePixelOperations() => new RgbaVector.PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this.backingVector = source.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - this.backingVector = source.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - this.backingVector = source.ToVector4(); - } - - /// - /// Converts the value of this instance to a hexadecimal string. - /// - /// A hexadecimal string representation of the value. - public string ToHex() - { - // Hex is RRGGBBAA - Vector4 vector = this.backingVector * MaxBytes; - vector += Half; - uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24); - return hexOrder.ToString("X8"); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.backingVector = vector; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return this.backingVector; - } - - /// - public override bool Equals(object obj) - { - return obj is RgbaVector other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(RgbaVector other) - { - return this.backingVector == other.backingVector; - } - - /// - /// Gets a string representation of the packed vector. - /// - /// A string representation of the packed vector. - public override string ToString() - { - return this.ToVector4().ToString(); - } - - /// - public override int GetHashCode() - { - return this.backingVector.GetHashCode(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes; - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short2.cs b/src/ImageSharp/PixelFormats/Short2.cs deleted file mode 100644 index 9fc7618b91..0000000000 --- a/src/ImageSharp/PixelFormats/Short2.cs +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing two 16-bit signed integer values. - /// - /// Ranges from [-32767, -32767, 0, 1] to [32767, 32767, 0, 1] in vector form. - /// - /// - public struct Short2 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector2 MaxBytes = new Vector2(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector2 Half = new Vector2(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector2 Round = new Vector2(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public Short2(Vector2 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - public Short2(float x, float y) - { - this.PackedValue = Pack(x, y); - } - - /// - public uint PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short2 left, Short2 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short2 left, Short2 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; - scaled -= new Vector2(32767F); - this.PackedValue = Pack(scaled.X, scaled.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += new Vector2(32767F); - scaled /= 65534F; - return new Vector4(scaled, 0F, 1F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - Vector2 vector = new Vector2(source.R, source.G) / 255; - vector *= 65534; - vector -= new Vector2(32767); - this.PackedValue = Pack(vector.X, vector.Y); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector2 vector = this.ToByteScaledVector2(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = 0; - dest.A = 255; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - /// Expands the packed representation into a . - /// The vector components are typically expanded in least to greatest significance order. - /// - /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector2 ToVector2() - { - return new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); - } - - /// - public override bool Equals(object obj) - { - return obj is Short2 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short2 other) - { - return this == other; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - public override string ToString() - { - return this.PackedValue.ToString("x8"); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint Pack(float x, float y) - { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - const float MinNeg = ~(int)MaxPos; - - // Clamp the value between min and max values - uint word2 = (uint)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF; - uint word1 = ((uint)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; - - return word2 | word1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector2 ToByteScaledVector2() - { - var vector = this.ToVector2(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - return vector; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Short4.cs b/src/ImageSharp/PixelFormats/Short4.cs deleted file mode 100644 index 641f154f94..0000000000 --- a/src/ImageSharp/PixelFormats/Short4.cs +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.PixelFormats -{ - /// - /// Packed pixel type containing four 16-bit signed integer values. - /// - /// Ranges from [-37267, -37267, -37267, -37267] to [37267, 37267, 37267, 37267] in vector form. - /// - /// - public struct Short4 : IPixel, IPackedVector - { - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new Vector4(255); - - /// - /// The half the maximum byte value. - /// - private static readonly Vector4 Half = new Vector4(127); - - /// - /// The vector value used for rounding. - /// - private static readonly Vector4 Round = new Vector4(.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components. - public Short4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - /// Initializes a new instance of the struct. - /// - /// The x-component. - /// The y-component. - /// The z-component. - /// The w-component. - public Short4(float x, float y, float z, float w) - { - this.PackedValue = Pack(x, y, z, w); - } - - /// - public ulong PackedValue { get; set; } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Short4 left, Short4 right) - { - return left.PackedValue == right.PackedValue; - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Short4 left, Short4 right) - { - return left.PackedValue != right.PackedValue; - } - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - vector *= 65534F; - vector -= new Vector4(32767F); - this.PackFromVector4(vector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - var scaled = this.ToVector4(); - scaled += new Vector4(32767F); - scaled /= 65534F; - return scaled; - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4( - (short)(this.PackedValue & 0xFFFF), - (short)((this.PackedValue >> 0x10) & 0xFFFF), - (short)((this.PackedValue >> 0x20) & 0xFFFF), - (short)((this.PackedValue >> 0x30) & 0xFFFF)); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromArgb32(Argb32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromBgra32(Bgra32 source) - { - var vector = source.ToVector4(); - vector *= 65534; - vector -= new Vector4(32767); - this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32(ref Argb32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24(ref Bgr24 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32(ref Bgra32 dest) - { - Vector4 vector = this.ToByteScaledVector4(); - dest.R = (byte)MathF.Round(vector.X); - dest.G = (byte)MathF.Round(vector.Y); - dest.B = (byte)MathF.Round(vector.Z); - dest.A = (byte)MathF.Round(vector.W); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); - - /// - public override bool Equals(object obj) - { - return obj is Short4 other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Short4 other) - { - return this == other; - } - - /// - /// Gets the hash code for the current instance. - /// - /// Hash code for the instance. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() => this.PackedValue.GetHashCode(); - - /// - /// Returns a string representation of the current instance. - /// - /// String that represents the object. - public override string ToString() - { - return this.PackedValue.ToString("x16"); - } - - /// - /// Packs the components into a . - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - /// The containing the packed values. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong Pack(float x, float y, float z, float w) - { - // Largest two byte positive number 0xFFFF >> 1; - const float MaxPos = 0x7FFF; - - // Two's complement - const float MinNeg = ~(int)MaxPos; - - // Clamp the value between min and max values - ulong word4 = ((ulong)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)Math.Round(z.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)Math.Round(w.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x30; - - return word4 | word3 | word2 | word1; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Vector4 ToByteScaledVector4() - { - var vector = this.ToVector4(); - vector /= 65534; - vector *= 255; - vector += Half; - vector += Round; - return Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs new file mode 100644 index 0000000000..12ec389b06 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs @@ -0,0 +1,108 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers.Binary; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Contains optimized implementations for conversion between pixel formats. + /// + /// + /// Implementations are based on ideas in: + /// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84 + /// The JIT can detect and optimize rotation idioms ROTL (Rotate Left) + /// and ROTR (Rotate Right) emitting efficient CPU instructions: + /// https://github.com/dotnet/coreclr/pull/1830 + /// + internal static class PixelConverter + { + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROTL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROTL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + public static class FromArgb32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // ROTR(8, packedArgb) = [aa bb gg rr] + return (packedArgb >> 8) | (packedArgb << 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedArgb) + { + // packedArgb = [bb gg rr aa] + // REVERSE(packedArgb) = [aa rr gg bb] + return BinaryPrimitives.ReverseEndianness(packedArgb); + } + } + + public static class FromBgra32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedBgra) + { + // packedBgra = [aa rr gg bb] + // REVERSE(packedBgra) = [bb gg rr aa] + return BinaryPrimitives.ReverseEndianness(packedBgra); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToRgba32(uint packedBgra) + { + // packedRgba = [aa rr gg bb] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 rr 00 bb] + // tmp3=ROTL(16, tmp2) = [00 bb 00 rr] + // tmp1 + tmp3 = [aa bb gg rr] + uint tmp1 = packedBgra & 0xFF00FF00; + uint tmp2 = packedBgra & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs new file mode 100644 index 0000000000..139dbfa10f --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -0,0 +1,89 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Helper class for (bulk) conversion of buffers to/from other buffer types. + /// + internal static partial class Vector4Converters + { + /// + /// Provides default implementations for batched to/from conversion. + /// WARNING: The methods are operating without bounds checking and input validation! + /// Input validation is the responsibility of the caller! + /// + public static class Default + { + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromVector4( + ReadOnlySpan sourceVectors, + Span destPixels) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToVector4( + ReadOnlySpan sourcePixels, + Span destVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + + for (int i = 0; i < sourcePixels.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToVector4(); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousFromScaledVector4( + ReadOnlySpan sourceVectors, + Span destinationColors) + where TPixel : struct, IPixel + { + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); + ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + + for (int i = 0; i < sourceVectors.Length; i++) + { + ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i); + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + dp.FromScaledVector4(sp); + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + internal static void DangerousToScaledVector4( + ReadOnlySpan sourceColors, + Span destinationVectors) + where TPixel : struct, IPixel + { + ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); + ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + + for (int i = 0; i < sourceColors.Length; i++) + { + ref TPixel sp = ref Unsafe.Add(ref sourceRef, i); + ref Vector4 dp = ref Unsafe.Add(ref destRef, i); + dp = sp.ToScaledVector4(); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs new file mode 100644 index 0000000000..5609e606d8 --- /dev/null +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -0,0 +1,154 @@ +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.PixelFormats.Utils +{ + /// + /// Contains + /// + internal static partial class Vector4Converters + { + /// + /// Provides efficient implementations for batched to/from conversion. + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + public static class RgbaCompatible + { + /// + /// It's not worth to bother the transitive pixel conversion method below this limit. + /// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT. + /// + private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ToVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourcePixels, + Span destVectors, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + + int count = sourcePixels.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + ToVector4Fallback(sourcePixels, destVectors, scaled); + + return; + } + + // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + int countWithoutLastItem = count - 1; + ReadOnlySpan reducedSource = sourcePixels.Slice(0, countWithoutLastItem); + Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); + pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); + + // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, + // but we are always reading/writing at different positions: + SimdUtils.BulkConvertByteToNormalizedFloat( + MemoryMarshal.Cast(lastQuarterOfDestBuffer), + MemoryMarshal.Cast(destVectors.Slice(0, countWithoutLastItem))); + + destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); + } + + /// + /// Provides an efficient default implementation for + /// and + /// which is applicable for -compatible pixel types where + /// returns the same scaled result as . + /// The method is works by internally converting to a therefore it's not applicable for that type! + /// + [MethodImpl(InliningOptions.ShortMethod)] + internal static void FromVector4( + Configuration configuration, + PixelOperations pixelOperations, + ReadOnlySpan sourceVectors, + Span destPixels, + bool scaled) + where TPixel : struct, IPixel + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + + int count = sourceVectors.Length; + + // Not worth for small buffers: + if (count < Vector4ConversionThreshold) + { + FromVector4Fallback(sourceVectors, destPixels, scaled); + + return; + } + + // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, + // so let's allocate a temporary buffer as usually: + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) + { + Span tempSpan = tempBuffer.Memory.Span; + + SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); + + pixelOperations.FromRgba32(configuration, tempSpan, destPixels); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void ToVector4Fallback(ReadOnlySpan sourcePixels, Span destVectors, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousToScaledVector4(sourcePixels, destVectors); + } + else + { + Default.DangerousToVector4(sourcePixels, destVectors); + } + } + + [MethodImpl(InliningOptions.ColdPath)] + private static void FromVector4Fallback(ReadOnlySpan sourceVectors, Span destPixels, bool scaled) + where TPixel : struct, IPixel + { + if (scaled) + { + Default.DangerousFromScaledVector4(sourceVectors, destPixels); + } + else + { + Default.DangerousFromVector4(sourceVectors, destPixels); + } + } + + private static int CalculateVector4ConversionThreshold() + { + if (!Vector.IsHardwareAccelerated) + { + return int.MaxValue; + } + + return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/AffineTransformBuilder.cs b/src/ImageSharp/Processing/AffineTransformBuilder.cs new file mode 100644 index 0000000000..c3d01241c9 --- /dev/null +++ b/src/ImageSharp/Processing/AffineTransformBuilder.cs @@ -0,0 +1,303 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A helper class for constructing instances for use in affine transforms. + /// + public class AffineTransformBuilder + { + private readonly List> matrixFactories = new List>(); + + /// + /// Prepends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. + /// + /// The amount of rotation, in degrees. + /// The . + public AffineTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + + /// + /// Prepends a rotation matrix using the given rotation angle in radians + /// and the image center point as rotation center. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder PrependRotationRadians(float radians) + => this.Prepend(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + + /// + /// Prepends a rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in degrees. + /// The rotation origin point. + /// The . + public AffineTransformBuilder PrependRotationDegrees(float degrees, Vector2 origin) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Prepends a rotation matrix using the given rotation in radians at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + public AffineTransformBuilder PrependRotationRadians(float radians, Vector2 origin) + => this.PrependMatrix(Matrix3x2.CreateRotation(radians, origin)); + + /// + /// Appends a rotation matrix using the given rotation angle in degrees + /// and the image center point as rotation center. + /// + /// The amount of rotation, in degrees. + /// The . + public AffineTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + + /// + /// Appends a rotation matrix using the given rotation angle in radians + /// and the image center point as rotation center. + /// + /// The amount of rotation, in radians. + /// The . + public AffineTransformBuilder AppendRotationRadians(float radians) + => this.Append(size => TransformUtils.CreateRotationMatrixRadians(radians, size)); + + /// + /// Appends a rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in degrees. + /// The rotation origin point. + /// The . + public AffineTransformBuilder AppendRotationDegrees(float degrees, Vector2 origin) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Appends a rotation matrix using the given rotation in radians at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + public AffineTransformBuilder AppendRotationRadians(float radians, Vector2 origin) + => this.AppendMatrix(Matrix3x2.CreateRotation(radians, origin)); + + /// + /// Prepends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public AffineTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix3x2.CreateScale(scale)); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix3x2.CreateScale(scales)); + + /// + /// Appends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public AffineTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix3x2.CreateScale(scale)); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public AffineTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix3x2.CreateScale(scales)); + + /// + /// Prepends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) + => this.Prepend(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + + /// + /// Prepends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY) + => this.Prepend(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + + /// + /// Prepends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public AffineTransformBuilder PrependSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Prepends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public AffineTransformBuilder PrependSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.PrependMatrix(Matrix3x2.CreateSkew(radiansX, radiansY, origin)); + + /// + /// Appends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) + => this.Append(size => TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size)); + + /// + /// Appends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY) + => this.Append(size => TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size)); + + /// + /// Appends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Appends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.AppendMatrix(Matrix3x2.CreateSkew(radiansX, radiansY, origin)); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix3x2.CreateTranslation(position)); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public AffineTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix3x2.CreateTranslation(position)); + + /// + /// Prepends a raw matrix. + /// + /// The matrix to prepend. + /// The . + public AffineTransformBuilder PrependMatrix(Matrix3x2 matrix) => this.Prepend(_ => matrix); + + /// + /// Appends a raw matrix. + /// + /// The matrix to append. + /// The . + public AffineTransformBuilder AppendMatrix(Matrix3x2 matrix) => this.Append(_ => matrix); + + /// + /// Returns the combined matrix for a given source size. + /// + /// The source image size. + /// The . + public Matrix3x2 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); + + /// + /// Returns the combined matrix for a given source rectangle. + /// + /// The rectangle in the source image. + /// The . + public Matrix3x2 BuildMatrix(Rectangle sourceRectangle) + { + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); + + // Translate the origin matrix to cater for source rectangle offsets. + var matrix = Matrix3x2.CreateTranslation(-sourceRectangle.Location); + + Size size = sourceRectangle.Size; + + foreach (Func factory in this.matrixFactories) + { + matrix *= factory(size); + } + + return matrix; + } + + private AffineTransformBuilder Prepend(Func factory) + { + this.matrixFactories.Insert(0, factory); + return this; + } + + private AffineTransformBuilder Append(Func factory) + { + this.matrixFactories.Add(factory); + return this; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/KnownFilterMatrices.cs b/src/ImageSharp/Processing/KnownFilterMatrices.cs index 4f5e3c8697..cf0d19ff85 100644 --- a/src/ImageSharp/Processing/KnownFilterMatrices.cs +++ b/src/ImageSharp/Processing/KnownFilterMatrices.cs @@ -322,7 +322,7 @@ namespace SixLabors.ImageSharp.Processing degrees += 360; } - float radian = MathFExtensions.DegreeToRadian(degrees); + float radian = GeometryUtilities.DegreeToRadian(degrees); float cosRadian = MathF.Cos(radian); float sinRadian = MathF.Sin(radian); diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs index fe98063104..e4a7a75d5f 100644 --- a/src/ImageSharp/Processing/KnownQuantizers.cs +++ b/src/ImageSharp/Processing/KnownQuantizers.cs @@ -12,20 +12,23 @@ namespace SixLabors.ImageSharp.Processing { /// /// Gets the adaptive Octree quantizer. Fast with good quality. - /// The quantizer only supports a single alpha value. /// public static IQuantizer Octree { get; } = new OctreeQuantizer(); /// /// Gets the Xiaolin Wu's Color Quantizer which generates high quality output. - /// The quantizer supports multiple alpha values. /// public static IQuantizer Wu { get; } = new WuQuantizer(); /// - /// Gets the palette based, Using the collection of web-safe colors. - /// The quantizer supports multiple alpha values. + /// Gets the palette based quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. /// - public static IQuantizer Palette { get; } = new PaletteQuantizer(); + public static IQuantizer WebSafe { get; } = new WebSafePaletteQuantizer(); + + /// + /// Gets the palette based quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public static IQuantizer Werner { get; } = new WernerPaletteQuantizer(); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 5041dcf5ac..32cc2f434b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -76,8 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -89,10 +88,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; + Rgba32 rgba = default; sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization if (!previousPixel.Equals(sourcePixel)) { sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 048af82619..cfdaf107c3 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -56,7 +56,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -68,10 +67,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization // Collect the values before looping so we can reduce our calculation count for identical sibling pixels TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; + Rgba32 rgba = default; sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization if (!previousPixel.Equals(sourcePixel)) { sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 60754b3bf2..67dcfc7f1b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); TPixel upper = this.UpperColor; TPixel lower = this.LowerColor; @@ -80,10 +80,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization configuration, rows => { + Rgba32 rgba = default; for (int y = rows.Min; y < rows.Max; y++) { Span row = source.GetPixelRowSpan(y); - Rgba32 rgba = default; for (int x = startX; x < endX; x++) { @@ -91,9 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization color.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly - ? rgba.A - : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); color = luminance >= threshold ? upper : lower; } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 0ec62ac3d4..38dc638b90 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -66,36 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ? new DenseMatrix(size, 1) : new DenseMatrix(1, size); - float sum = 0F; - for (int i = 0; i < size; i++) - { - float x = 1; - sum += x; - if (horizontal) - { - kernel[0, i] = x; - } - else - { - kernel[i, 0] = x; - } - } - - // Normalize kernel so that the sum of all weights equals 1 - if (horizontal) - { - for (int i = 0; i < size; i++) - { - kernel[0, i] = kernel[0, i] / sum; - } - } - else - { - for (int i = 0; i < size; i++) - { - kernel[i, 0] = kernel[i, 0] / sum; - } - } + kernel.Fill(1.0F / size); return kernel; } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 0669a12470..bd1419e4bb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 1f47649e6f..05007c3706 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index d2f3f8fc58..8ef64bdacc 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); for (int x = 0; x < width; x++) { DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } - PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); + PixelOperations.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs index ebf9c8dec2..4165cf024e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); - currentTargetPixel.PackFromVector4(pixelValue); + currentTargetPixel.FromVector4(pixelValue); } } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs similarity index 96% rename from src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs rename to src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs index d315875089..86232e306a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs @@ -6,9 +6,9 @@ using SixLabors.ImageSharp.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// - /// Contains the eight matrices used for Kirsh edge detection + /// Contains the eight matrices used for Kirsch edge detection /// - internal static class KirshKernels + internal static class KirschKernels { /// /// Gets the North gradient operator diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs index 46cf00c226..c3188676f3 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs @@ -23,27 +23,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override DenseMatrix North => KirshKernels.KirschNorth; + public override DenseMatrix North => KirschKernels.KirschNorth; /// - public override DenseMatrix NorthWest => KirshKernels.KirschNorthWest; + public override DenseMatrix NorthWest => KirschKernels.KirschNorthWest; /// - public override DenseMatrix West => KirshKernels.KirschWest; + public override DenseMatrix West => KirschKernels.KirschWest; /// - public override DenseMatrix SouthWest => KirshKernels.KirschSouthWest; + public override DenseMatrix SouthWest => KirschKernels.KirschSouthWest; /// - public override DenseMatrix South => KirshKernels.KirschSouth; + public override DenseMatrix South => KirschKernels.KirschSouth; /// - public override DenseMatrix SouthEast => KirshKernels.KirschSouthEast; + public override DenseMatrix SouthEast => KirschKernels.KirschSouthEast; /// - public override DenseMatrix East => KirshKernels.KirschEast; + public override DenseMatrix East => KirschKernels.KirschEast; /// - public override DenseMatrix NorthEast => KirshKernels.KirschNorthEast; + public override DenseMatrix NorthEast => KirschKernels.KirschNorthEast; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs index b407841f20..642da2f001 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffuserBase.cs @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering var offsetColor = pixel.ToVector4(); Vector4 result = ((error * coefficient) / this.divisorVector) + offsetColor; - pixel.PackFromVector4(result); + pixel.FromVector4(result); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index 8e2b2a5a82..911d3e8fdc 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -64,8 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - float threshold = this.Threshold * 255F; - Rgba32 rgba = default; + byte threshold = (byte)MathF.Round(this.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -78,10 +76,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); + Rgba32 rgba = default; sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -104,7 +103,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering } sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index b5e2eebc2b..1b4910a147 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -32,10 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// The ordered ditherer. /// The palette to select substitute colors from. public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette) - : base(palette) - { - this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); - } + : base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither)); /// /// Gets the ditherer. @@ -45,7 +41,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Rgba32 rgba = default; bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); @@ -58,10 +53,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering TPixel sourcePixel = source[startX, startY]; TPixel previousPixel = sourcePixel; PixelPair pair = this.GetClosestPixelPair(ref sourcePixel); + Rgba32 rgba = default; sourcePixel.ToRgba32(ref rgba); // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); for (int y = startY; y < endY; y++) { @@ -84,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering } sourcePixel.ToRgba32(ref rgba); - luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); // Setup the previous pointer previousPixel = sourcePixel; diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs index a1bbe72733..f01865ec05 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// The vector representation of the image palette. /// - private readonly Vector4[] paletteVector; + private Vector4[] paletteVector; /// /// Initializes a new instance of the class. @@ -30,8 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering protected PaletteDitherProcessorBase(TPixel[] palette) { this.Palette = palette ?? throw new ArgumentNullException(nameof(palette)); - this.paletteVector = new Vector4[this.Palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.Palette, this.paletteVector, this.Palette.Length); } /// @@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public TPixel[] Palette { get; } /// - /// Returns the two closest colors from the palette calcluated via Euclidean distance in the Rgba space. + /// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space. /// /// The source color to match. /// The . @@ -90,5 +89,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering return pair; } + + protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + base.BeforeFrameApply(source, sourceRectangle, configuration); + + // Lazy init paletteVector: + if (this.paletteVector == null) + { + this.paletteVector = new Vector4[this.Palette.Length]; + PixelOperations.Instance.ToScaledVector4(configuration, this.Palette, this.paletteVector); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 6ad4dcba97..1b17c470ed 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4( + pixel.FromVector4( new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index e20b42eb7c..d3a44c066e 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters { ref TPixel pixel = ref row[x]; var vector = Vector4.Transform(pixel.ToVector4(), matrix); - pixel.PackFromVector4(vector); + pixel.FromVector4(vector); } } }); diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index e90b352258..580adc7fe9 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization int luminance = this.GetLuminance(sourcePixel, this.LuminanceLevels); float luminanceEqualized = cdf[luminance] / numberOfPixelsMinusCdfMin; - pixels[i].PackFromVector4(new Vector4(luminanceEqualized)); + pixels[i].FromVector4(new Vector4(luminanceEqualized)); } } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 4adddd1536..25787ff922 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, colors.GetSpan(), destination, diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 93d6edff19..21f6be69f8 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 52dade4eff..a8fa1d65c1 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); this.blender.Blend( - source.MemoryAllocator, + source.Configuration, destination, destination, rowColors.GetSpan(), diff --git a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs index 6e594f223e..3b9b046a00 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Collect the palette. Required before the second pass runs. TPixel[] palette = this.GetPalette(); this.paletteVector = new Vector4[palette.Length]; - PixelOperations.Instance.ToScaledVector4(palette, this.paletteVector, palette.Length); + PixelOperations.Instance.ToScaledVector4(image.Configuration, palette, this.paletteVector); var quantizedFrame = new QuantizedFrame(image.MemoryAllocator, width, height, palette); if (this.Dither) @@ -139,8 +139,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization protected byte GetTransparentIndex() { // Transparent pixels are much more likely to be found at the end of a palette. - int index = this.paletteVector.Length - 1; - for (int i = this.paletteVector.Length - 1; i >= 0; i--) + int paletteVectorLengthMinus1 = this.paletteVector.Length - 1; + + int index = paletteVectorLengthMinus1; + for (int i = paletteVectorLengthMinus1; i >= 0; i--) { ref Vector4 candidate = ref this.paletteVector[i]; if (candidate.Equals(default)) diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 3da09cde09..f1490a6d2b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -19,18 +19,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Creates the generic frame quantizer /// + /// The to configure internal operations. /// The pixel format. /// The - IFrameQuantizer CreateFrameQuantizer() + IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel; /// /// Creates the generic frame quantizer /// /// The pixel format. + /// The to configure internal operations. /// The maximum number of colors to hold in the color palette. /// The - IFrameQuantizer CreateFrameQuantizer(int maxColors) + IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 39546d63f7..dd56375f63 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -73,14 +73,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); // And loop through each column - Rgba32 rgba = default; for (int x = 0; x < width; x++) { ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); // Add the color to the Octree - this.octree.AddColor(ref pixel, ref rgba); + this.octree.AddColor(ref pixel); } } } @@ -97,9 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // pass of the algorithm by avoiding transforming rows of identical color. TPixel sourcePixel = source[0, 0]; TPixel previousPixel = sourcePixel; - Rgba32 rgba = default; this.transparentIndex = this.GetTransparentIndex(); - byte pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + byte pixelValue = this.QuantizePixel(ref sourcePixel); TPixel transformedPixel = palette[pixelValue]; for (int y = 0; y < height; y++) @@ -117,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (!previousPixel.Equals(sourcePixel)) { // Quantize the pixel - pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba); + pixelValue = this.QuantizePixel(ref sourcePixel); // And setup the previous pointer previousPixel = sourcePixel; @@ -139,6 +136,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.GetPalette(); + /// protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors); @@ -146,10 +145,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Process the pixel in the second pass of the algorithm. /// /// The pixel to quantize. - /// The color to compare against. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte QuantizePixel(ref TPixel pixel, ref Rgba32 rgba) + private byte QuantizePixel(ref TPixel pixel) { if (this.Dither) { @@ -158,13 +156,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.GetClosestPixel(ref pixel); } + Rgba32 rgba = default; pixel.ToRgba32(ref rgba); if (rgba.Equals(default)) { return this.transparentIndex; } - return (byte)this.octree.GetPaletteIndex(ref pixel, ref rgba); + return (byte)this.octree.GetPaletteIndex(ref pixel); } /// @@ -239,8 +238,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Add a given color value to the Octree /// /// The pixel data. - /// The color. - public void AddColor(ref TPixel pixel, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel) { // Check if this request is for the same color as the last if (this.previousColor.Equals(pixel)) @@ -250,18 +248,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (this.previousNode is null) { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } else { // Just update the previous node - this.previousNode.Increment(ref pixel, ref rgba); + this.previousNode.Increment(ref pixel); } } else { this.previousColor = pixel; - this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba); + this.root.AddColor(ref pixel, this.maxColorBits, 0, this); } } @@ -294,12 +292,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Get the palette index for the passed color /// /// The pixel data. - /// The color to map to. /// /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) => this.root.GetPaletteIndex(ref pixel, 0, ref rgba); + public int GetPaletteIndex(ref TPixel pixel) => this.root.GetPaletteIndex(ref pixel, 0); /// /// Keep track of the previous node that was quantized @@ -426,13 +423,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The number of significant color bits /// The level in the tree /// The tree to which this node belongs - /// The color to map to. - public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree, ref Rgba32 rgba) + public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree) { // Update the color information if this is a leaf if (this.leaf) { - this.Increment(ref pixel, ref rgba); + this.Increment(ref pixel); // Setup the previous node octree.TrackPrevious(this); @@ -441,6 +437,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization { // Go to the next level down in the tree int shift = 7 - level; + Rgba32 rgba = default; pixel.ToRgba32(ref rgba); int index = ((rgba.B & Mask[level]) >> (shift - 2)) @@ -456,7 +453,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } // Add the color to the child node - child.AddColor(ref pixel, colorBits, level + 1, octree, ref rgba); + child.AddColor(ref pixel, colorBits, level + 1, octree); } } @@ -504,7 +501,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Set the color of the palette entry var vector = Vector3.Clamp(new Vector3(this.red, this.green, this.blue) / this.pixelCount, Vector3.Zero, new Vector3(255)); TPixel pixel = default; - pixel.PackFromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); + pixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); palette[index] = pixel; // Consume the next palette index @@ -525,18 +522,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The pixel data. /// The level. - /// The color to map to. /// /// The representing the index of the pixel in the palette. /// [MethodImpl(MethodImplOptions.NoInlining)] - public int GetPaletteIndex(ref TPixel pixel, int level, ref Rgba32 rgba) + public int GetPaletteIndex(ref TPixel pixel, int level) { int index = this.paletteIndex; if (!this.leaf) { int shift = 7 - level; + Rgba32 rgba = default; pixel.ToRgba32(ref rgba); int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2)) @@ -546,7 +543,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization OctreeNode child = this.children[pixelIndex]; if (child != null) { - index = child.GetPaletteIndex(ref pixel, level + 1, ref rgba); + index = child.GetPaletteIndex(ref pixel, level + 1); } else { @@ -561,10 +558,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Increment the pixel count and add to the color information /// /// The pixel to add. - /// The color to map to. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Increment(ref TPixel pixel, ref Rgba32 rgba) + public void Increment(ref TPixel pixel) { + Rgba32 rgba = default; pixel.ToRgba32(ref rgba); this.pixelCount++; this.red += rgba.R; diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 22bb5223f0..d49023886b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -15,11 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class OctreeQuantizer : IQuantizer { - /// - /// The default maximum number of colors to use when quantizing the image. - /// - public const int DefaultMaxColors = 256; - /// /// Initializes a new instance of the class. /// @@ -42,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public OctreeQuantizer(bool dither) - : this(GetDiffuser(dither), DefaultMaxColors) + : this(GetDiffuser(dither), QuantizerConstants.MaxColors) { } @@ -51,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The error diffusion algorithm, if any, to apply to the output image public OctreeQuantizer(IErrorDiffuser diffuser) - : this(diffuser, DefaultMaxColors) + : this(diffuser, QuantizerConstants.MaxColors) { } @@ -63,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public OctreeQuantizer(IErrorDiffuser diffuser, int maxColors) { this.Diffuser = diffuser; - this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); + this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); } /// @@ -74,16 +69,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new OctreeFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { - maxColors = maxColors.Clamp(1, DefaultMaxColors); + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); return new OctreeFrameQuantizer(this, maxColors); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index cdf3514e2d..f8a19f8c40 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; @@ -23,26 +22,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// private readonly TPixel[] palette; - /// - /// The vector representation of the image palette. - /// - private readonly Vector4[] paletteVector; - /// /// Initializes a new instance of the class. /// /// The palette quantizer. /// An array of all colors in the palette. - public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) - : base(quantizer, true) - { - // TODO: Why is this value constrained? Gif has limitations but theoretically - // we might want to reduce the palette of an image to greater than that limitation. - Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); - this.palette = colors; - this.paletteVector = new Vector4[this.palette.Length]; - PixelOperations.Instance.ToScaledVector4(this.palette, this.paletteVector, this.palette.Length); - } + public PaletteFrameQuantizer(IQuantizer quantizer, TPixel[] colors) + : base(quantizer, true) => this.palette = colors; /// protected override void SecondPass( diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 27ef05dfe9..6b2be3d038 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -8,18 +8,18 @@ using SixLabors.ImageSharp.Processing.Processors.Dithering; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { /// - /// Allows the quantization of images pixels using web safe colors defined in the CSS Color Module Level 4. - /// Override this class to provide your own palette. + /// Allows the quantization of images pixels using color palettes. + /// Override this class to provide your own palette. /// - /// By default the quantizer uses dithering and the + /// By default the quantizer uses dithering. /// /// - public class PaletteQuantizer : IQuantizer + public abstract class PaletteQuantizer : IQuantizer { /// /// Initializes a new instance of the class. /// - public PaletteQuantizer() + protected PaletteQuantizer() : this(true) { } @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// Whether to apply dithering to the output image - public PaletteQuantizer(bool dither) + protected PaletteQuantizer(bool dither) : this(GetDiffuser(dither)) { } @@ -37,41 +37,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// The error diffusion algorithm, if any, to apply to the output image - public PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; + protected PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; /// public IErrorDiffuser Diffuser { get; } /// - public virtual IFrameQuantizer CreateFrameQuantizer() - where TPixel : struct, IPixel - => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + public abstract IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + where TPixel : struct, IPixel; /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public abstract IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + where TPixel : struct, IPixel; + + /// + /// Creates the generic frame quantizer. + /// + /// The pixel format. + /// The to configure internal operations. + /// The color palette. + /// The maximum number of colors to hold in the color palette. + /// The + protected IFrameQuantizer CreateFrameQuantizer(Configuration configuration, TPixel[] palette, int maxColors) where TPixel : struct, IPixel { - TPixel[] websafe = NamedColors.WebSafePalette; - int max = Math.Min(maxColors, websafe.Length); + int max = Math.Min(QuantizerConstants.MaxColors, Math.Min(maxColors, palette.Length)); - if (max != websafe.Length) + if (max != palette.Length) { - return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + return new PaletteFrameQuantizer(this, palette.AsSpan(0, max).ToArray()); } - return this.CreateFrameQuantizer(() => websafe); + return new PaletteFrameQuantizer(this, palette); } - /// - /// Gets the palette to use to quantize the image. - /// - /// The pixel format. - /// The method to return the palette. - /// The - public IFrameQuantizer CreateFrameQuantizer(Func paletteFunction) - where TPixel : struct, IPixel - => new PaletteFrameQuantizer(this, paletteFunction.Invoke()); - private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs new file mode 100644 index 0000000000..a350adfc0c --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -0,0 +1,110 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A generic palette quantizer. + /// + /// The pixel format. + public class PaletteQuantizer : IQuantizer + where TPixel : struct, IPixel + { + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + public PaletteQuantizer(TPixel[] palette) + : this(palette, true) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + /// Whether to apply dithering to the output image + public PaletteQuantizer(TPixel[] palette, bool dither) + : this(palette, GetDiffuser(dither)) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color palette to use. + /// The error diffusion algorithm, if any, to apply to the output image + public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser) + { + Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette)); + this.Palette = palette; + this.Diffuser = diffuser; + } + + /// + public IErrorDiffuser Diffuser { get; } + + /// + /// Gets the palette. + /// + public TPixel[] Palette { get; } + + /// + /// Creates the generic frame quantizer. + /// + /// The to configure internal operations. + /// The . + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + => ((IQuantizer)this).CreateFrameQuantizer(configuration); + + /// + /// Creates the generic frame quantizer. + /// + /// The to configure internal operations. + /// The maximum number of colors to hold in the color palette. + /// The . + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + => ((IQuantizer)this).CreateFrameQuantizer(configuration, maxColors); + + /// + IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration) + { + if (!typeof(TPixel).Equals(typeof(TPixel1))) + { + throw new InvalidOperationException("Generic method type must be the same as class type."); + } + + TPixel[] paletteRef = this.Palette; + return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef)); + } + + /// + IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration, int maxColors) + { + if (!typeof(TPixel).Equals(typeof(TPixel1))) + { + throw new InvalidOperationException("Generic method type must be the same as class type."); + } + + TPixel[] paletteRef = this.Palette; + TPixel1[] castPalette = Unsafe.As(ref paletteRef); + + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); + int max = Math.Min(maxColors, castPalette.Length); + + if (max != castPalette.Length) + { + return new PaletteFrameQuantizer(this, castPalette.AsSpan(0, max).ToArray()); + } + + return new PaletteFrameQuantizer(this, castPalette); + } + + private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index bd5a6e9ec7..8da89bf94a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(); + IFrameQuantizer executor = this.Quantizer.CreateFrameQuantizer(configuration); using (QuantizedFrame quantized = executor.QuantizeFrame(source)) { int paletteCount = quantized.Palette.Length - 1; diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs new file mode 100644 index 0000000000..d79a91c301 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// Contains color quantization specific constants. + /// + internal static class QuantizerConstants + { + /// + /// The minimum number of colors to use when quantizing an image. + /// + public const int MinColors = 1; + + /// + /// The maximum number of colors to use when quantizing an image. + /// + public const int MaxColors = 256; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs new file mode 100644 index 0000000000..93630a9166 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A palette quantizer consisting of web safe colors as defined in the CSS Color Module Level 4. + /// + public class WebSafePaletteQuantizer : PaletteQuantizer + { + /// + /// Initializes a new instance of the class. + /// + public WebSafePaletteQuantizer() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Whether to apply dithering to the output image + public WebSafePaletteQuantizer(bool dither) + : base(dither) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error diffusion algorithm, if any, to apply to the output image + public WebSafePaletteQuantizer(IErrorDiffuser diffuser) + : base(diffuser) + { + } + + /// + public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + => this.CreateFrameQuantizer(configuration, NamedColors.WebSafePalette.Length); + + /// + public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + => this.CreateFrameQuantizer(configuration, NamedColors.WebSafePalette, maxColors); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs new file mode 100644 index 0000000000..2ff9f5090c --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Dithering; + +namespace SixLabors.ImageSharp.Processing.Processors.Quantization +{ + /// + /// A palette quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821. + /// The hex codes were collected and defined by Nicholas Rougeux + /// + public class WernerPaletteQuantizer : PaletteQuantizer + { + /// + /// Initializes a new instance of the class. + /// + public WernerPaletteQuantizer() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Whether to apply dithering to the output image + public WernerPaletteQuantizer(bool dither) + : base(dither) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The error diffusion algorithm, if any, to apply to the output image + public WernerPaletteQuantizer(IErrorDiffuser diffuser) + : base(diffuser) + { + } + + /// + public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration) + => this.CreateFrameQuantizer(configuration, NamedColors.WernerPalette.Length); + + /// + public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) + => this.CreateFrameQuantizer(configuration, NamedColors.WernerPalette, maxColors); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 13bc057da8..44df226cfd 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -173,6 +173,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + internal TPixel[] AotGetPalette() => this.GetPalette(); + /// protected override TPixel[] GetPalette() { @@ -199,7 +201,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization float a = Volume(ref this.colorCube[k], vmaSpan); ref TPixel color = ref this.palette[k]; - color.PackFromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); + color.FromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); } } } @@ -442,33 +444,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization // Build up the 3-D color histogram // Loop through each row - for (int y = 0; y < height; y++) + using (IMemoryOwner rgbaBuffer = source.MemoryAllocator.Allocate(source.Width)) { - Span row = source.GetPixelRowSpan(y); - ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); - - // And loop through each column - Rgba32 rgba = default; - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); + Span row = source.GetPixelRowSpan(y); + Span rgbaSpan = rgbaBuffer.GetSpan(); + PixelOperations.Instance.ToRgba32(source.Configuration, row, rgbaSpan); + ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan); + + // And loop through each column + for (int x = 0; x < width; x++) + { + ref Rgba32 rgba = ref Unsafe.Add(ref scanBaseRef, x); - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); - int a = rgba.A >> (8 - IndexAlphaBits); + int r = rgba.R >> (8 - IndexBits); + int g = rgba.G >> (8 - IndexBits); + int b = rgba.B >> (8 - IndexBits); + int a = rgba.A >> (8 - IndexAlphaBits); - int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); + int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); - vwtSpan[index]++; - vmrSpan[index] += rgba.R; - vmgSpan[index] += rgba.G; - vmbSpan[index] += rgba.B; - vmaSpan[index] += rgba.A; + vwtSpan[index]++; + vmrSpan[index] += rgba.R; + vmgSpan[index] += rgba.G; + vmbSpan[index] += rgba.B; + vmaSpan[index] += rgba.A; - var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); - m2Span[index] += Vector4.Dot(vector, vector); + var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); + m2Span[index] += Vector4.Dot(vector, vector); + } } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 5123e737d3..eb8b0fec91 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class WuQuantizer : IQuantizer { - /// - /// The default maximum number of colors to use when quantizing the image. - /// - public const int DefaultMaxColors = 256; - /// /// Initializes a new instance of the class. /// @@ -41,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public WuQuantizer(bool dither) - : this(GetDiffuser(dither), DefaultMaxColors) + : this(GetDiffuser(dither), QuantizerConstants.MaxColors) { } @@ -50,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The error diffusion algorithm, if any, to apply to the output image public WuQuantizer(IErrorDiffuser diffuser) - : this(diffuser, DefaultMaxColors) + : this(diffuser, QuantizerConstants.MaxColors) { } @@ -62,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public WuQuantizer(IErrorDiffuser diffuser, int maxColors) { this.Diffuser = diffuser; - this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); + this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); } /// @@ -73,16 +68,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public int MaxColors { get; } + /// /// - public IFrameQuantizer CreateFrameQuantizer() + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration) where TPixel : struct, IPixel => new WuFrameQuantizer(this); /// - public IFrameQuantizer CreateFrameQuantizer(int maxColors) + public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors) where TPixel : struct, IPixel { - maxColors = maxColors.Clamp(1, DefaultMaxColors); + maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors); return new WuFrameQuantizer(this, maxColors); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 790eb80482..5a3b5943b7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -5,13 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -20,29 +16,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides the base methods to perform affine transforms on an image. /// /// The pixel format. - internal class AffineTransformProcessor : InterpolatedTransformProcessorBase + internal class AffineTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// - /// The transform matrix + /// The transform matrix. /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. + /// The target dimensions. public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) { + Guard.NotNull(sampler, nameof(sampler)); + this.Sampler = sampler; this.TransformMatrix = matrix; this.TargetDimensions = targetDimensions; } /// - /// Gets the matrix used to supply the affine transform + /// Gets the sampler to perform interpolation of the transform operation. + /// + public IResampler Sampler { get; } + + /// + /// Gets the matrix used to supply the affine transform. /// public Matrix3x2 TransformMatrix { get; } /// - /// Gets the target dimensions to constrain the transformed image to + /// Gets the target dimensions to constrain the transformed image to. /// public Size TargetDimensions { get; } @@ -64,17 +66,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Rectangle sourceRectangle, Configuration configuration) { - int height = this.TargetDimensions.Height; - int width = this.TargetDimensions.Width; - - Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); + // Handle tranforms that result in output identical to the original. + if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix3x2.Identity)) + { + // The clone will be blank here copy all the pixel data over + source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); + return; + } - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + int width = this.TargetDimensions.Width; + var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. - Matrix3x2.Invert(matrix, out matrix); + Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 matrix); if (this.Sampler is NearestNeighborResampler) { @@ -82,158 +86,57 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms targetBounds, configuration, rows => + { + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destRow = destination.GetPixelRowSpan(y); + Span destRow = destination.GetPixelRowSpan(y); - for (int x = 0; x < width; x++) + for (int x = 0; x < width; x++) + { + var point = Point.Transform(new Point(x, y), matrix); + if (sourceRectangle.Contains(point.X, point.Y)) { - var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) - { - destRow[x] = source[point.X, point.Y]; - } + destRow[x] = source[point.X, point.Y]; } } - }); + } + }); return; } - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler); + try { - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( targetBounds, configuration, - rows => + (rows, vectorBuffer) => + { + Span vectorSpan = vectorBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + ref float ySpanRef = ref kernel.GetYStartReference(y); + ref float xSpanRef = ref kernel.GetXStartReference(y); - for (int x = 0; x < width; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var point = Vector2.Transform(new Vector2(x, y), matrix); - - // Clamp sampling pixel radial extents to the source image edges - Vector2 maxXY = point + radius; - Vector2 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); - - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; - - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } - - // It appears these have to be calculated on-the-fly. - // Precalculating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown( - top, - bottom, - minY, - maxY, - point.Y, - sampler, - yScale, - ref ySpanRef, - yLength); - - CalculateWeightsDown( - left, - right, - minX, - maxX, - point.X, - sampler, - xScale, - ref xSpanRef, - xLength); - } - else - { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } - - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); - - for (int xx = 0, i = minX; i <= maxX; i++, xx++) - { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - - // Values are first premultiplied to prevent darkening of edge pixels - var current = source[i, j].ToVector4(); - Vector4Utils.Premultiply(ref current); - sum += current * xWeight * yWeight; - } - } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); - - // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); - dest.PackFromVector4(sum); - } + for (int x = 0; x < width; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var point = Vector2.Transform(new Vector2(x, y), matrix); + kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); } - }); + + PixelOperations.Instance.FromVector4(configuration, vectorSpan, targetRowSpan); + } + }); + } + finally + { + kernel.Dispose(); } } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs deleted file mode 100644 index adaee17665..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// A base class that provides methods to allow the automatic centering of affine transforms - /// - /// The pixel format. - internal abstract class CenteredAffineTransformProcessor : AffineTransformProcessor - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The source image size - protected CenteredAffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size sourceSize) - : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix)) - { - } - - /// - protected override Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - => TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix); - - private static Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix) - { - var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height); - return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs deleted file mode 100644 index 962b9e4c9d..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// A base class that provides methods to allow the automatic centering of non-affine transforms - /// - /// The pixel format. - internal abstract class CenteredProjectiveTransformProcessor : ProjectiveTransformProcessor - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The transform matrix - /// The sampler to perform the transform operation. - /// The source image size - protected CenteredProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size sourceSize) - : base(matrix, sampler, GetTransformedDimensions(sourceSize, matrix)) - { - } - - /// - protected override Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - { - return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix); - } - - private static Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix) - { - var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height); - return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix).Size; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs deleted file mode 100644 index c1abb4a5e1..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/InterpolatedTransformProcessorBase.cs +++ /dev/null @@ -1,117 +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.Processing.Processors.Transforms -{ - /// - /// The base class for performing interpolated affine and non-affine transforms. - /// - /// The pixel format. - internal abstract class InterpolatedTransformProcessorBase : TransformProcessorBase - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The sampler to perform the transform operation. - protected InterpolatedTransformProcessorBase(IResampler sampler) - { - Guard.NotNull(sampler, nameof(sampler)); - this.Sampler = sampler; - } - - /// - /// Gets the sampler to perform interpolation of the transform operation. - /// - public IResampler Sampler { get; } - - /// - /// Calculated the weights for the given point. - /// This method uses more samples than the upscaled version to ensure edge pixels are correctly rendered. - /// Additionally the weights are normalized. - /// - /// The minimum sampling offset - /// The maximum sampling offset - /// The minimum source bounds - /// The maximum source bounds - /// The transformed point dimension - /// The sampler - /// The transformed image scale relative to the source - /// The reference to the collection of weights - /// The length of the weights collection - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, ref float weightsRef, int length) - { - float sum = 0; - - // Downsampling weights requires more edge sampling plus normalization of the weights - for (int x = 0, i = min; i <= max; i++, x++) - { - int index = i; - if (index < sourceMin) - { - index = sourceMin; - } - - if (index > sourceMax) - { - index = sourceMax; - } - - float weight = sampler.GetValue((index - point) / scale); - sum += weight; - Unsafe.Add(ref weightsRef, x) = weight; - } - - if (sum > 0) - { - for (int i = 0; i < length; i++) - { - ref float wRef = ref Unsafe.Add(ref weightsRef, i); - wRef = wRef / sum; - } - } - } - - /// - /// Calculated the weights for the given point. - /// - /// The minimum source bounds - /// The maximum source bounds - /// The transformed point dimension - /// The sampler - /// The reference to the collection of weights - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected static void CalculateWeightsScaleUp(int sourceMin, int sourceMax, float point, IResampler sampler, ref float weightsRef) - { - for (int x = 0, i = sourceMin; i <= sourceMax; i++, x++) - { - float weight = sampler.GetValue(i - point); - Unsafe.Add(ref weightsRef, x) = weight; - } - } - - /// - /// Calculates the sampling radius for the current sampler - /// - /// The source dimension size - /// The destination dimension size - /// The radius, and scaling factor - protected (float radius, float scale, float ratio) GetSamplingRadius(int sourceSize, int destinationSize) - { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; - - if (scale < 1F) - { - scale = 1F; - } - - return (MathF.Ceiling(scale * this.Sampler.Radius), scale, ratio); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs deleted file mode 100644 index 277be53fff..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs +++ /dev/null @@ -1,130 +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.Memory; -using SixLabors.Memory; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Holds the values in an optimized contigous memory region. - /// - internal class KernelMap : IDisposable - { - private readonly Buffer2D data; - - /// - /// Initializes a new instance of the class. - /// - /// The to use for allocations. - /// The size of the destination window - /// The radius of the kernel - public KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) - { - int width = (int)Math.Ceiling(kernelRadius * 2); - this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); - this.Kernels = new ResizeKernel[destinationSize]; - } - - /// - /// Gets the calculated values. - /// - public ResizeKernel[] Kernels { get; } - - /// - /// Disposes instance releasing it's backing buffer. - /// - public void Dispose() - { - this.data.Dispose(); - } - - /// - /// Computes the weights to apply at each pixel when resizing. - /// - /// The - /// The destination size - /// The source size - /// The to use for buffer allocations - /// The - public static KernelMap Calculate( - IResampler sampler, - int destinationSize, - int sourceSize, - MemoryAllocator memoryAllocator) - { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; - - if (scale < 1F) - { - scale = 1F; - } - - float radius = MathF.Ceiling(scale * sampler.Radius); - var result = new KernelMap(memoryAllocator, destinationSize, radius); - - for (int i = 0; i < destinationSize; i++) - { - float center = ((i + .5F) * ratio) - .5F; - - // Keep inside bounds. - int left = (int)MathF.Ceiling(center - radius); - if (left < 0) - { - left = 0; - } - - int right = (int)MathF.Floor(center + radius); - if (right > sourceSize - 1) - { - right = sourceSize - 1; - } - - float sum = 0; - - ResizeKernel ws = result.CreateKernel(i, left, right); - result.Kernels[i] = ws; - - ref float weightsBaseRef = ref ws.GetStartReference(); - - for (int j = left; j <= right; j++) - { - float weight = sampler.GetValue((j - center) / scale); - sum += weight; - - // weights[j - left] = weight: - Unsafe.Add(ref weightsBaseRef, j - left) = weight; - } - - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) - { - for (int w = 0; w < ws.Length; w++) - { - // weights[w] = weights[w] / sum: - ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); - wRef /= sum; - } - } - } - - return result; - } - - /// - /// Slices a weights value at the given positions. - /// - /// The index in destination buffer - /// The local left index value - /// The local right index value - /// The weights - private ResizeKernel CreateKernel(int destIdx, int leftIdx, int rightIdx) - { - return new ResizeKernel(destIdx, leftIdx, this.data, rightIdx - leftIdx + 1); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index bad8eab3af..98d488a420 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -5,13 +5,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -20,22 +16,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides the base methods to perform non-affine transforms on an image. /// /// The pixel format. - internal class ProjectiveTransformProcessor : InterpolatedTransformProcessorBase + internal class ProjectiveTransformProcessor : TransformProcessorBase where TPixel : struct, IPixel { /// /// Initializes a new instance of the class. /// - /// The transform matrix + /// The transform matrix. /// The sampler to perform the transform operation. - /// The target dimensions to constrain the transformed image to. + /// The target dimensions. public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions) - : base(sampler) { + Guard.NotNull(sampler, nameof(sampler)); + this.Sampler = sampler; this.TransformMatrix = matrix; this.TargetDimensions = targetDimensions; } + /// + /// Gets the sampler to perform interpolation of the transform operation. + /// + public IResampler Sampler { get; } + /// /// Gets the matrix used to supply the projective transform /// @@ -60,17 +62,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// protected override void OnFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { - int height = this.TargetDimensions.Height; - int width = this.TargetDimensions.Width; - - Rectangle sourceBounds = source.Bounds(); - var targetBounds = new Rectangle(0, 0, width, height); + // Handle tranforms that result in output identical to the original. + if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix4x4.Identity)) + { + // The clone will be blank here copy all the pixel data over + source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); + return; + } - // Since could potentially be resizing the canvas we might need to re-calculate the matrix - Matrix4x4 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); + int width = this.TargetDimensions.Width; + var targetBounds = new Rectangle(Point.Empty, this.TargetDimensions); // Convert from screen to world space. - Matrix4x4.Invert(matrix, out matrix); + Matrix4x4.Invert(this.TransformMatrix, out Matrix4x4 matrix); const float Epsilon = 0.0000001F; if (this.Sampler is NearestNeighborResampler) @@ -92,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int px = (int)MathF.Round(v3.X / z); int py = (int)MathF.Round(v3.Y / z); - if (sourceBounds.Contains(px, py)) + if (sourceRectangle.Contains(px, py)) { destRow[x] = source[px, py]; } @@ -103,145 +107,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - int maxSourceX = source.Width - 1; - int maxSourceY = source.Height - 1; - (float radius, float scale, float ratio) xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); - (float radius, float scale, float ratio) yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); - float xScale = xRadiusScale.scale; - float yScale = yRadiusScale.scale; - - // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: - var radius = new Vector4(xRadiusScale.radius, yRadiusScale.radius, 0, 0); - - IResampler sampler = this.Sampler; - var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); - int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); - int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); - - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - - using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) - using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) + var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.Sampler); + try { - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( targetBounds, configuration, - rows => + (rows, vectorBuffer) => + { + Span vectorSpan = vectorBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - - for (int x = 0; x < width; x++) - { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); - float z = MathF.Max(v3.Z, Epsilon); - - // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: - Vector4 point = new Vector4(v3.X, v3.Y, 0, 0) / z; - - // Clamp sampling pixel radial extents to the source image edges - Vector4 maxXY = point + radius; - Vector4 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + ref float ySpanRef = ref kernel.GetYStartReference(y); + ref float xSpanRef = ref kernel.GetXStartReference(y); - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; - - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } - - // It appears these have to be calculated on-the-fly. - // Precalulating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown( - top, - bottom, - minY, - maxY, - point.Y, - sampler, - yScale, - ref ySpanRef, - yLength); - - CalculateWeightsDown( - left, - right, - minX, - maxX, - point.X, - sampler, - xScale, - ref xSpanRef, - xLength); - } - else - { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } - - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); - - for (int xx = 0, i = minX; i <= maxX; i++, xx++) - { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - - // Values are first premultiplied to prevent darkening of edge pixels - var current = source[i, j].ToVector4(); - Vector4Utils.Premultiply(ref current); - sum += current * xWeight * yWeight; - } - } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); + for (int x = 0; x < width; x++) + { + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var v3 = Vector3.Transform(new Vector3(x, y, 1F), matrix); + Vector2 point = new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); - // Reverse the premultiplication - Vector4Utils.UnPremultiply(ref sum); - dest.PackFromVector4(sum); - } + kernel.Convolve(point, x, ref ySpanRef, ref xSpanRef, source.PixelBuffer, vectorSpan); } - }); + + PixelOperations.Instance.FromVector4(configuration, vectorSpan, targetRowSpan); + } + }); + } + finally + { + kernel.Dispose(); } } - - /// - /// Gets a transform matrix adjusted for final processing based upon the target image bounds. - /// - /// The source image bounds. - /// The destination image bounds. - /// - /// The . - /// - protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs b/src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs similarity index 100% rename from src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs similarity index 51% rename from src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs index cc3c204534..f349634ac0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs @@ -2,82 +2,62 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Points to a collection of of weights allocated in . + /// Points to a collection of of weights allocated in . /// - internal struct ResizeKernel + internal readonly unsafe struct ResizeKernel { - /// - /// The local left index position - /// - public int Left; - - /// - /// The length of the weights window - /// - public int Length; - - /// - /// The buffer containing the weights values. - /// - private readonly Memory buffer; + private readonly float* bufferPtr; /// /// Initializes a new instance of the struct. /// - /// The destination index in the buffer - /// The local left index - /// The span - /// The length of the window [MethodImpl(InliningOptions.ShortMethod)] - internal ResizeKernel(int index, int left, Buffer2D buffer, int length) + internal ResizeKernel(int left, float* bufferPtr, int length) { - int flatStartIndex = index * buffer.Width; this.Left = left; - this.buffer = buffer.MemorySource.Memory.Slice(flatStartIndex, length); + this.bufferPtr = bufferPtr; this.Length = length; } /// - /// Gets a reference to the first item of the window. + /// Gets the left index for the destination row /// - /// The reference to the first item of the window - [MethodImpl(InliningOptions.ShortMethod)] - public ref float GetStartReference() - { - Span span = this.buffer.Span; - return ref span[0]; - } + public int Left { get; } /// - /// Gets the span representing the portion of the that this window covers + /// Gets the the length of the kernel /// - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public Span GetSpan() => this.buffer.Span; + public int Length { get; } + + /// + /// Gets the span representing the portion of the that this window covers + /// + /// The + /// + public Span Values + { + [MethodImpl(InliningOptions.ShortMethod)] + get => new Span(this.bufferPtr, this.Length); + } /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. /// /// The input span of vectors - /// The source row position. /// The weighted sum [MethodImpl(InliningOptions.ShortMethod)] - public Vector4 Convolve(Span rowSpan, int sourceX) + public Vector4 Convolve(Span rowSpan) { - ref float horizontalValues = ref this.GetStartReference(); + ref float horizontalValues = ref Unsafe.AsRef(this.bufferPtr); int left = this.Left; - ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left + sourceX); + ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left); // Destination color components Vector4 result = Vector4.Zero; @@ -91,5 +71,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } + + /// + /// Copy the contents of altering + /// to the value . + /// + internal ResizeKernel AlterLeftValue(int left) + { + return new ResizeKernel(left, this.bufferPtr, this.Length); + } + + internal void Fill(Span values) + { + DebugGuard.IsTrue(values.Length == this.Length, nameof(values), "ResizeKernel.Fill: values.Length != this.Length!"); + + for (int i = 0; i < this.Length; i++) + { + this.Values[i] = (float)values[i]; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs new file mode 100644 index 0000000000..4b81aaa64e --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.PeriodicKernelMap.cs @@ -0,0 +1,81 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains + /// + internal partial class ResizeKernelMap + { + /// + /// Memory-optimized where repeating rows are stored only once. + /// + private sealed class PeriodicKernelMap : ResizeKernelMap + { + private readonly int period; + + private readonly int cornerInterval; + + public PeriodicKernelMap( + MemoryAllocator memoryAllocator, + IResampler sampler, + int sourceLength, + int destinationLength, + double ratio, + double scale, + int radius, + int period, + int cornerInterval) + : base( + memoryAllocator, + sampler, + sourceLength, + destinationLength, + (cornerInterval * 2) + period, + ratio, + scale, + radius) + { + this.cornerInterval = cornerInterval; + this.period = period; + } + + internal override string Info => base.Info + $"|period:{this.period}|cornerInterval:{this.cornerInterval}"; + + protected override void Initialize() + { + // Build top corner data + one period of the mosaic data: + int startOfFirstRepeatedMosaic = this.cornerInterval + this.period; + + for (int i = 0; i < startOfFirstRepeatedMosaic; i++) + { + ResizeKernel kernel = this.BuildKernel(i, i); + this.kernels[i] = kernel; + } + + // Copy the mosaics: + int bottomStartDest = this.DestinationLength - this.cornerInterval; + for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) + { + double center = ((i + .5) * this.ratio) - .5; + int left = (int)TolerantMath.Ceiling(center - this.radius); + ResizeKernel kernel = this.kernels[i - this.period]; + this.kernels[i] = kernel.AlterLeftValue(left); + } + + // Build bottom corner data: + int bottomStartData = this.cornerInterval + this.period; + for (int i = 0; i < this.cornerInterval; i++) + { + ResizeKernel kernel = this.BuildKernel(bottomStartDest + i, bottomStartData + i); + this.kernels[bottomStartDest + i] = kernel; + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs new file mode 100644 index 0000000000..2ab574df2a --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -0,0 +1,247 @@ +// 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; + +using SixLabors.ImageSharp.Memory; +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Provides values from an optimized, + /// contiguous memory region. + /// + internal partial class ResizeKernelMap : IDisposable + { + private static readonly TolerantMath TolerantMath = TolerantMath.Default; + + private readonly IResampler sampler; + + private readonly int sourceLength; + + private readonly double ratio; + + private readonly double scale; + + private readonly int radius; + + private readonly MemoryHandle pinHandle; + + private readonly Buffer2D data; + + private readonly ResizeKernel[] kernels; + + // To avoid both GC allocations, and MemoryAllocator ceremony: + private readonly double[] tempValues; + + private ResizeKernelMap( + MemoryAllocator memoryAllocator, + IResampler sampler, + int sourceLength, + int destinationLength, + int bufferHeight, + double ratio, + double scale, + int radius) + { + this.sampler = sampler; + this.ratio = ratio; + this.scale = scale; + this.radius = radius; + this.sourceLength = sourceLength; + this.DestinationLength = destinationLength; + int maxWidth = (radius * 2) + 1; + this.data = memoryAllocator.Allocate2D(maxWidth, bufferHeight, AllocationOptions.Clean); + this.pinHandle = this.data.Memory.Pin(); + this.kernels = new ResizeKernel[destinationLength]; + this.tempValues = new double[maxWidth]; + } + + /// + /// Gets the length of the destination row/column + /// + public int DestinationLength { get; } + + /// + /// Gets a string of information to help debugging + /// + internal virtual string Info => + $"radius:{this.radius}|sourceSize:{this.sourceLength}|destinationSize:{this.DestinationLength}|ratio:{this.ratio}|scale:{this.scale}"; + + /// + /// Disposes instance releasing it's backing buffer. + /// + public void Dispose() + { + this.pinHandle.Dispose(); + this.data.Dispose(); + } + + /// + /// Returns a for an index value between 0 and DestinationSize - 1. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; + + /// + /// Computes the weights to apply at each pixel when resizing. + /// + /// The + /// The destination size + /// The source size + /// The to use for buffer allocations + /// The + public static ResizeKernelMap Calculate( + IResampler sampler, + int destinationSize, + int sourceSize, + MemoryAllocator memoryAllocator) + { + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; + + if (scale < 1) + { + scale = 1; + } + + int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); + + // 'ratio' is a rational number. + // Multiplying it by LCM(sourceSize, destSize)/sourceSize will result in a whole number "again". + // This value is determining the length of the periods in repeating kernel map rows. + int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; + + // the center position at i == 0: + double center0 = (ratio - 1) * 0.5; + double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; + + // The number of rows building a "stairway" at the top and the bottom of the kernel map + // corresponding to the corners of the image. + // If we do not normalize the kernel values, these rows also fit the periodic logic, + // however, it's just simpler to calculate them separately. + int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); + + // If firstNonNegativeLeftVal was an integral value, we need firstNonNegativeLeftVal+1 + // instead of Ceiling: + if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) + { + cornerInterval++; + } + + // If 'cornerInterval' is too big compared to 'period', we can't apply the periodic optimization. + // If we don't have at least 2 periods, we go with the basic implementation: + bool hasAtLeast2Periods = 2 * (cornerInterval + period) < destinationSize; + + ResizeKernelMap result = hasAtLeast2Periods + ? new PeriodicKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + ratio, + scale, + radius, + period, + cornerInterval) + : new ResizeKernelMap( + memoryAllocator, + sampler, + sourceSize, + destinationSize, + destinationSize, + ratio, + scale, + radius); + + result.Initialize(); + + return result; + } + + protected virtual void Initialize() + { + for (int i = 0; i < this.DestinationLength; i++) + { + ResizeKernel kernel = this.BuildKernel(i, i); + this.kernels[i] = kernel; + } + } + + /// + /// Builds a for the row (in ) + /// referencing the data at row within , + /// so the data reusable by other data rows. + /// + private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex) + { + double center = ((destRowIndex + .5) * this.ratio) - .5; + + // Keep inside bounds. + int left = (int)TolerantMath.Ceiling(center - this.radius); + if (left < 0) + { + left = 0; + } + + int right = (int)TolerantMath.Floor(center + this.radius); + if (right > this.sourceLength - 1) + { + right = this.sourceLength - 1; + } + + ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right); + + Span kernelValues = this.tempValues.AsSpan().Slice(0, kernel.Length); + double sum = 0; + + for (int j = left; j <= right; j++) + { + double value = this.sampler.GetValue((float)((j - center) / this.scale)); + sum += value; + + kernelValues[j - left] = value; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) + { + for (int j = 0; j < kernel.Length; j++) + { + // weights[w] = weights[w] / sum: + ref double kRef = ref kernelValues[j]; + kRef /= sum; + } + } + + kernel.Fill(kernelValues); + + return kernel; + } + + /// + /// Returns a referencing values of + /// at row . + /// + private unsafe ResizeKernel CreateKernel(int dataRowIndex, int left, int right) + { + int length = right - left + 1; + + if (length > this.data.Width) + { + throw new InvalidOperationException( + $"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width"); + } + + Span rowSpan = this.data.GetRowSpan(dataRowIndex); + + ref float rowReference = ref MemoryMarshal.GetReference(rowSpan); + float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); + return new ResizeKernel(left, rowPtr, length); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs similarity index 94% rename from src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 812c0578b2..189e21de7a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -27,8 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms where TPixel : struct, IPixel { // The following fields are not immutable but are optionally created on demand. - private KernelMap horizontalKernelMap; - private KernelMap verticalKernelMap; + private ResizeKernelMap horizontalKernelMap; + private ResizeKernelMap verticalKernelMap; /// /// Initializes a new instance of the class. @@ -165,13 +165,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // Since all image frame dimensions have to be the same we can calculate this for all frames. MemoryAllocator memoryAllocator = source.GetMemoryAllocator(); - this.horizontalKernelMap = KernelMap.Calculate( + this.horizontalKernelMap = ResizeKernelMap.Calculate( this.Sampler, this.ResizeRectangle.Width, sourceRectangle.Width, memoryAllocator); - this.verticalKernelMap = KernelMap.Calculate( + this.verticalKernelMap = ResizeKernelMap.Calculate( this.Sampler, this.ResizeRectangle.Height, sourceRectangle.Height, @@ -254,10 +254,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.Span; + Span sourceRow = source.GetPixelRowSpan(y).Slice(sourceX); + Span tempRowSpan = tempRowBuffer.Span.Slice(sourceX); - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); + PixelOperations.Instance.ToVector4(configuration, sourceRow, tempRowSpan); Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; @@ -269,9 +269,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = minX; x < maxX; x++) { - ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; + ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - startX); Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.Convolve(tempRowSpan, sourceX); + kernel.Convolve(tempRowSpan); } } }); @@ -289,16 +289,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int y = rows.Min; y < rows.Max; y++) { // Ensure offsets are normalized for cropping and padding. - ResizeKernel window = this.verticalKernelMap.Kernels[y - startY]; + ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY); ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempRowSpan); for (int x = 0; x < width; x++) { - Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); + Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY); // Destination color components - Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn, sourceY); + Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn); } Vector4Utils.UnPremultiply(tempRowSpan); @@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.PackFromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); + PixelOperations.Instance.FromVector4(configuration, tempRowSpan, targetRowSpan); } }); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 2ad626755c..69ecf59215 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -2,12 +2,12 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Threading.Tasks; +using System.Numerics; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides methods that allow the rotating of images. /// /// The pixel format. - internal class RotateProcessor : CenteredAffineTransformProcessor + internal class RotateProcessor : AffineTransformProcessor where TPixel : struct, IPixel { /// @@ -36,9 +36,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the rotating operation. /// The source image size public RotateProcessor(float degrees, IResampler sampler, Size sourceSize) - : base(Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty), sampler, sourceSize) + : this( + TransformUtils.CreateRotationMatrixDegrees(degrees, sourceSize), + sampler, + sourceSize) + => this.Degrees = degrees; + + // Helper constructor + private RotateProcessor(Matrix3x2 rotationMatrix, IResampler sampler, Size sourceSize) + : base(rotationMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, rotationMatrix)) { - this.Degrees = degrees; } /// @@ -84,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The private static float WrapDegrees(float degrees) { - degrees = degrees % 360; + degrees %= 360; while (degrees < 0) { @@ -223,7 +230,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int newX = height - y - 1; for (int x = 0; x < width; x++) { - // TODO: Optimize this: if (destinationBounds.Contains(newX, x)) { destination[newX, x] = sourceRow[x]; diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index a0cfa63794..c7b1d74104 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -1,8 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Numerics; + using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -11,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Provides methods that allow the skewing of images. /// /// The pixel format. - internal class SkewProcessor : CenteredAffineTransformProcessor + internal class SkewProcessor : AffineTransformProcessor where TPixel : struct, IPixel { /// @@ -33,12 +34,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The sampler to perform the skew operation. /// The source image size public SkewProcessor(float degreesX, float degreesY, IResampler sampler, Size sourceSize) - : base(Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty), sampler, sourceSize) + : this( + TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, sourceSize), + sampler, + sourceSize) { this.DegreesX = degreesX; this.DegreesY = degreesY; } + // Helper constructor: + private SkewProcessor(Matrix3x2 skewMatrix, IResampler sampler, Size sourceSize) + : base(skewMatrix, sampler, TransformUtils.GetTransformedSize(sourceSize, skewMatrix)) + { + } + /// /// Gets the angle of rotation along the x-axis in degrees. /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs deleted file mode 100644 index b22fa64cfd..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformHelpers.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.MetaData.Profiles.Exif; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Contains helper methods for working with affine and non-affine transforms - /// - internal static class TransformHelpers - { - /// - /// Updates the dimensional metadata of a transformed image - /// - /// The pixel format. - /// The image to update - public static void UpdateDimensionalMetData(Image image) - where TPixel : struct, IPixel - { - ExifProfile profile = image.MetaData.ExifProfile; - if (profile is null) - { - return; - } - - // Removing the previously stored value allows us to set a value with our own data tag if required. - if (profile.GetValue(ExifTag.PixelXDimension) != null) - { - profile.RemoveValue(ExifTag.PixelXDimension); - - if (image.Width <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); - } - else - { - profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); - } - } - - if (profile.GetValue(ExifTag.PixelYDimension) != null) - { - profile.RemoveValue(ExifTag.PixelYDimension); - - if (image.Height <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); - } - else - { - profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); - } - } - } - - /// - /// Gets the centered transform matrix based upon the source and destination rectangles - /// - /// The source image bounds. - /// The destination image bounds. - /// The transformation matrix. - /// The - public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) - { - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix3x2.Invert(matrix, out Matrix3x2 inverted); - - var translationToTargetCenter = Matrix3x2.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F); - var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F); - - Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); - - // Translate back to world to pass to the Transform method. - return centered; - } - - /// - /// Gets the centered transform matrix based upon the source and destination rectangles - /// - /// The source image bounds. - /// The destination image bounds. - /// The transformation matrix. - /// The - public static Matrix4x4 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix4x4 matrix) - { - // We invert the matrix to handle the transformation from screen to world space. - // This ensures scaling matrices are correct. - Matrix4x4.Invert(matrix, out Matrix4x4 inverted); - - var translationToTargetCenter = Matrix4x4.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F, 0); - var translateToSourceCenter = Matrix4x4.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F, 0); - - Matrix4x4.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix4x4 centered); - - // Translate back to world to pass to the Transform method. - return centered; - } - - /// - /// Returns the bounding rectangle relative to the source for the given transformation matrix. - /// - /// The source rectangle. - /// The transformation matrix. - /// - /// The . - /// - public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) - { - // Calculate the position of the four corners in world space by applying - // The world matrix to the four corners in object space (0, 0, width, height) - var tl = Vector2.Transform(Vector2.Zero, matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix); - var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix); - - return GetBoundingRectangle(tl, tr, bl, br); - } - - /// - /// Returns the bounding rectangle relative to the source for the given transformation matrix. - /// - /// The source rectangle. - /// The transformation matrix. - /// - /// The . - /// - public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix4x4 matrix) - { - // Calculate the position of the four corners in world space by applying - // The world matrix to the four corners in object space (0, 0, width, height) - var tl = Vector2.Transform(Vector2.Zero, matrix); - var tr = Vector2.Transform(new Vector2(rectangle.Width, 0), matrix); - var bl = Vector2.Transform(new Vector2(0, rectangle.Height), matrix); - var br = Vector2.Transform(new Vector2(rectangle.Width, rectangle.Height), matrix); - - return GetBoundingRectangle(tl, tr, bl, br); - } - - private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) - { - // Find the minimum and maximum "corners" based on the given vectors - float minX = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X))); - float maxX = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X))); - float minY = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y))); - float maxY = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y))); - float sizeX = maxX - minX + .5F; - float sizeY = maxY - minY + .5F; - - return new Rectangle((int)(MathF.Ceiling(minX) - .5F), (int)(MathF.Ceiling(minY) - .5F), (int)MathF.Floor(sizeX), (int)MathF.Floor(sizeY)); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs new file mode 100644 index 0000000000..573120888f --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformKernelMap.cs @@ -0,0 +1,161 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains the methods required to calculate transform kernel convolution. + /// + internal class TransformKernelMap : IDisposable + { + private readonly Buffer2D yBuffer; + private readonly Buffer2D xBuffer; + private readonly Vector2 extents; + private Vector4 maxSourceExtents; + private readonly IResampler sampler; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration. + /// The source size. + /// The destination size. + /// The sampler. + public TransformKernelMap(Configuration configuration, Size source, Size destination, IResampler sampler) + { + this.sampler = sampler; + float yRadius = this.GetSamplingRadius(source.Height, destination.Height); + float xRadius = this.GetSamplingRadius(source.Width, destination.Width); + + this.extents = new Vector2(xRadius, yRadius); + int xLength = (int)MathF.Ceiling((this.extents.X * 2) + 2); + int yLength = (int)MathF.Ceiling((this.extents.Y * 2) + 2); + + // We use 2D buffers so that we can access the weight spans per row in parallel. + this.yBuffer = configuration.MemoryAllocator.Allocate2D(yLength, destination.Height); + this.xBuffer = configuration.MemoryAllocator.Allocate2D(xLength, destination.Height); + + int maxX = source.Width - 1; + int maxY = source.Height - 1; + this.maxSourceExtents = new Vector4(maxX, maxY, maxX, maxY); + } + + /// + /// Gets a reference to the first item of the y window. + /// + /// The reference to the first item of the window. + [MethodImpl(InliningOptions.ShortMethod)] + public ref float GetYStartReference(int y) + => ref MemoryMarshal.GetReference(this.yBuffer.GetRowSpan(y)); + + /// + /// Gets a reference to the first item of the x window. + /// + /// The reference to the first item of the window. + [MethodImpl(InliningOptions.ShortMethod)] + public ref float GetXStartReference(int y) + => ref MemoryMarshal.GetReference(this.xBuffer.GetRowSpan(y)); + + public void Convolve( + Vector2 transformedPoint, + int column, + ref float ySpanRef, + ref float xSpanRef, + Buffer2D sourcePixels, + Span targetRow) + where TPixel : struct, IPixel + { + // Clamp sampling pixel radial extents to the source image edges + Vector2 minXY = transformedPoint - this.extents; + Vector2 maxXY = transformedPoint + this.extents; + + // left, top, right, bottom + var extents = new Vector4( + MathF.Ceiling(minXY.X - .5F), + MathF.Ceiling(minXY.Y - .5F), + MathF.Floor(maxXY.X + .5F), + MathF.Floor(maxXY.Y + .5F)); + + extents = Vector4.Clamp(extents, Vector4.Zero, this.maxSourceExtents); + + int left = (int)extents.X; + int top = (int)extents.Y; + int right = (int)extents.Z; + int bottom = (int)extents.W; + + if (left == right || top == bottom) + { + return; + } + + this.CalculateWeights(top, bottom, transformedPoint.Y, ref ySpanRef); + this.CalculateWeights(left, right, transformedPoint.X, ref xSpanRef); + + Vector4 sum = Vector4.Zero; + for (int kernelY = 0, y = top; y <= bottom; y++, kernelY++) + { + float yWeight = Unsafe.Add(ref ySpanRef, kernelY); + + for (int kernelX = 0, x = left; x <= right; x++, kernelX++) + { + float xWeight = Unsafe.Add(ref xSpanRef, kernelX); + + // Values are first premultiplied to prevent darkening of edge pixels. + var current = sourcePixels[x, y].ToVector4(); + Vector4Utils.Premultiply(ref current); + sum += current * xWeight * yWeight; + } + } + + // Reverse the premultiplication + Vector4Utils.UnPremultiply(ref sum); + targetRow[column] = sum; + } + + /// + /// Calculated the normalized weights for the given point. + /// + /// The minimum sampling offset + /// The maximum sampling offset + /// The transformed point dimension + /// The reference to the collection of weights + [MethodImpl(InliningOptions.ShortMethod)] + private void CalculateWeights(int min, int max, float point, ref float weightsRef) + { + float sum = 0; + for (int x = 0, i = min; i <= max; i++, x++) + { + float weight = this.sampler.GetValue(i - point); + sum += weight; + Unsafe.Add(ref weightsRef, x) = weight; + } + } + + [MethodImpl(InliningOptions.ShortMethod)] + private float GetSamplingRadius(int sourceSize, int destinationSize) + { + float scale = (float)sourceSize / destinationSize; + + if (scale < 1F) + { + scale = 1F; + } + + return MathF.Ceiling(scale * this.sampler.Radius); + } + + public void Dispose() + { + this.yBuffer?.Dispose(); + this.xBuffer?.Dispose(); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs index 13ee90a062..4973b90f46 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorBase.cs @@ -16,6 +16,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// protected override void AfterImageApply(Image source, Image destination, Rectangle sourceRectangle) - => TransformHelpers.UpdateDimensionalMetData(destination); + => TransformProcessorHelpers.UpdateDimensionalMetData(destination); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs new file mode 100644 index 0000000000..f5536d0467 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData.Profiles.Exif; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains helper methods for working with transforms. + /// + internal static class TransformProcessorHelpers + { + /// + /// Updates the dimensional metadata of a transformed image + /// + /// The pixel format. + /// The image to update + public static void UpdateDimensionalMetData(Image image) + where TPixel : struct, IPixel + { + ExifProfile profile = image.MetaData.ExifProfile; + if (profile is null) + { + return; + } + + // Removing the previously stored value allows us to set a value with our own data tag if required. + if (profile.GetValue(ExifTag.PixelXDimension) != null) + { + profile.RemoveValue(ExifTag.PixelXDimension); + + if (image.Width <= ushort.MaxValue) + { + profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); + } + else + { + profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); + } + } + + if (profile.GetValue(ExifTag.PixelYDimension) != null) + { + profile.RemoveValue(ExifTag.PixelYDimension); + + if (image.Height <= ushort.MaxValue) + { + profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); + } + else + { + profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); + } + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs new file mode 100644 index 0000000000..24b15d3098 --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformUtils.cs @@ -0,0 +1,332 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Contains utility methods for working with transforms. + /// + internal static class TransformUtils + { + /// + /// Creates a centered rotation matrix using the given rotation in degrees and the source size. + /// + /// The amount of rotation, in degrees. + /// The source image size. + /// The . + public static Matrix3x2 CreateRotationMatrixDegrees(float degrees, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotationDegrees(degrees, PointF.Empty)); + + /// + /// Creates a centered rotation matrix using the given rotation in radians and the source size. + /// + /// The amount of rotation, in radians. + /// The source image size. + /// The . + public static Matrix3x2 CreateRotationMatrixRadians(float radians, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateRotation(radians, PointF.Empty)); + + /// + /// Creates a centered skew matrix from the give angles in degrees and the source size. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The source image size. + /// The . + public static Matrix3x2 CreateSkewMatrixDegrees(float degreesX, float degreesY, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkewDegrees(degreesX, degreesY, PointF.Empty)); + + /// + /// Creates a centered skew matrix from the give angles in radians and the source size. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The source image size. + /// The . + public static Matrix3x2 CreateSkewMatrixRadians(float radiansX, float radiansY, Size size) + => CreateCenteredTransformMatrix( + new Rectangle(Point.Empty, size), + Matrix3x2Extensions.CreateSkew(radiansX, radiansY, PointF.Empty)); + + /// + /// Gets the centered transform matrix based upon the source and destination rectangles. + /// + /// The source image bounds. + /// The transformation matrix. + /// The + public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) + { + Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); + + // We invert the matrix to handle the transformation from screen to world space. + // This ensures scaling matrices are correct. + Matrix3x2.Invert(matrix, out Matrix3x2 inverted); + + var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); + var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); + + // Translate back to world space. + Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); + + return centered; + } + + /// + /// Creates a matrix that performs a tapering projective transform. + /// + /// + /// The rectangular size of the image being transformed. + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The + public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner corner, float fraction) + { + Matrix4x4 matrix = Matrix4x4.Identity; + + switch (side) + { + case TaperSide.Left: + matrix.M11 = fraction; + matrix.M22 = fraction; + matrix.M13 = (fraction - 1) / size.Width; + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M12 = size.Height * matrix.M13; + matrix.M32 = size.Height * (1 - fraction); + break; + + case TaperCorner.Both: + matrix.M12 = size.Height * .5F * matrix.M13; + matrix.M32 = size.Height * (1 - fraction) / 2; + break; + } + + break; + + case TaperSide.Top: + matrix.M11 = fraction; + matrix.M22 = fraction; + matrix.M23 = (fraction - 1) / size.Height; + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M21 = size.Width * matrix.M23; + matrix.M31 = size.Width * (1 - fraction); + break; + + case TaperCorner.Both: + matrix.M21 = size.Width * .5F * matrix.M23; + matrix.M31 = size.Width * (1 - fraction) / 2; + break; + } + + break; + + case TaperSide.Right: + matrix.M11 = 1 / fraction; + matrix.M13 = (1 - fraction) / (size.Width * fraction); + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M12 = size.Height * matrix.M13; + break; + + case TaperCorner.Both: + matrix.M12 = size.Height * .5F * matrix.M13; + break; + } + + break; + + case TaperSide.Bottom: + matrix.M22 = 1 / fraction; + matrix.M23 = (1 - fraction) / (size.Height * fraction); + + switch (corner) + { + case TaperCorner.RightOrBottom: + break; + + case TaperCorner.LeftOrTop: + matrix.M21 = size.Width * matrix.M23; + break; + + case TaperCorner.Both: + matrix.M21 = size.Width * .5F * matrix.M23; + break; + } + + break; + } + + return matrix; + } + + /// + /// Returns the rectangle bounds relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedBoundingRectangle(Rectangle rectangle, Matrix3x2 matrix) + { + Rectangle transformed = GetTransformedRectangle(rectangle, matrix); + return new Rectangle(0, 0, transformed.Width, transformed.Height); + } + + /// + /// Returns the rectangle relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix3x2 matrix) + { + if (rectangle.Equals(default) || Matrix3x2.Identity.Equals(matrix)) + { + return rectangle; + } + + var tl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Top), matrix); + var tr = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Top), matrix); + var bl = Vector2.Transform(new Vector2(rectangle.Left, rectangle.Bottom), matrix); + var br = Vector2.Transform(new Vector2(rectangle.Right, rectangle.Bottom), matrix); + + return GetBoundingRectangle(tl, tr, bl, br); + } + + /// + /// Returns the size relative to the source for the given transformation matrix. + /// + /// The source size. + /// The transformation matrix. + /// + /// The . + /// + public static Size GetTransformedSize(Size size, Matrix3x2 matrix) + { + Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); + + if (matrix.Equals(default) || matrix.Equals(Matrix3x2.Identity)) + { + return size; + } + + Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + + return ConstrainSize(rectangle); + } + + /// + /// Returns the rectangle relative to the source for the given transformation matrix. + /// + /// The source rectangle. + /// The transformation matrix. + /// + /// The . + /// + public static Rectangle GetTransformedRectangle(Rectangle rectangle, Matrix4x4 matrix) + { + if (rectangle.Equals(default) || Matrix4x4.Identity.Equals(matrix)) + { + return rectangle; + } + + Vector2 GetVector(float x, float y) + { + const float Epsilon = 0.0000001F; + var v3 = Vector3.Transform(new Vector3(x, y, 1F), matrix); + return new Vector2(v3.X, v3.Y) / MathF.Max(v3.Z, Epsilon); + } + + Vector2 tl = GetVector(rectangle.Left, rectangle.Top); + Vector2 tr = GetVector(rectangle.Right, rectangle.Top); + Vector2 bl = GetVector(rectangle.Left, rectangle.Bottom); + Vector2 br = GetVector(rectangle.Right, rectangle.Bottom); + + return GetBoundingRectangle(tl, tr, bl, br); + } + + /// + /// Returns the size relative to the source for the given transformation matrix. + /// + /// The source size. + /// The transformation matrix. + /// + /// The . + /// + public static Size GetTransformedSize(Size size, Matrix4x4 matrix) + { + Guard.IsTrue(size.Width > 0 && size.Height > 0, nameof(size), "Source size dimensions cannot be 0!"); + + if (matrix.Equals(default) || matrix.Equals(Matrix4x4.Identity)) + { + return size; + } + + Rectangle rectangle = GetTransformedRectangle(new Rectangle(Point.Empty, size), matrix); + + return ConstrainSize(rectangle); + } + + private static Size ConstrainSize(Rectangle rectangle) + { + // We want to resize the canvas here taking into account any translations. + int height = rectangle.Top < 0 ? rectangle.Bottom : Math.Max(rectangle.Height, rectangle.Bottom); + int width = rectangle.Left < 0 ? rectangle.Right : Math.Max(rectangle.Width, rectangle.Right); + + // If location in either direction is translated to a negative value equal to or exceeding the + // dimensions in eith direction we need to reassign the dimension. + if (height <= 0) + { + height = rectangle.Height; + } + + if (width <= 0) + { + width = rectangle.Width; + } + + return new Size(width, height); + } + + private static Rectangle GetBoundingRectangle(Vector2 tl, Vector2 tr, Vector2 bl, Vector2 br) + { + // Find the minimum and maximum "corners" based on the given vectors + float left = MathF.Min(tl.X, MathF.Min(tr.X, MathF.Min(bl.X, br.X))); + float top = MathF.Min(tl.Y, MathF.Min(tr.Y, MathF.Min(bl.Y, br.Y))); + float right = MathF.Max(tl.X, MathF.Max(tr.X, MathF.Max(bl.X, br.X))); + float bottom = MathF.Max(tl.Y, MathF.Max(tr.Y, MathF.Max(bl.Y, br.Y))); + + return Rectangle.Round(RectangleF.FromLTRB(left, top, right, bottom)); + } + } +} diff --git a/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs new file mode 100644 index 0000000000..c29941d071 --- /dev/null +++ b/src/ImageSharp/Processing/ProjectiveTransformBuilder.cs @@ -0,0 +1,319 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A helper class for constructing instances for use in projective transforms. + /// + public class ProjectiveTransformBuilder + { + private readonly List> matrixFactories = new List>(); + + /// + /// Prepends a matrix that performs a tapering projective transform. + /// + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The . + public ProjectiveTransformBuilder PrependTaper(TaperSide side, TaperCorner corner, float fraction) + => this.Prepend(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); + + /// + /// Appends a matrix that performs a tapering projective transform. + /// + /// An enumeration that indicates the side of the rectangle that tapers. + /// An enumeration that indicates on which corners to taper the rectangle. + /// The amount to taper. + /// The . + public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction) + => this.Append(size => TransformUtils.CreateTaperMatrix(size, side, corner, fraction)); + + /// + /// Prepends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder PrependRotationDegrees(float degrees) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + + /// + /// Prepends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public ProjectiveTransformBuilder PrependRotationRadians(float radians) + => this.Prepend(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); + + /// + /// Prepends a centered rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder PrependRotationDegrees(float degrees, Vector2 origin) + => this.PrependRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Prepends a centered rotation matrix using the given rotation in radians at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder PrependRotationRadians(float radians, Vector2 origin) + => this.PrependMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(origin, 0))); + + /// + /// Appends a centered rotation matrix using the given rotation in degrees. + /// + /// The amount of rotation, in degrees. + /// The . + public ProjectiveTransformBuilder AppendRotationDegrees(float degrees) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees)); + + /// + /// Appends a centered rotation matrix using the given rotation in radians. + /// + /// The amount of rotation, in radians. + /// The . + public ProjectiveTransformBuilder AppendRotationRadians(float radians) + => this.Append(size => new Matrix4x4(TransformUtils.CreateRotationMatrixRadians(radians, size))); + + /// + /// Appends a centered rotation matrix using the given rotation in degrees at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder AppendRotationDegrees(float degrees, Vector2 origin) + => this.AppendRotationRadians(GeometryUtilities.DegreeToRadian(degrees), origin); + + /// + /// Appends a centered rotation matrix using the given rotation in radians at the given origin. + /// + /// The amount of rotation, in radians. + /// The rotation origin point. + /// The . + internal ProjectiveTransformBuilder AppendRotationRadians(float radians, Vector2 origin) + => this.AppendMatrix(Matrix4x4.CreateRotationZ(radians, new Vector3(origin, 0))); + + /// + /// Prepends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder PrependScale(float scale) + => this.PrependMatrix(Matrix4x4.CreateScale(scale)); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(SizeF scale) + => this.PrependScale((Vector2)scale); + + /// + /// Prepends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder PrependScale(Vector2 scales) + => this.PrependMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); + + /// + /// Appends a scale matrix from the given uniform scale. + /// + /// The uniform scale. + /// The . + public ProjectiveTransformBuilder AppendScale(float scale) + => this.AppendMatrix(Matrix4x4.CreateScale(scale)); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder AppendScale(SizeF scales) + => this.AppendScale((Vector2)scales); + + /// + /// Appends a scale matrix from the given vector scale. + /// + /// The horizontal and vertical scale. + /// The . + public ProjectiveTransformBuilder AppendScale(Vector2 scales) + => this.AppendMatrix(Matrix4x4.CreateScale(new Vector3(scales, 1F))); + + /// + /// Prepends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + internal ProjectiveTransformBuilder PrependSkewDegrees(float degreesX, float degreesY) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); + + /// + /// Prepends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY) + => this.Prepend(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + + /// + /// Prepends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder PrependSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.PrependSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Prepends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder PrependSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.PrependMatrix(new Matrix4x4(Matrix3x2.CreateSkew(radiansX, radiansY, origin))); + + /// + /// Appends a centered skew matrix from the give angles in degrees. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The . + internal ProjectiveTransformBuilder AppendSkewDegrees(float degreesX, float degreesY) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY)); + + /// + /// Appends a centered skew matrix from the give angles in radians. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The . + public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY) + => this.Append(size => new Matrix4x4(TransformUtils.CreateSkewMatrixRadians(radiansX, radiansY, size))); + + /// + /// Appends a skew matrix using the given angles in degrees at the given origin. + /// + /// The X angle, in degrees. + /// The Y angle, in degrees. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder AppendSkewDegrees(float degreesX, float degreesY, Vector2 origin) + => this.AppendSkewRadians(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), origin); + + /// + /// Appends a skew matrix using the given angles in radians at the given origin. + /// + /// The X angle, in radians. + /// The Y angle, in radians. + /// The skew origin point. + /// The . + public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY, Vector2 origin) + => this.AppendMatrix(new Matrix4x4(Matrix3x2.CreateSkew(radiansX, radiansY, origin))); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(PointF position) + => this.PrependTranslation((Vector2)position); + + /// + /// Prepends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder PrependTranslation(Vector2 position) + => this.PrependMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder AppendTranslation(PointF position) + => this.AppendTranslation((Vector2)position); + + /// + /// Appends a translation matrix from the given vector. + /// + /// The translation position. + /// The . + public ProjectiveTransformBuilder AppendTranslation(Vector2 position) + => this.AppendMatrix(Matrix4x4.CreateTranslation(new Vector3(position, 0))); + + /// + /// Prepends a raw matrix. + /// + /// The matrix to prepend. + /// The . + public ProjectiveTransformBuilder PrependMatrix(Matrix4x4 matrix) => this.Prepend(_ => matrix); + + /// + /// Appends a raw matrix. + /// + /// The matrix to append. + /// The . + public ProjectiveTransformBuilder AppendMatrix(Matrix4x4 matrix) => this.Append(_ => matrix); + + /// + /// Returns the combined matrix for a given source size. + /// + /// The source image size. + /// The . + public Matrix4x4 BuildMatrix(Size sourceSize) => this.BuildMatrix(new Rectangle(Point.Empty, sourceSize)); + + /// + /// Returns the combined matrix for a given source rectangle. + /// + /// The rectangle in the source image. + /// The . + public Matrix4x4 BuildMatrix(Rectangle sourceRectangle) + { + Guard.MustBeGreaterThan(sourceRectangle.Width, 0, nameof(sourceRectangle)); + Guard.MustBeGreaterThan(sourceRectangle.Height, 0, nameof(sourceRectangle)); + + // Translate the origin matrix to cater for source rectangle offsets. + var matrix = Matrix4x4.CreateTranslation(new Vector3(-sourceRectangle.Location, 0)); + + Size size = sourceRectangle.Size; + + foreach (Func factory in this.matrixFactories) + { + matrix *= factory(size); + } + + return matrix; + } + + private ProjectiveTransformBuilder Prepend(Func factory) + { + this.matrixFactories.Insert(0, factory); + return this; + } + + private ProjectiveTransformBuilder Append(Func factory) + { + this.matrixFactories.Add(factory); + return this; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/ProjectiveTransformHelper.cs b/src/ImageSharp/Processing/ProjectiveTransformHelper.cs deleted file mode 100644 index 4057ec586c..0000000000 --- a/src/ImageSharp/Processing/ProjectiveTransformHelper.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing -{ - /// - /// Enumerates the various options which determine which side to taper - /// - public enum TaperSide - { - /// - /// Taper the left side - /// - Left, - - /// - /// Taper the top side - /// - Top, - - /// - /// Taper the right side - /// - Right, - - /// - /// Taper the bottom side - /// - Bottom - } - - /// - /// Enumerates the various options which determine how to taper corners - /// - public enum TaperCorner - { - /// - /// Taper the left or top corner - /// - LeftOrTop, - - /// - /// Taper the right or bottom corner - /// - RightOrBottom, - - /// - /// Taper the both sets of corners - /// - Both - } - - /// - /// Provides helper methods for working with generalized projective transforms. - /// - public static class ProjectiveTransformHelper - { - /// - /// Creates a matrix that performs a tapering projective transform. - /// - /// - /// The rectangular size of the image being transformed. - /// An enumeration that indicates the side of the rectangle that tapers. - /// An enumeration that indicates on which corners to taper the rectangle. - /// The amount to taper. - /// The - public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide taperSide, TaperCorner taperCorner, float taperFraction) - { - Matrix4x4 matrix = Matrix4x4.Identity; - - switch (taperSide) - { - case TaperSide.Left: - matrix.M11 = taperFraction; - matrix.M22 = taperFraction; - matrix.M13 = (taperFraction - 1) / size.Width; - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M12 = size.Height * matrix.M13; - matrix.M32 = size.Height * (1 - taperFraction); - break; - - case TaperCorner.Both: - matrix.M12 = (size.Height * 0.5f) * matrix.M13; - matrix.M32 = size.Height * (1 - taperFraction) / 2; - break; - } - - break; - - case TaperSide.Top: - matrix.M11 = taperFraction; - matrix.M22 = taperFraction; - matrix.M23 = (taperFraction - 1) / size.Height; - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M21 = size.Width * matrix.M23; - matrix.M31 = size.Width * (1 - taperFraction); - break; - - case TaperCorner.Both: - matrix.M21 = (size.Width * 0.5f) * matrix.M23; - matrix.M31 = size.Width * (1 - taperFraction) / 2; - break; - } - - break; - - case TaperSide.Right: - matrix.M11 = 1 / taperFraction; - matrix.M13 = (1 - taperFraction) / (size.Width * taperFraction); - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M12 = size.Height * matrix.M13; - break; - - case TaperCorner.Both: - matrix.M12 = (size.Height * 0.5f) * matrix.M13; - break; - } - - break; - - case TaperSide.Bottom: - matrix.M22 = 1 / taperFraction; - matrix.M23 = (1 - taperFraction) / (size.Height * taperFraction); - - switch (taperCorner) - { - case TaperCorner.RightOrBottom: - break; - - case TaperCorner.LeftOrTop: - matrix.M21 = size.Width * matrix.M23; - break; - - case TaperCorner.Both: - matrix.M21 = (size.Width * 0.5f) * matrix.M23; - break; - } - - break; - } - - return matrix; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/ResizeHelper.cs index b9233937b1..3ae632162f 100644 --- a/src/ImageSharp/Processing/ResizeHelper.cs +++ b/src/ImageSharp/Processing/ResizeHelper.cs @@ -333,25 +333,21 @@ namespace SixLabors.ImageSharp.Processing return (new Size(sourceWidth, sourceWidth), new Rectangle(0, 0, sourceWidth, sourceHeight)); } - // Fractional variants for preserving aspect ratio. - float percentHeight = MathF.Abs(height / (float)sourceHeight); - float percentWidth = MathF.Abs(width / (float)sourceWidth); - - float sourceRatio = (float)sourceHeight / sourceWidth; - // Find the shortest distance to go. int widthDiff = sourceWidth - width; int heightDiff = sourceHeight - height; if (widthDiff < heightDiff) { + float sourceRatio = (float)sourceHeight / sourceWidth; destinationHeight = (int)MathF.Round(width * sourceRatio); height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationWidth = (int)MathF.Round(height / sourceRatio); + float sourceRatioInverse = (float)sourceWidth / sourceHeight; + destinationWidth = (int)MathF.Round(height * sourceRatioInverse); destinationHeight = height; width = destinationWidth; } @@ -360,12 +356,14 @@ namespace SixLabors.ImageSharp.Processing if (height > width) { destinationWidth = width; + float percentWidth = MathF.Abs(width / (float)sourceWidth); destinationHeight = (int)MathF.Round(sourceHeight * percentWidth); height = destinationHeight; } else { destinationHeight = height; + float percentHeight = MathF.Abs(height / (float)sourceHeight); destinationWidth = (int)MathF.Round(sourceWidth * percentHeight); width = destinationWidth; } diff --git a/src/ImageSharp/Processing/TaperCorner.cs b/src/ImageSharp/Processing/TaperCorner.cs new file mode 100644 index 0000000000..395b171424 --- /dev/null +++ b/src/ImageSharp/Processing/TaperCorner.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Enumerates the various options which determine how to taper corners + /// + public enum TaperCorner + { + /// + /// Taper the left or top corner + /// + LeftOrTop, + + /// + /// Taper the right or bottom corner + /// + RightOrBottom, + + /// + /// Taper the both sets of corners + /// + Both + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TaperSide.cs b/src/ImageSharp/Processing/TaperSide.cs new file mode 100644 index 0000000000..226d11aed2 --- /dev/null +++ b/src/ImageSharp/Processing/TaperSide.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Enumerates the various options which determine which side to taper + /// + public enum TaperSide + { + /// + /// Taper the left side + /// + Left, + + /// + /// Taper the top side + /// + Top, + + /// + /// Taper the right side + /// + Right, + + /// + /// Taper the bottom side + /// + Bottom + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/TransformExtensions.cs b/src/ImageSharp/Processing/TransformExtensions.cs index 0ec1e295d9..db14b6baf9 100644 --- a/src/ImageSharp/Processing/TransformExtensions.cs +++ b/src/ImageSharp/Processing/TransformExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Numerics; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; @@ -14,109 +15,147 @@ namespace SixLabors.ImageSharp.Processing public static class TransformExtensions { /// - /// Transforms an image by the given matrix. + /// Performs an affine transform of an image. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. + /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + AffineTransformBuilder builder) where TPixel : struct, IPixel - => Transform(source, matrix, KnownResamplers.Bicubic); + => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Transforms an image by the given matrix using the specified sampling algorithm. + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The . + /// The affine transform builder. /// The to perform the resampling. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix, IResampler sampler) + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + AffineTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(matrix, sampler, source.GetCurrentSize())); + => ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); /// - /// Transforms an image by the given matrix using the specified sampling algorithm - /// and a rectangle defining the transform origin in the source image and the size of the result image. + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The . + /// The source rectangle + /// The affine transform builder. /// The to perform the resampling. - /// - /// The rectangle defining the transform origin in the source image, and the size of the result image. - /// /// The public static IImageProcessingContext Transform( - this IImageProcessingContext source, - Matrix3x2 matrix, - IResampler sampler, - Rectangle rectangle) + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + AffineTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel { - var t = Matrix3x2.CreateTranslation(-rectangle.Location); - Matrix3x2 combinedMatrix = t * matrix; - return source.ApplyProcessor(new AffineTransformProcessor(combinedMatrix, sampler, rectangle.Size)); + Matrix3x2 transform = builder.BuildMatrix(sourceRectangle); + Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler); } /// - /// Transforms an image by the given matrix using the specified sampling algorithm, - /// cropping or extending the image according to . + /// Performs an affine transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The . + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. /// The to perform the resampling. - /// The size of the destination image. /// The public static IImageProcessingContext Transform( - this IImageProcessingContext source, - Matrix3x2 matrix, - IResampler sampler, - Size destinationSize) + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + Matrix3x2 transform, + Size targetDimensions, + IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new AffineTransformProcessor(matrix, sampler, destinationSize)); + { + return ctx.ApplyProcessor( + new AffineTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); + } /// - /// Transforms an image by the given matrix. + /// Performs a projective transform of an image. /// /// The pixel format. /// The image to transform. - /// The transformation matrix. + /// The affine transform builder. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix) + public static IImageProcessingContext Transform( + this IImageProcessingContext source, + ProjectiveTransformBuilder builder) where TPixel : struct, IPixel - => Transform(source, matrix, KnownResamplers.Bicubic); + => Transform(source, builder, KnownResamplers.Bicubic); /// - /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. + /// Performs a projective transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The . + /// The projective transform builder. /// The to perform the resampling. /// The - public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler) + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + ProjectiveTransformBuilder builder, + IResampler sampler) where TPixel : struct, IPixel - => source.ApplyProcessor(new ProjectiveTransformProcessor(matrix, sampler, source.GetCurrentSize())); + => ctx.Transform(new Rectangle(Point.Empty, ctx.GetCurrentSize()), builder, sampler); /// - /// Applies a projective transform to the image by the given matrix using the specified sampling algorithm. - /// TODO: Should we be offsetting the matrix here? + /// Performs a projective transform of an image using the specified sampling algorithm. /// /// The pixel format. - /// The image to transform. - /// The transformation matrix. + /// The . + /// The source rectangle + /// The projective transform builder. /// The to perform the resampling. - /// The rectangle to constrain the transformed image to. /// The - internal static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler, Rectangle rectangle) + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + ProjectiveTransformBuilder builder, + IResampler sampler) + where TPixel : struct, IPixel + { + Matrix4x4 transform = builder.BuildMatrix(sourceRectangle); + Size targetDimensions = TransformUtils.GetTransformedSize(sourceRectangle.Size, transform); + return ctx.Transform(sourceRectangle, transform, targetDimensions, sampler); + } + + /// + /// Performs a projective transform of an image using the specified sampling algorithm. + /// + /// The pixel format. + /// The . + /// The source rectangle + /// The transformation matrix. + /// The size of the result image. + /// The to perform the resampling. + /// The + public static IImageProcessingContext Transform( + this IImageProcessingContext ctx, + Rectangle sourceRectangle, + Matrix4x4 transform, + Size targetDimensions, + IResampler sampler) where TPixel : struct, IPixel { - var t = Matrix4x4.CreateTranslation(new Vector3(-rectangle.Location, 0)); - Matrix4x4 combinedMatrix = t * matrix; - return source.ApplyProcessor(new ProjectiveTransformProcessor(combinedMatrix, sampler, rectangle.Size)); + return ctx.ApplyProcessor( + new ProjectiveTransformProcessor(transform, sampler, targetDimensions), + sourceRectangle); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs index 12e74ccdbb..89eb63d629 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public void GifCore() { // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; using (var memoryStream = new MemoryStream()) { this.bmpCore.SaveAsGif(memoryStream, options); diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs index 9b94347f34..bf9627f4c1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs this.ForEachImageSharpImage((img, ms) => { // Try to get as close to System.Drawing's output as possible - var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; img.Save(ms, options); return null; }); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs index 962b34eb7c..639d1594ee 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { using (var memoryStream = new MemoryStream()) { - var options = new PngEncoder { Quantizer = KnownQuantizers.Palette }; + var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe }; this.bmpCore.SaveAsPng(memoryStream, options); } } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs { using (var memoryStream = new MemoryStream()) { - var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) }; + var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(false) }; this.bmpCore.SaveAsPng(memoryStream, options); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs new file mode 100644 index 0000000000..bf9b1af338 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs @@ -0,0 +1,133 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Memory; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_CopyTo1x1 + { + private Block8x8F block; + + private Buffer2D buffer; + + private BufferArea destArea; + + [GlobalSetup] + public void Setup() + { + if (!SimdUtils.IsAvx2CompatibleArchitecture) + { + throw new InvalidOperationException("Benchmark Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support."); + } + + this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); + this.destArea = this.buffer.GetArea(200, 100, 64, 64); + } + + [Benchmark(Baseline = true)] + public void Original() + { + ref byte selfBase = ref Unsafe.As(ref this.block); + ref byte destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride * sizeof(float); + + CopyRowImpl(ref selfBase, ref destBase, destStride, 0); + CopyRowImpl(ref selfBase, ref destBase, destStride, 1); + CopyRowImpl(ref selfBase, ref destBase, destStride, 2); + CopyRowImpl(ref selfBase, ref destBase, destStride, 3); + CopyRowImpl(ref selfBase, ref destBase, destStride, 4); + CopyRowImpl(ref selfBase, ref destBase, destStride, 5); + CopyRowImpl(ref selfBase, ref destBase, destStride, 6); + CopyRowImpl(ref selfBase, ref destBase, destStride, 7); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void CopyRowImpl(ref byte selfBase, ref byte destBase, int destStride, int row) + { + ref byte s = ref Unsafe.Add(ref selfBase, row * 8 * sizeof(float)); + ref byte d = ref Unsafe.Add(ref destBase, row * destStride); + Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); + } + + [Benchmark] + public void UseVector8() + { + ref Block8x8F s = ref this.block; + ref float origin = ref this.destArea.GetReferenceToOrigin(); + int stride = this.destArea.Stride; + + ref Vector d0 = ref Unsafe.As>(ref origin); + ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); + ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2)); + ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3)); + ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4)); + ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5)); + ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6)); + ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7)); + + Vector row0 = Unsafe.As>(ref s.V0L); + Vector row1 = Unsafe.As>(ref s.V1L); + Vector row2 = Unsafe.As>(ref s.V2L); + Vector row3 = Unsafe.As>(ref s.V3L); + Vector row4 = Unsafe.As>(ref s.V4L); + Vector row5 = Unsafe.As>(ref s.V5L); + Vector row6 = Unsafe.As>(ref s.V6L); + Vector row7 = Unsafe.As>(ref s.V7L); + + d0 = row0; + d1 = row1; + d2 = row2; + d3 = row3; + d4 = row4; + d5 = row5; + d6 = row6; + d7 = row7; + } + + [Benchmark] + public void UseVector8_V2() + { + ref Block8x8F s = ref this.block; + ref float origin = ref this.destArea.GetReferenceToOrigin(); + int stride = this.destArea.Stride; + + ref Vector d0 = ref Unsafe.As>(ref origin); + ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride)); + ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2)); + ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3)); + ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4)); + ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5)); + ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6)); + ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7)); + + d0 = Unsafe.As>(ref s.V0L); + d1 = Unsafe.As>(ref s.V1L); + d2 = Unsafe.As>(ref s.V2L); + d3 = Unsafe.As>(ref s.V3L); + d4 = Unsafe.As>(ref s.V4L); + d5 = Unsafe.As>(ref s.V5L); + d6 = Unsafe.As>(ref s.V6L); + d7 = Unsafe.As>(ref s.V7L); + } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Scaled | + // -------------- |---------:|----------:|----------:|-------:| + // Original | 22.53 ns | 0.1660 ns | 0.1553 ns | 1.00 | + // UseVector8 | 21.59 ns | 0.3079 ns | 0.2571 ns | 0.96 | + // UseVector8_V2 | 22.57 ns | 0.1699 ns | 0.1506 ns | 1.00 | + // + // Conclusion: + // Doesn't worth to bother with this + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs new file mode 100644 index 0000000000..65176af5bb --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs @@ -0,0 +1,404 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; +using SixLabors.ImageSharp.Memory; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_CopyTo2x2 + { + private Block8x8F block; + + private Buffer2D buffer; + + private BufferArea destArea; + + [GlobalSetup] + public void Setup() + { + this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500); + this.destArea = this.buffer.GetArea(200, 100, 128, 128); + } + + [Benchmark(Baseline = true)] + public void Original() + { + ref float destBase = ref this.destArea.GetReferenceToOrigin(); + int destStride = this.destArea.Stride; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride) + { + ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); + ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride); + + Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X; + Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X; + Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y; + Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y; + Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z; + Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z; + Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W; + Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W; + + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W; + Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W; + } + + [Benchmark] + public void Original_V2() + { + ref float destBase = ref this.destArea.GetReferenceToOrigin(); + int destStride = this.destArea.Stride; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_V2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_V2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_V2(ref Block8x8F src, ref float destBase, int row, int destStride) + { + ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1); + ref float dest0 = ref Unsafe.Add(ref destBase, row * 2 * destStride); + + Unsafe.Add(ref dest0, 0) = selfLeft.X; + Unsafe.Add(ref dest0, 1) = selfLeft.X; + Unsafe.Add(ref dest0, 2) = selfLeft.Y; + Unsafe.Add(ref dest0, 3) = selfLeft.Y; + Unsafe.Add(ref dest0, 4) = selfLeft.Z; + Unsafe.Add(ref dest0, 5) = selfLeft.Z; + Unsafe.Add(ref dest0, 6) = selfLeft.W; + Unsafe.Add(ref dest0, 7) = selfLeft.W; + + ref float dest1 = ref Unsafe.Add(ref dest0, 8); + + Unsafe.Add(ref dest1, 0) = selfRight.X; + Unsafe.Add(ref dest1, 1) = selfRight.X; + Unsafe.Add(ref dest1, 2) = selfRight.Y; + Unsafe.Add(ref dest1, 3) = selfRight.Y; + Unsafe.Add(ref dest1, 4) = selfRight.Z; + Unsafe.Add(ref dest1, 5) = selfRight.Z; + Unsafe.Add(ref dest1, 6) = selfRight.W; + Unsafe.Add(ref dest1, 7) = selfRight.W; + + ref float dest2 = ref Unsafe.Add(ref dest0, destStride); + + Unsafe.Add(ref dest2, 0) = selfLeft.X; + Unsafe.Add(ref dest2, 1) = selfLeft.X; + Unsafe.Add(ref dest2, 2) = selfLeft.Y; + Unsafe.Add(ref dest2, 3) = selfLeft.Y; + Unsafe.Add(ref dest2, 4) = selfLeft.Z; + Unsafe.Add(ref dest2, 5) = selfLeft.Z; + Unsafe.Add(ref dest2, 6) = selfLeft.W; + Unsafe.Add(ref dest2, 7) = selfLeft.W; + + ref float dest3 = ref Unsafe.Add(ref dest2, 8); + + Unsafe.Add(ref dest3, 0) = selfRight.X; + Unsafe.Add(ref dest3, 1) = selfRight.X; + Unsafe.Add(ref dest3, 2) = selfRight.Y; + Unsafe.Add(ref dest3, 3) = selfRight.Y; + Unsafe.Add(ref dest3, 4) = selfRight.Z; + Unsafe.Add(ref dest3, 5) = selfRight.Z; + Unsafe.Add(ref dest3, 6) = selfRight.W; + Unsafe.Add(ref dest3, 7) = selfRight.W; + } + + [Benchmark] + public void UseVector2() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector2(sLeft.X); + var yLeft = new Vector2(sLeft.Y); + var zLeft = new Vector2(sLeft.Z); + var wLeft = new Vector2(sLeft.W); + + var xRight = new Vector2(sRight.X); + var yRight = new Vector2(sRight.Y); + var zRight = new Vector2(sRight.Z); + var wRight = new Vector2(sRight.W); + + dTopLeft = xLeft; + Unsafe.Add(ref dTopLeft, 1) = yLeft; + Unsafe.Add(ref dTopLeft, 2) = zLeft; + Unsafe.Add(ref dTopLeft, 3) = wLeft; + + dTopRight = xRight; + Unsafe.Add(ref dTopRight, 1) = yRight; + Unsafe.Add(ref dTopRight, 2) = zRight; + Unsafe.Add(ref dTopRight, 3) = wRight; + + dBottomLeft = xLeft; + Unsafe.Add(ref dBottomLeft, 1) = yLeft; + Unsafe.Add(ref dBottomLeft, 2) = zLeft; + Unsafe.Add(ref dBottomLeft, 3) = wLeft; + + dBottomRight = xRight; + Unsafe.Add(ref dBottomRight, 1) = yRight; + Unsafe.Add(ref dBottomRight, 2) = zRight; + Unsafe.Add(ref dBottomRight, 3) = wRight; + } + + [Benchmark] + public void UseVector4() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector4(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + + Unsafe.As(ref dTopRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + + Unsafe.As(ref dBottomRight) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight; + Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight; + } + + [Benchmark] + public void UseVector4_SafeRightCorner() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4_SafeRightCorner(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride); + ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride); + + var xLeft = new Vector4(sLeft.X); + var yLeft = new Vector4(sLeft.Y); + var zLeft = new Vector4(sLeft.Z); + var wLeft = new Vector4(sLeft.W); + + var xRight = new Vector4(sRight.X); + var yRight = new Vector4(sRight.Y); + var zRight = new Vector4(sRight.Z); + var wRight = new Vector2(sRight.W); + + Unsafe.As(ref dTopLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft; + + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 4)) = xRight; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 5)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dTopLeft, 6)) = zRight; + Unsafe.Add(ref dTopLeft, 7) = wRight; + + Unsafe.As(ref dBottomLeft) = xLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft; + + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 4)) = xRight; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 5)) = yRight; + Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 6)) = zRight; + Unsafe.Add(ref dBottomLeft, 7) = wRight; + } + + + [Benchmark] + public void UseVector4_V2() + { + ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin()); + int destStride = this.destArea.Stride / 2; + + ref Block8x8F src = ref this.block; + + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 0, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 1, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 2, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 3, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 4, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 5, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 6, destStride); + WidenCopyImpl2x2_Vector4_V2(ref src, ref destBase, 7, destStride); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void WidenCopyImpl2x2_Vector4_V2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride) + { + ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row); + ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); + + int offset = 2 * row * destStride; + ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset)); + ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride)); + + var xyLeft = new Vector4(sLeft.X); + xyLeft.Z = sLeft.Y; + xyLeft.W = sLeft.Y; + + var zwLeft = new Vector4(sLeft.Z); + zwLeft.Z = sLeft.W; + zwLeft.W = sLeft.W; + + var xyRight = new Vector4(sRight.X); + xyRight.Z = sRight.Y; + xyRight.W = sRight.Y; + + var zwRight = new Vector4(sRight.Z); + zwRight.Z = sRight.W; + zwRight.W = sRight.W; + + dTopLeft = xyLeft; + Unsafe.Add(ref dTopLeft, 1) = zwLeft; + Unsafe.Add(ref dTopLeft, 2) = xyRight; + Unsafe.Add(ref dTopLeft, 3) = zwRight; + + dBottomLeft = xyLeft; + Unsafe.Add(ref dBottomLeft, 1) = zwLeft; + Unsafe.Add(ref dBottomLeft, 2) = xyRight; + Unsafe.Add(ref dBottomLeft, 3) = zwRight; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | ScaledSD | + // --------------------------- |---------:|----------:|----------:|-------:|---------:| + // Original | 92.69 ns | 2.4722 ns | 2.7479 ns | 1.00 | 0.00 | + // Original_V2 | 91.72 ns | 1.2089 ns | 1.0095 ns | 0.99 | 0.03 | + // UseVector2 | 86.70 ns | 0.5873 ns | 0.5206 ns | 0.94 | 0.03 | + // UseVector4 | 55.42 ns | 0.2482 ns | 0.2322 ns | 0.60 | 0.02 | + // UseVector4_SafeRightCorner | 58.97 ns | 0.4152 ns | 0.3884 ns | 0.64 | 0.02 | + // UseVector4_V2 | 41.88 ns | 0.3531 ns | 0.3303 ns | 0.45 | 0.01 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs similarity index 96% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs index fcc5f9a592..5502475d43 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_DivideRound.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_DivideRound.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { /// /// The goal of this benchmark is to measure the following Jpeg-related scenario: @@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.General private static readonly Vector4 MinusOne = new Vector4(-1); private static readonly Vector4 Half = new Vector4(0.5f); - private Block8x8F inputDividend = default(Block8x8F); - private Block8x8F inputDivisior = default(Block8x8F); + private Block8x8F inputDividend; + private Block8x8F inputDivisior; [GlobalSetup] public void Setup() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs new file mode 100644 index 0000000000..29ee402a00 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs @@ -0,0 +1,53 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System; +using System.Numerics; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg.Components; + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations +{ + public class Block8x8F_LoadFromInt16 + { + private Block8x8 source; + + private Block8x8F dest = default; + + [GlobalSetup] + public void Setup() + { + if (Vector.Count != 8) + { + throw new NotSupportedException("Vector.Count != 8"); + } + + for (short i = 0; i < Block8x8F.Size; i++) + { + this.source[i] = i; + } + } + + [Benchmark(Baseline = true)] + public void Scalar() + { + this.dest.LoadFromInt16Scalar(ref this.source); + } + + [Benchmark] + public void ExtendedAvx2() + { + this.dest.LoadFromInt16ExtendedAvx2(ref this.source); + } + + // RESULT: + // Method | Mean | Error | StdDev | Scaled | + // ------------- |---------:|----------:|----------:|-------:| + // Scalar | 34.88 ns | 0.3296 ns | 0.3083 ns | 1.00 | + // ExtendedAvx2 | 21.58 ns | 0.2125 ns | 0.1884 ns | 0.62 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs similarity index 90% rename from tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs rename to tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs index 200af64c25..c7b5802c4f 100644 --- a/tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs @@ -1,4 +1,7 @@ -// ReSharper disable InconsistentNaming +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming using System; using System.Numerics; @@ -8,7 +11,7 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Formats.Jpeg.Components; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations { public class Block8x8F_Round { diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs deleted file mode 100644 index 9b968e4db3..0000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Drawing; -using System.IO; -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Tests; -using CoreSize = SixLabors.Primitives.Size; -using SDImage = System.Drawing.Image; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg -{ - [Config(typeof(Config.ShortClr))] - public class DecodeJpeg : BenchmarkBase - { - 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(Baseline = true, Description = "Decode Jpeg - System.Drawing")] - public Size JpegSystemDrawing() - { - using (var memoryStream = new MemoryStream(this.jpegBytes)) - { - using (var image = SDImage.FromStream(memoryStream)) - { - return image.Size; - } - } - } - - [Benchmark(Description = "Decode Jpeg - ImageSharp")] - public CoreSize JpegImageSharp() - { - using (var memoryStream = new MemoryStream(this.jpegBytes)) - { - using (var image = Image.Load(memoryStream, new JpegDecoder())) - { - 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 deleted file mode 100644 index be0fe76b82..0000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SDImage = System.Drawing.Image; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg -{ - [Config(typeof(Config.ShortClr))] - public class DecodeJpegMultiple : MultiImageBenchmarkBase - { - protected override IEnumerable InputImageSubfoldersOrFiles => new[] - { - "Jpg/baseline", - "Jpg/progressive", - }; - - protected override IEnumerable SearchPatterns => new[] { "*.jpg" }; - - [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] - public void DecodeJpegImageSharp() - { - this.ForEachStream(ms => Image.Load(ms, new JpegDecoder())); - } - - [Benchmark(Baseline = true, Description = "DecodeJpegMultiple - System.Drawing")] - public void DecodeJpegSystemDrawing() - { - this.ForEachStream(SDImage.FromStream); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs new file mode 100644 index 0000000000..f8a7556ca5 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests; + +using SDImage = System.Drawing.Image; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + /// + /// An expensive Jpeg benchmark, running on a wide range of input images, showing aggregate results. + /// + [Config(typeof(MultiImageBenchmarkBase.Config))] + public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase + { + protected override IEnumerable InputImageSubfoldersOrFiles => + new[] + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; + + [Params(InputImageCategory.AllImages)] + public override InputImageCategory InputCategory { get; set; } + + [Benchmark] + public void ImageSharp() + { + this.ForEachStream(ms => Image.Load(ms, new JpegDecoder())); + } + + [Benchmark(Baseline = true)] + public void SystemDrawing() + { + this.ForEachStream(SDImage.FromStream); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs new file mode 100644 index 0000000000..fe112042ef --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -0,0 +1,119 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Drawing; +using System.IO; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests; +using CoreSize = SixLabors.Primitives.Size; +using SDImage = System.Drawing.Image; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + /// + /// Image-specific Jpeg benchmarks + /// + [Config(typeof(Config.ShortClr))] + public class DecodeJpeg_ImageSpecific + { + public class Config : ManualConfig + { + public Config() + { + // Uncomment if you want to use any of the diagnoser + this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + } + + public class ShortClr : Benchmarks.Config + { + public ShortClr() + { + this.Add( + //Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3), + Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithTargetCount(3) + ); + } + } + } + + private byte[] jpegBytes; + + private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + + [Params( + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + + // The scaled result for the large image "ExifGetString750Transform_Huge420YCbCr" + // is almost the same as the result for Jpeg420Exif, + // which proves that the execution time for the most common YCbCr 420 path scales linearly. + // + // TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr + )] + public string TestImage { get; set; } + + + [GlobalSetup] + public void ReadImages() + { + if (this.jpegBytes == null) + { + this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath); + } + } + + [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] + public Size JpegSystemDrawing() + { + using (var memoryStream = new MemoryStream(this.jpegBytes)) + { + using (var image = SDImage.FromStream(memoryStream)) + { + return image.Size; + } + } + } + + [Benchmark(Description = "Decode Jpeg - ImageSharp")] + public CoreSize JpegImageSharp() + { + using (var memoryStream = new MemoryStream(this.jpegBytes)) + { + using (var image = Image.Load(memoryStream, new JpegDecoder(){ IgnoreMetadata = true})) + { + return new CoreSize(image.Width, image.Height); + } + } + } + + // RESULTS (2018 November 4): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | TestImage | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Gen 1 | Gen 2 | Allocated | + // ------------------------------- |-------------------------------------------- |-----------:|-----------:|----------:|-------:|---------:|----------:|---------:|---------:|------------:| + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/Lake.jpg | 6.117 ms | 0.3923 ms | 0.0222 ms | 1.00 | 0.00 | 62.5000 | - | - | 205.83 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/Lake.jpg | 18.126 ms | 0.6023 ms | 0.0340 ms | 2.96 | 0.01 | - | - | - | 19.97 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/baseline/jpeg420exif.jpg | 17.063 ms | 2.6096 ms | 0.1474 ms | 1.00 | 0.00 | 218.7500 | - | - | 757.04 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/baseline/jpeg420exif.jpg | 41.366 ms | 1.0115 ms | 0.0572 ms | 2.42 | 0.02 | - | - | - | 21.94 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 428.282 ms | 94.9163 ms | 5.3629 ms | 1.00 | 0.00 | 2375.0000 | - | - | 7403.76 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/Issue518-Bad-RST-Progressive.jpg | 386.698 ms | 33.0065 ms | 1.8649 ms | 0.90 | 0.01 | 125.0000 | 125.0000 | 125.0000 | 35186.97 KB | + // | | | | | | | | | | | + // 'Decode Jpeg - System.Drawing' | Jpg/issues/issue750-exif-tranform.jpg | 95.192 ms | 3.1762 ms | 0.1795 ms | 1.00 | 0.00 | 1750.0000 | - | - | 5492.63 KB | + // 'Decode Jpeg - ImageSharp' | Jpg/issues/issue750-exif-tranform.jpg | 230.158 ms | 48.8128 ms | 2.7580 ms | 2.42 | 0.02 | 312.5000 | 312.5000 | 312.5000 | 58834.66 KB | + } +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs deleted file mode 100644 index 77ed828ef1..0000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using BenchmarkDotNet.Attributes; -using System; -using System.IO; -using SixLabors.ImageSharp.Tests; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; -using SixLabors.ImageSharp.Processing; -using SDImage = System.Drawing.Image; -using SixLabors.ImageSharp.Formats.Jpeg; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg -{ - [Config(typeof(Config.ShortClr))] - public class LoadResizeSave : BenchmarkBase - { - private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); - - private byte[] sourceBytes; - - private byte[] destBytes; - - private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); - - [Params( - TestImages.Jpeg.Baseline.Jpeg420Exif - //, TestImages.Jpeg.Baseline.Calliphora - )] - public string TestImage { get; set; } - - [Params(false, true)] - public bool EnableParallelExecution { get; set; } - - [GlobalSetup] - public void Setup() - { - this.configuration.MaxDegreeOfParallelism = - this.EnableParallelExecution ? Environment.ProcessorCount : 1; - - if (this.sourceBytes == null) - { - this.sourceBytes = File.ReadAllBytes(this.TestImageFullPath); - } - - if (this.destBytes == null) - { - this.destBytes = new byte[this.sourceBytes.Length]; - } - } - - [Benchmark(Baseline = true)] - public void SystemDrawing() - { - using (var sourceStream = new MemoryStream(this.sourceBytes)) - using (var destStream = new MemoryStream(this.destBytes)) - using (var source = SDImage.FromStream(sourceStream)) - using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) - { - using (var graphics = Graphics.FromImage(destination)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(source, 0, 0, 400, 400); - } - - destination.Save(destStream, ImageFormat.Jpeg); - } - } - - [Benchmark] - public void ImageSharp() - { - var source = Image.Load(this.configuration, this.sourceBytes, new JpegDecoder { IgnoreMetadata = true }); - using (source) - using (var destStream = new MemoryStream(this.destBytes)) - { - source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4)); - source.SaveAsJpeg(destStream); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs new file mode 100644 index 0000000000..e39cfa6ba2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_Aggregate.cs @@ -0,0 +1,96 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + [Config(typeof(MultiImageBenchmarkBase.Config))] + public class LoadResizeSave_Aggregate : MultiImageBenchmarkBase + { + protected override IEnumerable InputImageSubfoldersOrFiles => + new[] + { + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, + }; + + [Params(InputImageCategory.AllImages)] + public override InputImageCategory InputCategory { get; set; } + + private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); + + private byte[] destBytes; + + public override void Setup() + { + base.Setup(); + + this.configuration.MaxDegreeOfParallelism = 1; + const int MaxOutputSizeInBytes = 2 * 1024 * 1024; // ~2 MB + this.destBytes = new byte[MaxOutputSizeInBytes]; + } + + [Benchmark(Baseline = true)] + public void SystemDrawing() + { + this.ForEachStream( + sourceStream => + { + using (var destStream = new MemoryStream(this.destBytes)) + using (var source = System.Drawing.Image.FromStream(sourceStream)) + using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) + { + using (var g = Graphics.FromImage(destination)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.DrawImage(source, 0, 0, 400, 400); + } + + destination.Save(destStream, ImageFormat.Jpeg); + } + + return null; + }); + } + + [Benchmark] + public void ImageSharp() + { + this.ForEachStream( + sourceStream => + { + using (var source = Image.Load( + this.configuration, + sourceStream, + new JpegDecoder { IgnoreMetadata = true })) + { + using (var destStream = new MemoryStream(this.destBytes)) + { + source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4)); + source.SaveAsJpeg(destStream); + } + } + + return null; + }); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs new file mode 100644 index 0000000000..1834f77eaf --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/LoadResizeSave_ImageSpecific.cs @@ -0,0 +1,107 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using BenchmarkDotNet.Attributes; +using System; +using System.IO; +using SixLabors.ImageSharp.Tests; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using SixLabors.ImageSharp.Processing; +using SDImage = System.Drawing.Image; +using SixLabors.ImageSharp.Formats.Jpeg; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg +{ + [Config(typeof(Config.ShortClr))] + public class LoadResizeSave_ImageSpecific + { + private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); + + private byte[] sourceBytes; + + private byte[] destBytes; + + private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + + [Params( + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr + )] + public string TestImage { get; set; } + + [Params(false, true)] + public bool ParallelExec { get; set; } + + [GlobalSetup] + public void Setup() + { + this.configuration.MaxDegreeOfParallelism = + this.ParallelExec ? Environment.ProcessorCount : 1; + + this.sourceBytes = File.ReadAllBytes(this.TestImageFullPath); + + this.destBytes = new byte[this.sourceBytes.Length * 2]; + } + + [Benchmark(Baseline = true)] + public void SystemDrawing() + { + using (var sourceStream = new MemoryStream(this.sourceBytes)) + using (var destStream = new MemoryStream(this.destBytes)) + using (var source = SDImage.FromStream(sourceStream)) + using (var destination = new Bitmap(source.Width / 4, source.Height / 4)) + { + using (var g = Graphics.FromImage(destination)) + { + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.DrawImage(source, 0, 0, 400, 400); + } + + destination.Save(destStream, ImageFormat.Jpeg); + } + } + + [Benchmark] + public void ImageSharp() + { + var source = Image.Load(this.configuration, this.sourceBytes, new JpegDecoder { IgnoreMetadata = true }); + using (source) + using (var destStream = new MemoryStream(this.destBytes)) + { + source.Mutate(c => c.Resize(source.Width / 4, source.Height / 4)); + source.SaveAsJpeg(destStream); + } + } + + // RESULTS (2018 October 31): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-ZPEZGV : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-SGOCJT : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | TestImage | ParallelExec | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // -------------- |-------- |----------------------------- |------------- |----------:|----------:|----------:|-------:|---------:|---------:|----------:| + // SystemDrawing | Clr | Jpg/baseline/jpeg420exif.jpg | False | 64.88 ms | 3.735 ms | 0.2110 ms | 1.00 | 0.00 | 250.0000 | 791.07 KB | + // ImageSharp | Clr | Jpg/baseline/jpeg420exif.jpg | False | 129.53 ms | 23.423 ms | 1.3234 ms | 2.00 | 0.02 | - | 50.09 KB | + // | | | | | | | | | | | + // SystemDrawing | Core | Jpg/baseline/jpeg420exif.jpg | False | 65.87 ms | 10.488 ms | 0.5926 ms | 1.00 | 0.00 | 250.0000 | 789.79 KB | + // ImageSharp | Core | Jpg/baseline/jpeg420exif.jpg | False | 92.00 ms | 7.241 ms | 0.4091 ms | 1.40 | 0.01 | - | 46.36 KB | + // | | | | | | | | | | | + // SystemDrawing | Clr | Jpg/baseline/jpeg420exif.jpg | True | 64.23 ms | 5.998 ms | 0.3389 ms | 1.00 | 0.00 | 250.0000 | 791.07 KB | + // ImageSharp | Clr | Jpg/baseline/jpeg420exif.jpg | True | 82.63 ms | 29.320 ms | 1.6566 ms | 1.29 | 0.02 | - | 57.59 KB | + // | | | | | | | | | | | + // SystemDrawing | Core | Jpg/baseline/jpeg420exif.jpg | True | 64.20 ms | 6.560 ms | 0.3707 ms | 1.00 | 0.00 | 250.0000 | 789.79 KB | + // ImageSharp | Core | Jpg/baseline/jpeg420exif.jpg | True | 68.08 ms | 18.376 ms | 1.0383 ms | 1.06 | 0.01 | - | 50.49 KB | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index f046f3033b..446c038596 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -3,6 +3,9 @@ // Licensed under the Apache License, Version 2.0. // +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; + using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Codecs @@ -20,8 +23,27 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using CoreImage = ImageSharp.Image; - public abstract class MultiImageBenchmarkBase : BenchmarkBase + public abstract class MultiImageBenchmarkBase { + public class Config : ManualConfig + { + public Config() + { + // Uncomment if you want to use any of the diagnoser + this.Add(new BenchmarkDotNet.Diagnosers.MemoryDiagnoser()); + } + + public class ShortClr : Benchmarks.Config + { + public ShortClr() + { + this.Add( + Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithTargetCount(2) + ); + } + } + } + protected Dictionary FileNamesToBytes = new Dictionary(); protected Dictionary> FileNamesToImageSharpImages = new Dictionary>(); @@ -49,7 +71,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs /// /// Gets the file names containing these strings are substrings are not processed by the benchmark. /// - protected IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" }; + protected virtual IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" }; /// /// Enumerates folders containing files OR files to be processed by the benchmark. @@ -87,7 +109,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs protected abstract IEnumerable InputImageSubfoldersOrFiles { get; } [GlobalSetup] - public void ReadImages() + public virtual void Setup() { if (!Vector.IsHardwareAccelerated) { @@ -107,11 +129,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs continue; } + string[] excludeStrings = this.ExcludeSubstringsInFileNames.Select(s => s.ToLower()).ToArray(); + string[] allFiles = this.SearchPatterns.SelectMany( f => Directory.EnumerateFiles(path, f, SearchOption.AllDirectories) - .Where(fn => !this.ExcludeSubstringsInFileNames.Any(w => fn.ToLower().Contains(w)))).ToArray(); + .Where(fn => !excludeStrings.Any(excludeStr => fn.ToLower().Contains(excludeStr)))).ToArray(); foreach (string fn in allFiles) { diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs new file mode 100644 index 0000000000..b964221764 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs @@ -0,0 +1,92 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System.Buffers; +using System; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + public abstract class FromRgba32Bytes + where TPixel : struct, IPixel + { + private IMemoryOwner destination; + + private IMemoryOwner source; + + private Configuration configuration; + + [Params( + 128, + 1024, + 2048)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.configuration = Configuration.Default; + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.configuration.MemoryAllocator.Allocate(this.Count * 4); + } + + [GlobalCleanup] + public void Cleanup() + { + this.destination.Dispose(); + this.source.Dispose(); + } + + //[Benchmark] + public void Naive() + { + Span s = this.source.GetSpan(); + Span d = this.destination.GetSpan(); + + for (int i = 0; i < this.Count; i++) + { + int i4 = i * 4; + var c = default(TPixel); + c.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); + d[i] = c; + } + } + + [Benchmark(Baseline = true)] + public void CommonBulk() + { + new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); + } + + [Benchmark] + public void OptimizedBulk() + { + PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); + } + } + + public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes + { + } + + public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes + { + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------- |------ |-----------:|----------:|----------:|-------:| + // CommonBulk | 128 | 207.1 ns | 3.723 ns | 3.300 ns | 1.00 | + // OptimizedBulk | 128 | 166.5 ns | 1.204 ns | 1.005 ns | 0.80 | + // | | | | | | + // CommonBulk | 1024 | 1,333.9 ns | 12.426 ns | 11.624 ns | 1.00 | + // OptimizedBulk | 1024 | 974.1 ns | 18.803 ns | 16.669 ns | 0.73 | + // | | | | | | + // CommonBulk | 2048 | 2,625.4 ns | 30.143 ns | 26.721 ns | 1.00 | + // OptimizedBulk | 2048 | 1,843.0 ns | 20.505 ns | 18.177 ns | 0.70 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs new file mode 100644 index 0000000000..2b9573ed73 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs @@ -0,0 +1,130 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System; +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public abstract class FromVector4 + where TPixel : struct, IPixel + { + protected IMemoryOwner source; + + protected IMemoryOwner destination; + + protected Configuration Configuration => Configuration.Default; + + [Params( + 64, + 2048 + )] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + } + + [GlobalCleanup] + public void Cleanup() + { + this.destination.Dispose(); + this.source.Dispose(); + } + + //[Benchmark] + public void PerElement() + { + ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); + ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan()); + + for (int i = 0; i < this.Count; i++) + { + Unsafe.Add(ref d, i).FromVector4(Unsafe.Add(ref s, i)); + } + } + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); + } + + [Benchmark] + public void PixelOperations_Specialized() + { + PixelOperations.Instance.FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); + } + } + + public class FromVector4Rgba32 : FromVector4 + { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsic() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats); + } + + // RESULTS (2018 October): + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 340.38 ns | 22.319 ns | 1.2611 ns | 1.41 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.79 ns | 11.421 ns | 0.6453 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 64 | 199.09 ns | 124.239 ns | 7.0198 ns | 0.83 | 0.02 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 647.99 ns | 24.003 ns | 1.3562 ns | 2.69 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 259.79 ns | 13.391 ns | 0.7566 ns | 1.08 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 234.64 ns | 12.320 ns | 0.6961 ns | 1.58 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 148.87 ns | 2.794 ns | 0.1579 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 64 | 94.06 ns | 10.015 ns | 0.5659 ns | 0.63 | 0.00 | - | 0 B | + // PixelOperations_Base | Core | 64 | 573.52 ns | 31.865 ns | 1.8004 ns | 3.85 | 0.01 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 64 | 117.21 ns | 13.264 ns | 0.7494 ns | 0.79 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 6,735.93 ns | 2,139.340 ns | 120.8767 ns | 1.71 | 0.03 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 3,929.29 ns | 334.027 ns | 18.8731 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Clr | 2048 | 2,226.01 ns | 130.525 ns | 7.3749 ns |!! 0.57 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 16,760.84 ns | 367.800 ns | 20.7814 ns | 4.27 | 0.02 | - | 24 B | <--- Extra copies using "Vector4 TPixel.ToVector4()" + // PixelOperations_Specialized | Clr | 2048 | 3,986.03 ns | 237.238 ns | 13.4044 ns | 1.01 | 0.00 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 6,644.65 ns | 2,677.090 ns | 151.2605 ns | 1.69 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 3,923.70 ns | 1,971.760 ns | 111.4081 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsic | Core | 2048 | 2,092.32 ns | 375.657 ns | 21.2253 ns |!! 0.53 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 16,875.73 ns | 1,271.957 ns | 71.8679 ns | 4.30 | 0.10 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,129.92 ns | 262.888 ns | 14.8537 ns |!! 0.54 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs deleted file mode 100644 index a5fa59ba07..0000000000 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// ReSharper disable InconsistentNaming - -using System.Buffers; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - [Config(typeof(Config.ShortClr))] - public abstract class PackFromVector4 - where TPixel : struct, IPixel - { - private IMemoryOwner source; - - private IMemoryOwner destination; - - [Params(16, 128, 512)] - public int Count { get; set; } - - [GlobalSetup] - public void Setup() - { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - } - - [GlobalCleanup] - public void Cleanup() - { - this.destination.Dispose(); - this.source.Dispose(); - } - - [Benchmark(Baseline = true)] - public void PerElement() - { - ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); - ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan()); - - for (int i = 0; i < this.Count; i++) - { - Unsafe.Add(ref d, i).PackFromVector4(Unsafe.Add(ref s, i)); - } - } - - [Benchmark] - public void CommonBulk() - { - new PixelOperations().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - } - - public class PackFromVector4_Rgba32 : PackFromVector4 - { - - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs deleted file mode 100644 index 7e7dfb3652..0000000000 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// ReSharper disable InconsistentNaming - -using System.Buffers; -using System; - -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - public abstract class PackFromXyzw - where TPixel : struct, IPixel - { - private IMemoryOwner destination; - - private IMemoryOwner source; - - [Params(16, 128, 1024)] - public int Count { get; set; } - - [GlobalSetup] - public void Setup() - { - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); - } - - [GlobalCleanup] - public void Cleanup() - { - this.destination.Dispose(); - this.source.Dispose(); - } - - [Benchmark(Baseline = true)] - public void PerElement() - { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); - - for (int i = 0; i < this.Count; i++) - { - int i4 = i * 4; - var c = default(TPixel); - c.PackFromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); - d[i] = c; - } - } - - [Benchmark] - public void CommonBulk() - { - new PixelOperations().PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.PackFromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - } - - public class PackFromXyzw_Rgba32 : PackFromXyzw - { - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs new file mode 100644 index 0000000000..294baa9d51 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs @@ -0,0 +1,60 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// ReSharper disable InconsistentNaming + +using System.Buffers; +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + public abstract class Rgb24Bytes + where TPixel : struct, IPixel + { + private IMemoryOwner source; + + private IMemoryOwner destination; + + private Configuration configuration; + + [Params(16, 128, 1024)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 3); + } + + [GlobalCleanup] + public void Cleanup() + { + this.source.Dispose(); + this.destination.Dispose(); + } + + [Benchmark(Baseline = true)] + public void CommonBulk() => + new PixelOperations().ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); + + [Benchmark] + public void OptimizedBulk() => + PixelOperations.Instance.ToRgb24Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); + } + + public class Rgb24Bytes_Rgba32 : Rgb24Bytes + { + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs similarity index 54% rename from tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs rename to tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs index 8166c8f465..7f4b2bc41d 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs @@ -12,21 +12,24 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk { - public abstract class ToXyzw + public abstract class ToRgba32Bytes where TPixel : struct, IPixel { private IMemoryOwner source; private IMemoryOwner destination; + private Configuration configuration; + [Params(16, 128, 1024)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 4); + this.configuration = Configuration.Default; + this.source = this.configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.configuration.MemoryAllocator.Allocate(this.Count * 4); } [GlobalCleanup] @@ -36,18 +39,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); - var rgba = default(Rgba32); - for (int i = 0; i < this.Count; i++) { TPixel c = s[i]; int i4 = i * 4; + Rgba32 rgba = default; c.ToRgba32(ref rgba); d[i4] = rgba.R; d[i4 + 1] = rgba.G; @@ -56,24 +58,32 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk } } - [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + [Benchmark(Baseline = true)] + public void CommonBulk() => + new PixelOperations().ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + public void OptimizedBulk() => + PixelOperations.Instance.ToRgba32Bytes( + this.configuration, + this.source.GetSpan(), + this.destination.GetSpan(), + this.Count); + } + + public class ToRgba32Bytes_FromRgba32 : ToRgba32Bytes + { } - public class ToXyzw_Rgba32 : ToXyzw + public class ToRgba32Bytes_FromArgb32 : ToRgba32Bytes { } - public class ToXyzw_Argb32 : ToXyzw + public class ToRgba32Bytes_FromBgra32 : ToRgba32Bytes { } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 50fac25139..70de8f4e27 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -17,18 +17,25 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk public abstract class ToVector4 where TPixel : struct, IPixel { - private IMemoryOwner source; + protected IMemoryOwner source; - private IMemoryOwner destination; + protected IMemoryOwner destination; - [Params(64, 300, 1024)] + protected Configuration Configuration => Configuration.Default; + + [Params( + 64, + 256, + //512, + //1024, + 2048)] public int Count { get; set; } [GlobalSetup] public void Setup() { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count); + this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] @@ -38,33 +45,26 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk this.destination.Dispose(); } - [Benchmark(Baseline = true)] - public void PerElement() + //[Benchmark] + public void Naive() { Span s = this.source.GetSpan(); Span d = this.destination.GetSpan(); for (int i = 0; i < this.Count; i++) { - TPixel c = s[i]; - d[i] = c.ToVector4(); + d[i] = s[i].ToVector4(); } } + [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() + public void PixelOperations_Specialized() { - PixelOperations.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count); + PixelOperations.Instance.ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); } } - - public class ToVector4_Rgba32 : ToVector4 - { - } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs new file mode 100644 index 0000000000..39702d5253 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs @@ -0,0 +1,41 @@ +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Bgra32 : ToVector4 + { + [Benchmark(Baseline = true)] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + + // RESULTS: + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |-----------:|------------:|-----------:|-------:|---------:|-------:|----------:| + // PixelOperations_Base | Clr | 64 | 339.9 ns | 138.30 ns | 7.8144 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 338.1 ns | 13.30 ns | 0.7515 ns | 0.99 | 0.02 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 64 | 245.6 ns | 29.05 ns | 1.6413 ns | 1.00 | 0.00 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 257.1 ns | 37.89 ns | 2.1407 ns | 1.05 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 256 | 972.7 ns | 61.98 ns | 3.5020 ns | 1.00 | 0.00 | 0.0057 | 24 B | + // PixelOperations_Specialized | Clr | 256 | 882.9 ns | 126.21 ns | 7.1312 ns | 0.91 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 256 | 910.0 ns | 90.87 ns | 5.1346 ns | 1.00 | 0.00 | 0.0067 | 24 B | + // PixelOperations_Specialized | Core | 256 | 448.4 ns | 15.77 ns | 0.8910 ns | 0.49 | 0.00 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Clr | 2048 | 6,951.8 ns | 1,299.01 ns | 73.3963 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 5,852.3 ns | 630.56 ns | 35.6279 ns | 0.84 | 0.01 | - | 0 B | + // | | | | | | | | | | + // PixelOperations_Base | Core | 2048 | 6,937.5 ns | 1,692.19 ns | 95.6121 ns | 1.00 | 0.00 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 2,994.5 ns | 1,126.65 ns | 63.6578 ns | 0.43 | 0.01 | - | 0 B | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs new file mode 100644 index 0000000000..ab05a14073 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs @@ -0,0 +1,164 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk +{ + [Config(typeof(Config.ShortClr))] + public class ToVector4_Rgba32 : ToVector4 + { + [Benchmark] + public void FallbackIntrinsics128() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void PixelOperations_Base() + { + new PixelOperations().ToVector4( + this.Configuration, + this.source.GetSpan(), + this.destination.GetSpan()); + } + + [Benchmark(Baseline = true)] + public void BasicIntrinsics256() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + [Benchmark] + public void ExtendedIntrinsics() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats); + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + ref Vector destBaseU = ref Unsafe.As, Vector>(ref destBase); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref destBaseU, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + + n = dFloats.Length / Vector.Count; + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector dRef = ref Unsafe.Add(ref destBase, i); + + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + dRef = v; + } + } + + //[Benchmark] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() + { + Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + + int n = dFloats.Length / Vector.Count; + + ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); + ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sourceBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + Vector f0 = ConvertToNormalizedSingle(w0, scale); + Vector f1 = ConvertToNormalizedSingle(w1, scale); + Vector f2 = ConvertToNormalizedSingle(w2, scale); + Vector f3 = ConvertToNormalizedSingle(w3, scale); + + ref Vector d = ref Unsafe.Add(ref destBase, i * 4); + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) + { + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); + v *= scale; + return v; + } + + // RESULTS (2018 October): + // + // Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated | + // ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:| + // FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B | + // PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized! + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B | + // BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B | + // PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B | + // PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B | + // | | | | | | | | | | + // FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B | + // BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :( + // | | | | | | | | | | + // FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B | + // BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B | + // ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock! + // PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | + // PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs deleted file mode 100644 index 4e9c6d10a6..0000000000 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// ReSharper disable InconsistentNaming - -using System.Buffers; -using System; - -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk -{ - public abstract class ToXyz - where TPixel : struct, IPixel - { - private IMemoryOwner source; - - private IMemoryOwner destination; - - [Params(16, 128, 1024)] - public int Count { get; set; } - - [GlobalSetup] - public void Setup() - { - this.source = Configuration.Default.MemoryAllocator.Allocate(this.Count); - this.destination = Configuration.Default.MemoryAllocator.Allocate(this.Count * 3); - } - - [GlobalCleanup] - public void Cleanup() - { - this.source.Dispose(); - this.destination.Dispose(); - } - - [Benchmark(Baseline = true)] - public void PerElement() - { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); - - var rgb = default(Rgb24); - - for (int i = 0; i < this.Count; i++) - { - TPixel c = s[i]; - int i3 = i * 3; - c.ToRgb24(ref rgb); - d[i3] = rgb.R; - d[i3 + 1] = rgb.G; - d[i3 + 2] = rgb.B; - } - } - - [Benchmark] - public void CommonBulk() - { - new PixelOperations().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - - [Benchmark] - public void OptimizedBulk() - { - PixelOperations.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } - } - - public class ToXyz_Rgba32 : ToXyz - { - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Abs.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs similarity index 88% rename from tests/ImageSharp.Benchmarks/General/Abs.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs index a67f3f1078..ea53959b6a 100644 --- a/tests/ImageSharp.Benchmarks/General/Abs.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs @@ -1,9 +1,9 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; +using System; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ public class Abs { [Params(-1, 1)] diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs new file mode 100644 index 0000000000..3b7dea0955 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs @@ -0,0 +1,70 @@ +using System; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Running; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampFloat + { + private readonly float min = -1.5f; + private readonly float max = 2.5f; + private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 }; + + [Benchmark(Baseline = true)] + public float UsingMathF() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingMathF(Values[i], this.min, this.max); + } + + return acc; + } + + [Benchmark] + public float UsingBranching() + { + float acc = 0; + + for (int i = 0; i < Values.Length; i++) + { + acc += ClampUsingBranching(Values[i], this.min, this.max); + } + + return acc; + } + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingMathF(float x, float min, float max) + { + return Math.Min(max, Math.Max(min, x)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static float ClampUsingBranching(float x, float min, float max) + { + if (x >= max) + { + return max; + } + + if (x <= min) + { + return min; + } + + return x; + } + + // RESULTS: + // Method | Mean | Error | StdDev | Scaled | + // --------------- |---------:|----------:|----------:|-------:| + // UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 | + // UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Clamp.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs similarity index 93% rename from tests/ImageSharp.Benchmarks/General/Clamp.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs index ef6bc3c402..6ce82ba115 100644 --- a/tests/ImageSharp.Benchmarks/General/Clamp.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs @@ -3,14 +3,14 @@ // Licensed under the Apache License, Version 2.0. // -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System; - using System.Runtime.CompilerServices; +using System; +using System.Runtime.CompilerServices; - using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; - public class Clamp +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + public class ClampInt32IntoByte { [Params(-1, 0, 255, 256)] public int Value { get; set; } diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs new file mode 100644 index 0000000000..9ddfad7222 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs @@ -0,0 +1,23 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoConstant + { + private readonly int value = 42; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % 8; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.Modulo8(this.value); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs new file mode 100644 index 0000000000..5c2fe81fa2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs @@ -0,0 +1,32 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath +{ + [LongRunJob] + public class ModuloPowerOfTwoVariable + { + private readonly int value = 42; + + private readonly int m = 32; + + [Benchmark(Baseline = true)] + public int Standard() + { + return this.value % this.m; + } + + [Benchmark] + public int Bitwise() + { + return ImageMaths.ModuloP2(this.value, this.m); + } + + // RESULTS: + // + // Method | Mean | Error | StdDev | Median | Scaled | ScaledSD | + // --------- |----------:|----------:|----------:|----------:|-------:|---------:| + // Standard | 1.2465 ns | 0.0093 ns | 0.0455 ns | 1.2423 ns | 1.00 | 0.00 | + // Bitwise | 0.0265 ns | 0.0103 ns | 0.0515 ns | 0.0000 ns | 0.02 | 0.04 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Pow.cs b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs similarity index 93% rename from tests/ImageSharp.Benchmarks/General/Pow.cs rename to tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs index 325bd9d20e..0f256fc781 100644 --- a/tests/ImageSharp.Benchmarks/General/Pow.cs +++ b/tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs @@ -1,7 +1,8 @@ using System; + using BenchmarkDotNet.Attributes; -namespace SixLabors.ImageSharp.Benchmarks.General +namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath { public class Pow { diff --git a/tests/ImageSharp.Benchmarks/General/Modulus.cs b/tests/ImageSharp.Benchmarks/General/Modulus.cs deleted file mode 100644 index e6d5ccce62..0000000000 --- a/tests/ImageSharp.Benchmarks/General/Modulus.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using BenchmarkDotNet.Attributes; - - public class Modulus - { - [Benchmark(Baseline = true, Description = "Standard Modulus using %")] - public int StandardModulus() - { - return 255 % 256; - } - - [Benchmark(Description = "Bitwise Modulus using &")] - public int BitwiseModulus() - { - return 255 & 255; - } - } -} diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs new file mode 100644 index 0000000000..b5f339fb37 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -0,0 +1,28 @@ +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + interface ITestPixel + where T : struct, ITestPixel + { + void FromRgba32(Rgba32 source); + + void FromRgba32(ref Rgba32 source); + + void FromBytes(byte r, byte g, byte b, byte a); + + void FromVector4(Vector4 source); + + void FromVector4(ref Vector4 source); + + Rgba32 ToRgba32(); + + void CopyToRgba32(ref Rgba32 dest); + + Vector4 ToVector4(); + + void CopyToVector4(ref Vector4 dest); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs new file mode 100644 index 0000000000..9f1b2721b4 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -0,0 +1,215 @@ +// ReSharper disable InconsistentNaming + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public abstract class PixelConversion_ConvertFromRgba32 + { + internal struct ConversionRunner + where T : struct, ITestPixel + { + public readonly T[] dest; + + public readonly Rgba32[] source; + + public ConversionRunner(int count) + { + this.dest = new T[count]; + this.source = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunByRefConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Rgba32 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i).FromRgba32(ref Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunByValConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Rgba32 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i).FromRgba32(Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunFromBytesConversion() + { + int count = this.dest.Length; + + ref T destBaseRef = ref this.dest[0]; + ref Rgba32 sourceBaseRef = ref this.source[0]; + + for (int i = 0; i < count; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sourceBaseRef, i); + Unsafe.Add(ref destBaseRef, i).FromBytes(s.R, s.G, s.B, s.A); + } + } + } + + internal ConversionRunner compatibleMemLayoutRunner; + + internal ConversionRunner permutedRunnerRgbaToArgb; + + [Params( + 256, + 2048 + )] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.compatibleMemLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunnerRgbaToArgb = new ConversionRunner(this.Count); + } + } + + public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32 + { + [Benchmark(Baseline = true)] + public void ByRef() + { + this.compatibleMemLayoutRunner.RunByRefConversion(); + } + + [Benchmark] + public void ByVal() + { + this.compatibleMemLayoutRunner.RunByValConversion(); + } + + [Benchmark] + public void FromBytes() + { + this.compatibleMemLayoutRunner.RunFromBytesConversion(); + } + + [Benchmark] + public void Inline() + { + ref Rgba32 sBase = ref this.compatibleMemLayoutRunner.source[0]; + ref Rgba32 dBase = ref Unsafe.As(ref this.compatibleMemLayoutRunner.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i); + } + } + + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 | + // ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 | + // FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 | + // Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 | + } + + public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 + { + [Benchmark(Baseline = true)] + public void ByRef() + { + this.permutedRunnerRgbaToArgb.RunByRefConversion(); + } + + [Benchmark] + public void ByVal() + { + this.permutedRunnerRgbaToArgb.RunByValConversion(); + } + + [Benchmark] + public void FromBytes() + { + this.permutedRunnerRgbaToArgb.RunFromBytesConversion(); + } + + [Benchmark] + public void InlineShuffle() + { + ref Rgba32 sBase = ref this.permutedRunnerRgbaToArgb.source[0]; + ref TestArgb dBase = ref this.permutedRunnerRgbaToArgb.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + ref TestArgb d = ref Unsafe.Add(ref dBase, i); + + d.R = s.R; + d.G = s.G; + d.B = s.B; + d.A = s.A; + } + } + + [Benchmark] + public void PixelConverter_Rgba32_ToArgb32() + { + ref uint sBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.source[0]); + ref uint dBase = ref Unsafe.As(ref this.permutedRunnerRgbaToArgb.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); + } + } + + [Benchmark] + public void PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer() + { + Span source = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.source); + Span dest = MemoryMarshal.Cast(this.permutedRunnerRgbaToArgb.dest); + source.CopyTo(dest); + + ref uint dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref dBase, i); + Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s); + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------------------------------------------------------- |------ |-----------:|-----------:|-----------:|-------:|---------:| + // ByRef | 256 | 328.7 ns | 6.6141 ns | 6.1868 ns | 1.00 | 0.00 | + // ByVal | 256 | 322.0 ns | 4.3541 ns | 4.0728 ns | 0.98 | 0.02 | + // FromBytes | 256 | 321.5 ns | 3.3499 ns | 3.1335 ns | 0.98 | 0.02 | + // InlineShuffle | 256 | 330.7 ns | 4.2525 ns | 3.9778 ns | 1.01 | 0.02 | + // PixelConverter_Rgba32_ToArgb32 | 256 | 167.4 ns | 0.6357 ns | 0.5309 ns | 0.51 | 0.01 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 256 | 196.6 ns | 0.8929 ns | 0.7915 ns | 0.60 | 0.01 | + // | | | | | | | + // ByRef | 2048 | 2,534.4 ns | 8.2947 ns | 6.9265 ns | 1.00 | 0.00 | + // ByVal | 2048 | 2,638.5 ns | 52.6843 ns | 70.3320 ns | 1.04 | 0.03 | + // FromBytes | 2048 | 2,517.2 ns | 40.8055 ns | 38.1695 ns | 0.99 | 0.01 | + // InlineShuffle | 2048 | 2,546.5 ns | 21.2506 ns | 19.8778 ns | 1.00 | 0.01 | + // PixelConverter_Rgba32_ToArgb32 | 2048 | 1,265.7 ns | 5.1397 ns | 4.5562 ns | 0.50 | 0.00 | + // PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 2048 | 1,410.3 ns | 11.1939 ns | 9.9231 ns | 0.56 | 0.00 |// + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs similarity index 79% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index 5b059e2e65..d0c8a3045c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -1,62 +1,48 @@ // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Numerics; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using BenchmarkDotNet.Attributes; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; - public class PixelConversion_ConvertFromVector4 - { - interface ITestPixel - where T : struct, ITestPixel - { - void FromVector4(Vector4 source); +using BenchmarkDotNet.Attributes; - void FromVector4(ref Vector4 source); - } +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertFromVector4 + { [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel + struct TestRgbaVector : ITestPixel { - private byte a, r, g, b; + private Vector4 v; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.v = p; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromVector4(ref Vector4 p) { - this.r = (byte)p.X; - this.g = (byte)p.Y; - this.b = (byte)p.Z; - this.a = (byte)p.W; + this.v = p; } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgbaVector : ITestPixel - { - private Vector4 v; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) - { - this.v = p; - } + public Vector4 ToVector4() => this.v; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) + public void CopyToVector4(ref Vector4 dest) { - this.v = p; + dest = this.v; } + + public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); + public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); + public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); + public Rgba32 ToRgba32() => throw new System.NotImplementedException(); + public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException(); } struct ConversionRunner diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs similarity index 67% rename from tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs rename to tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs index 5656904fe0..d205e1e63e 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs @@ -1,14 +1,14 @@ // ReSharper disable InconsistentNaming -using SixLabors.ImageSharp.PixelFormats; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; - using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ /// /// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer? /// 1. Rgba32 ToRgba32(); @@ -18,53 +18,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General /// public class PixelConversion_ConvertToRgba32 { - interface ITestPixel - where T : struct, ITestPixel - { - Rgba32 ToRgba32(); - - void CopyToRgba32(ref Rgba32 dest); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return new Rgba32(this.r, this.g, this.b, this.a); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest.R = this.r; - dest.G = this.g; - dest.B = this.b; - dest.A = this.a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return Unsafe.As(ref this); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest = Unsafe.As(ref this); - } - } - struct ConversionRunner where T : struct, ITestPixel { @@ -111,7 +64,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General private ConversionRunner permutedRunner; - [Params(128)] + [Params(32)] public int Count { get; set; } [GlobalSetup] diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..fff9ae9bc7 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs @@ -0,0 +1,113 @@ +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Rgba32[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Rgba32[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToRgba32(); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Rgba32 destBaseRef = ref this.dest[0]; + + Rgba32 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.A = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner compatibleMemoryLayoutRunner; + + private ConversionRunner permutedRunner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.compatibleMemoryLayoutRunner = new ConversionRunner(this.Count); + this.permutedRunner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void CompatibleRetval() + { + this.compatibleMemoryLayoutRunner.RunRetvalConversion(); + } + + [Benchmark] + public void CompatibleCopyTo() + { + this.compatibleMemoryLayoutRunner.RunCopyToConversion(); + } + + [Benchmark] + public void PermutedRetval() + { + this.permutedRunner.RunRetvalConversion(); + } + + [Benchmark] + public void PermutedCopyTo() + { + this.permutedRunner.RunCopyToConversion(); + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ----------------- |------ |----------:|----------:|----------:|-------:|---------:| + // CompatibleRetval | 32 | 53.05 ns | 0.1865 ns | 0.1557 ns | 1.00 | 0.00 | + // CompatibleCopyTo | 32 | 36.12 ns | 0.3596 ns | 0.3003 ns | 0.68 | 0.01 | + // PermutedRetval | 32 | 303.61 ns | 5.1697 ns | 4.8358 ns | 5.72 | 0.09 | + // PermutedCopyTo | 32 | 38.05 ns | 0.8053 ns | 1.2297 ns | 0.72 | 0.02 | +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs new file mode 100644 index 0000000000..2bc3ee9716 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs @@ -0,0 +1,83 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4 + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref Unsafe.Add(ref destBaseRef, i)); + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // ---------- |------ |---------:|---------:|---------:|-------:| + // UseRetval | 32 | 109.0 ns | 1.202 ns | 1.125 ns | 1.00 | + // UseCopyTo | 32 | 108.6 ns | 1.151 ns | 1.020 ns | 1.00 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs new file mode 100644 index 0000000000..c6daf0f1e2 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs @@ -0,0 +1,95 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_ConvertToVector4_AsPartOfCompositeOperation + { + struct ConversionRunner + where T : struct, ITestPixel + { + private T[] source; + + private Vector4[] dest; + + public ConversionRunner(int count) + { + this.source = new T[count]; + this.dest = new Vector4[count]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunRetvalConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp; + + for (int i = 0; i < count; i++) + { + temp = Unsafe.Add(ref sourceBaseRef, i).ToVector4(); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RunCopyToConversion() + { + int count = this.source.Length; + + ref T sourceBaseRef = ref this.source[0]; + ref Vector4 destBaseRef = ref this.dest[0]; + + Vector4 temp = default; + + for (int i = 0; i < count; i++) + { + Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref temp); + + // manipulate pixel before saving to dest buffer: + temp.W = 0; + + Unsafe.Add(ref destBaseRef, i) = temp; + } + } + } + + private ConversionRunner runner; + + [Params(32)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.runner = new ConversionRunner(this.Count); + } + + [Benchmark(Baseline = true)] + public void UseRetval() + { + this.runner.RunRetvalConversion(); + } + + [Benchmark] + public void UseCopyTo() + { + this.runner.RunCopyToConversion(); + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // ---------- |------ |---------:|---------:|---------:|-------:|---------:| + // UseRetval | 32 | 120.2 ns | 1.560 ns | 1.383 ns | 1.00 | 0.00 | + // UseCopyTo | 32 | 121.7 ns | 2.439 ns | 2.281 ns | 1.01 | 0.02 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs new file mode 100644 index 0000000000..40893914e1 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -0,0 +1,176 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + public class PixelConversion_Rgba32_To_Argb32 + { + private Rgba32[] source; + + private Argb32[] dest; + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Argb32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + Rgba32 s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i += 2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Argb32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); + ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); + ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToArgb32(lo); + hi = FromRgba32.ToArgb32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | + // -------------------- |------ |----------:|----------:|----------:|-------:| + // Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 | + // Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 | + // Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 | + // Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 | + // BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 | + // BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs new file mode 100644 index 0000000000..a8fea68661 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -0,0 +1,392 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes.Jobs; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + //[MonoJob] + //[RyuJitX64Job] + public class PixelConversion_Rgba32_To_Bgra32 + { + private Rgba32[] source; + + private Bgra32[] dest; + + [StructLayout(LayoutKind.Sequential)] + struct Tuple4OfUInt32 + { + public uint V0, V1, V2, V3; + + public void ConvertMe() + { + this.V0 = FromRgba32.ToBgra32(this.V0); + this.V1 = FromRgba32.ToBgra32(this.V1); + this.V2 = FromRgba32.ToBgra32(this.V2); + this.V3 = FromRgba32.ToBgra32(this.V3); + } + } + + [Params(64)] + public int Count { get; set; } + + [GlobalSetup] + public void Setup() + { + this.source = new Rgba32[this.Count]; + this.dest = new Bgra32[this.Count]; + } + + [Benchmark(Baseline = true)] + public void Default() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Default_GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i++) + { + ref Rgba32 s = ref Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i).FromRgba32(s); + } + } + + [Benchmark] + public void Default_Generic() + { + Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + [Benchmark] + public void Default_Group2() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i+=2) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + Rgba32 s1 = Unsafe.Add(ref s0, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + d0.FromRgba32(s0); + Unsafe.Add(ref d0, 1).FromRgba32(s1); + } + } + + [Benchmark] + public void Default_Group4() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Group4GenericImpl(ReadOnlySpan source, Span dest) + where TPixel : struct, IPixel + { + ref Rgba32 sBase = ref MemoryMarshal.GetReference(source); + ref TPixel dBase = ref MemoryMarshal.GetReference(dest); + + for (int i = 0; i < source.Length; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + Rgba32 s3 = Unsafe.Add(ref s2, 1); + + ref TPixel d0 = ref Unsafe.Add(ref dBase, i); + ref TPixel d1 = ref Unsafe.Add(ref d0, 1); + ref TPixel d2 = ref Unsafe.Add(ref d1, 1); + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + Unsafe.Add(ref d2, 1).FromRgba32(s3); + } + } + + //[Benchmark] + public void Default_Group4_Generic() + { + Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); + } + + //[Benchmark] + public void Default_Group8() + { + ref Rgba32 sBase = ref this.source[0]; + ref Bgra32 dBase = ref this.dest[0]; + + for (int i = 0; i < this.Count / 4; i += 4) + { + ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i); + ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1); + ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1); + ref Rgba32 s3 = ref Unsafe.Add(ref s1, 1); + + ref Rgba32 s4 = ref Unsafe.Add(ref s3, 1); + ref Rgba32 s5 = ref Unsafe.Add(ref s4, 1); + ref Rgba32 s6 = ref Unsafe.Add(ref s5, 1); + Rgba32 s7 = Unsafe.Add(ref s6, 1); + + ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); + ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); + ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); + ref Bgra32 d3 = ref Unsafe.Add(ref d2, 1); + ref Bgra32 d4 = ref Unsafe.Add(ref d3, 1); + + ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1); + ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1); + + + d0.FromRgba32(s0); + d1.FromRgba32(s1); + d2.FromRgba32(s2); + d3.FromRgba32(s3); + + d4.FromRgba32(s4); + d5.FromRgba32(s5); + d6.FromRgba32(s6); + Unsafe.Add(ref d6, 1).FromRgba32(s7); + } + } + + [Benchmark] + public void BitOps() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + uint s = Unsafe.Add(ref sBase, i); + Unsafe.Add(ref dBase, i) = FromRgba32.ToBgra32(s); + } + } + + [Benchmark] + public void Bitops_Tuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Tuple4OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + ref Tuple4OfUInt32 d = ref Unsafe.Add(ref dBase, i); + d = Unsafe.Add(ref sBase, i); + d.ConvertMe(); + } + } + + //[Benchmark] + public void Bitops_SingleTuple() + { + ref Tuple4OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + + for (int i = 0; i < this.Count / 4; i++) + { + Unsafe.Add(ref sBase, i).ConvertMe(); + } + } + + //[Benchmark] + public void Bitops_Simd() + { + ref Octet.OfUInt32 sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 8; i++) + { + BitopsSimdImpl(ref Unsafe.Add(ref sBase, i), ref Unsafe.Add(ref dBase, i)); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct B + { + public uint tmp2, tmp5, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23; + } + + [StructLayout(LayoutKind.Sequential)] + struct C + { + public uint tmp3, tmp6, tmp9, tmp12, tmp15, tmp18, tmp21, tmp24; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void BitopsSimdImpl(ref Octet.OfUInt32 s, ref Octet.OfUInt32 d) + { + Vector sVec = Unsafe.As>(ref s); + Vector aMask = new Vector(0xFF00FF00); + Vector bMask = new Vector(0x00FF00FF); + + Vector aa = sVec & aMask; + Vector bb = sVec & bMask; + + B b = Unsafe.As, B>(ref bb); + + C c = default; + + c.tmp3 = (b.tmp2 << 16) | (b.tmp2 >> 16); + c.tmp6 = (b.tmp5 << 16) | (b.tmp5 >> 16); + c.tmp9 = (b.tmp8 << 16) | (b.tmp8 >> 16); + c.tmp12 = (b.tmp11 << 16) | (b.tmp11 >> 16); + c.tmp15 = (b.tmp14 << 16) | (b.tmp14 >> 16); + c.tmp18 = (b.tmp17 << 16) | (b.tmp17 >> 16); + c.tmp21 = (b.tmp20 << 16) | (b.tmp20 >> 16); + c.tmp24 = (b.tmp23 << 16) | (b.tmp23 >> 16); + + Vector cc = Unsafe.As>(ref c); + Vector dd = aa + cc; + + d = Unsafe.As, Octet.OfUInt32>(ref dd); + } + + //[Benchmark] + public void BitOps_Group2() + { + ref uint sBase = ref Unsafe.As(ref this.source[0]); + ref uint dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count; i++) + { + ref uint s0 = ref Unsafe.Add(ref sBase, i); + uint s1 = Unsafe.Add(ref s0, 1); + + ref uint d0 = ref Unsafe.Add(ref dBase, i); + d0 = FromRgba32.ToBgra32(s0); + Unsafe.Add(ref d0, 1) = FromRgba32.ToBgra32(s1); + } + } + + [Benchmark] + public void BitOps_GroupAsULong() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + lo = FromRgba32.ToBgra32(lo); + hi = FromRgba32.ToBgra32(hi); + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + //[Benchmark] + public void BitOps_GroupAsULong_V2() + { + ref ulong sBase = ref Unsafe.As(ref this.source[0]); + ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < this.Count / 2; i++) + { + ulong s = Unsafe.Add(ref sBase, i); + uint lo = (uint)s; + uint hi = (uint)(s >> 32); + + uint tmp1 = lo & 0xFF00FF00; + uint tmp4 = hi & 0xFF00FF00; + + uint tmp2 = lo & 0x00FF00FF; + uint tmp5 = hi & 0x00FF00FF; + + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + uint tmp6 = (tmp5 << 16) | (tmp5 >> 16); + + lo = tmp1 + tmp3; + hi = tmp4 + tmp6; + + s = (ulong)(hi << 32) | lo; + + Unsafe.Add(ref dBase, i) = s; + } + } + + public static class FromRgba32 + { + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToArgb32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // ROL(8, packedRgba) = [bb gg rr aa] + return (packedRgba << 8) | (packedRgba >> 24); + } + + /// + /// Converts a packed to . + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static uint ToBgra32(uint packedRgba) + { + // packedRgba = [aa bb gg rr] + // tmp1 = [aa 00 gg 00] + // tmp2 = [00 bb 00 rr] + // tmp3=ROL(16, tmp2) = [00 rr 00 bb] + // tmp1 + tmp3 = [aa rr gg bb] + uint tmp1 = packedRgba & 0xFF00FF00; + uint tmp2 = packedRgba & 0x00FF00FF; + uint tmp3 = (tmp2 << 16) | (tmp2 >> 16); + return tmp1 + tmp3; + } + } + + + // RESULTS: + // Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | + // -------------------- |------ |---------:|----------:|----------:|-------:|---------:| + // Default | 64 | 82.67 ns | 0.6737 ns | 0.5625 ns | 1.00 | 0.00 | + // Default_Generic | 64 | 88.73 ns | 1.7959 ns | 1.7638 ns | 1.07 | 0.02 | + // Default_Group2 | 64 | 91.03 ns | 1.5237 ns | 1.3508 ns | 1.10 | 0.02 | + // Default_Group4 | 64 | 86.62 ns | 1.5737 ns | 1.4720 ns | 1.05 | 0.02 | + // BitOps | 64 | 57.45 ns | 0.6067 ns | 0.5066 ns | 0.69 | 0.01 | + // Bitops_Tuple | 64 | 75.47 ns | 1.1824 ns | 1.1060 ns | 0.91 | 0.01 | + // BitOps_GroupAsULong | 64 | 65.42 ns | 0.7157 ns | 0.6695 ns | 0.79 | 0.01 | + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs new file mode 100644 index 0000000000..76de794eca --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -0,0 +1,89 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestArgb : ITestPixel + { + public byte A, R, G, B; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 p) + { + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 p) + { + this.R = p.R; + this.G = p.G; + this.B = p.B; + this.A = p.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 p) + { + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 p) + { + this.R = (byte)p.X; + this.G = (byte)p.Y; + this.B = (byte)p.Z; + this.A = (byte)p.W; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return new Rgba32(this.R, this.G, this.B, this.A); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest.R = this.R; + dest.G = this.G; + dest.B = this.B; + dest.A = this.A; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.R, this.G, this.B, this.A); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + dest.X = this.R; + dest.Y = this.G; + dest.Z = this.B; + dest.W = this.A; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs new file mode 100644 index 0000000000..36d5f3e5b9 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -0,0 +1,71 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion +{ + [StructLayout(LayoutKind.Sequential)] + struct TestRgba : ITestPixel + { + public byte R, G, B, A; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) + { + this = Unsafe.As(ref source); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + + public void FromVector4(Vector4 source) + { + throw new System.NotImplementedException(); + } + + public void FromVector4(ref Vector4 source) + { + throw new System.NotImplementedException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() + { + return Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToRgba32(ref Rgba32 dest) + { + dest = Unsafe.As(ref this); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToVector4() + { + return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void CopyToVector4(ref Vector4 dest) + { + var tmp = new Vector4(this.R, this.G, this.B, this.A); + tmp *= new Vector4(1f / 255f); + dest = tmp; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs deleted file mode 100644 index f5bd135e12..0000000000 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs +++ /dev/null @@ -1,209 +0,0 @@ -// ReSharper disable InconsistentNaming - -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Benchmarks.General -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - using BenchmarkDotNet.Attributes; - - public class PixelConversion_ConvertFromRgba32 - { - interface ITestPixel - where T : struct, ITestPixel - { - void FromRgba32(Rgba32 source); - - void FromRgba32(ref Rgba32 source); - - void FromBytes(byte r, byte g, byte b, byte a); - } - - [StructLayout(LayoutKind.Sequential)] - struct TestArgb : ITestPixel - { - private byte a, r, g, b; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 p) - { - this.r = p.R; - this.g = p.G; - this.b = p.B; - this.a = p.A; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - - [StructLayout(LayoutKind.Sequential)] - struct TestRgba : ITestPixel - { - private byte r, g, b, a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 source) - { - this = Unsafe.As(ref source); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) - { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - } - - struct ConversionRunner - where T : struct, ITestPixel - { - private T[] dest; - - private Rgba32[] source; - - public ConversionRunner(int count) - { - this.dest = new T[count]; - this.source = new Rgba32[count]; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunByRefConversion() - { - int count = this.dest.Length; - - ref T destBaseRef = ref this.dest[0]; - ref Rgba32 sourceBaseRef = ref this.source[0]; - - for (int i = 0; i < count; i++) - { - Unsafe.Add(ref destBaseRef, i).FromRgba32(ref Unsafe.Add(ref sourceBaseRef, i)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunByValConversion() - { - int count = this.dest.Length; - - ref T destBaseRef = ref this.dest[0]; - ref Rgba32 sourceBaseRef = ref this.source[0]; - - for (int i = 0; i < count; i++) - { - Unsafe.Add(ref destBaseRef, i).FromRgba32(Unsafe.Add(ref sourceBaseRef, i)); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunFromBytesConversion() - { - int count = this.dest.Length; - - ref T destBaseRef = ref this.dest[0]; - ref Rgba32 sourceBaseRef = ref this.source[0]; - - for (int i = 0; i < count; i++) - { - ref Rgba32 s = ref Unsafe.Add(ref sourceBaseRef, i); - Unsafe.Add(ref destBaseRef, i).FromBytes(s.R, s.G, s.B, s.A); - } - } - } - - private ConversionRunner compatibleMemLayoutRunner; - - private ConversionRunner permutedRunner; - - [Params(32)] - public int Count { get; set; } - - [GlobalSetup] - public void Setup() - { - this.compatibleMemLayoutRunner = new ConversionRunner(this.Count); - this.permutedRunner = new ConversionRunner(this.Count); - } - - [Benchmark(Baseline = true)] - public void CompatibleByRef() - { - this.compatibleMemLayoutRunner.RunByRefConversion(); - } - - [Benchmark] - public void CompatibleByVal() - { - this.compatibleMemLayoutRunner.RunByValConversion(); - } - - [Benchmark] - public void CompatibleFromBytes() - { - this.compatibleMemLayoutRunner.RunFromBytesConversion(); - } - - - [Benchmark] - public void PermutedByRef() - { - this.permutedRunner.RunByRefConversion(); - } - - [Benchmark] - public void PermutedByVal() - { - this.permutedRunner.RunByValConversion(); - } - - [Benchmark] - public void PermutedFromBytes() - { - this.permutedRunner.RunFromBytesConversion(); - } - } - - /* - * Results: - * Method | Count | Mean | StdDev | Scaled | Scaled-StdDev | - * ------------------ |------ |----------- |---------- |------- |-------------- | - * CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 | - * CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 | - * CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 | - * PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 | - * PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 | - * PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 | - * - * !!! Conclusion !!! - * All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution. - * In memory compatible cases we should use the optimized Bulk-copying variant anyways, - * so there is no benefit introducing non-bulk API-s other than PackFromBytes() OR PackFromRgba32(). - */ -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs new file mode 100644 index 0000000000..ca85a350cc --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -0,0 +1,113 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + [Config(typeof(Config.ShortClr))] + public class UInt32ToSingle + { + private float[] data; + + private const int Count = 32; + + [GlobalSetup] + public void Setup() + { + this.data = new float[Count]; + } + + [Benchmark(Baseline = true)] + public void MagicMethod() + { + ref Vector b = ref Unsafe.As>(ref this.data[0]); + + int n = Count / Vector.Count; + + var bVec = new Vector(256.0f / 255.0f); + var magicFloat = new Vector(32768.0f); + var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f + var mask = new Vector(255); + + for (int i = 0; i < n; i++) + { + // union { float f; uint32_t i; } u; + // u.f = 32768.0f + x * (255.0f / 256.0f); + // return (uint8_t)u.i; + + ref Vector df = ref Unsafe.Add(ref b, i); + + var vi = Vector.AsVectorUInt32(df); + vi &= mask; + vi |= magicInt; + + var vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + + df = vf; + } + } + + [Benchmark] + public void StandardSimd() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); + v *= scale; + Unsafe.Add(ref bf, i) = v; + } + } + + [Benchmark] + public void StandardSimdFromInt() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + Vector u = Unsafe.Add(ref bu, i); + Vector v = Vector.ConvertToSingle(u); + v *= scale; + Unsafe.Add(ref bf, i) = v; + } + } + + + [Benchmark] + public void StandardSimdFromInt_RefCast() + { + int n = Count / Vector.Count; + + ref Vector bf = ref Unsafe.As>(ref this.data[0]); + ref Vector bu = ref Unsafe.As, Vector>(ref bf); + + var scale = new Vector(1f / 255f); + + for (int i = 0; i < n; i++) + { + ref Vector fRef = ref Unsafe.Add(ref bf, i); + + Vector du = Vector.AsVectorInt32(fRef); + Vector v = Vector.ConvertToSingle(du); + v *= scale; + + fRef = v; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs new file mode 100644 index 0000000000..2bc3af4c98 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -0,0 +1,64 @@ +using System.Numerics; +using System.Runtime.CompilerServices; + +using BenchmarkDotNet.Attributes; + +using SixLabors.ImageSharp.Tuples; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + [Config(typeof(Config.ShortClr))] + public class WidenBytesToUInt32 + { + private byte[] source; + + private uint[] dest; + + private const int Count = 64; + + [GlobalSetup] + public void Setup() + { + this.source = new byte[Count]; + this.dest = new uint[Count]; + } + + [Benchmark(Baseline = true)] + public void Standard() + { + const int N = Count / 8; + + ref Octet.OfByte sBase = ref Unsafe.As(ref this.source[0]); + ref Octet.OfUInt32 dBase = ref Unsafe.As(ref this.dest[0]); + + for (int i = 0; i < N; i++) + { + Unsafe.Add(ref dBase, i).LoadFrom(ref Unsafe.Add(ref sBase, i)); + } + } + + [Benchmark] + public void Simd() + { + int n = Count / Vector.Count; + + ref Vector sBase = ref Unsafe.As>(ref this.source[0]); + ref Vector dBase = ref Unsafe.As>(ref this.dest[0]); + + for (int i = 0; i < n; i++) + { + Vector b = Unsafe.Add(ref sBase, i); + + Vector.Widen(b, out Vector s0, out Vector s1); + Vector.Widen(s0, out Vector w0, out Vector w1); + Vector.Widen(s1, out Vector w2, out Vector w3); + + ref Vector d = ref Unsafe.Add(ref dBase, i * 4); + d = w0; + Unsafe.Add(ref d, 1) = w1; + Unsafe.Add(ref d, 2) = w2; + Unsafe.Add(ref d, 3) = w3; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs index d9cf65d4be..cdd56fa074 100644 --- a/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs +++ b/tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Benchmarks public class PorterDuffBulkVsPixel : BenchmarkBase { + private Configuration Configuration => Configuration.Default; + private void BulkVectorConvert( Span destination, Span background, @@ -35,15 +37,15 @@ namespace SixLabors.ImageSharp.Benchmarks Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToVector4(this.Configuration, background, backgroundSpan); + PixelOperations.Instance.ToVector4(this.Configuration, source, sourceSpan); for (int i = 0; i < destination.Length; i++) { destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.FromVector4(this.Configuration, destinationSpan, destination); } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index ff2e57b974..729971548c 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.Benchmarks float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); TPixel packed = default(TPixel); - packed.PackFromVector4( + packed.FromVector4( PremultipliedLerp( sourceColor, glowColor.ToVector4(), diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index f53061d4e1..148b253281 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -22,15 +22,17 @@ namespace SixLabors.ImageSharp.Benchmarks private Bitmap sourceBitmap; - public const int SourceSize = 3032; + [Params(3032)] + public int SourceSize { get; set; } - public const int DestSize = 400; + [Params(400)] + public int DestSize { get; set; } [GlobalSetup] public void Setup() { - this.sourceImage = new Image(this.Configuration, SourceSize, SourceSize); - this.sourceBitmap = new Bitmap(SourceSize, SourceSize); + this.sourceImage = new Image(this.Configuration, this.SourceSize, this.SourceSize); + this.sourceBitmap = new Bitmap(this.SourceSize, this.SourceSize); } [GlobalCleanup] @@ -43,14 +45,17 @@ namespace SixLabors.ImageSharp.Benchmarks [Benchmark(Baseline = true)] public int SystemDrawing() { - using (var destination = new Bitmap(DestSize, DestSize)) + using (var destination = new Bitmap(this.DestSize, this.DestSize)) { - using (var graphics = Graphics.FromImage(destination)) + using (var g = Graphics.FromImage(destination)) { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(this.sourceBitmap, 0, 0, DestSize, DestSize); + g.CompositingMode = CompositingMode.SourceCopy; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + g.CompositingQuality = CompositingQuality.HighQuality; + g.SmoothingMode = SmoothingMode.HighQuality; + + g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize); } return destination.Width; @@ -83,15 +88,60 @@ namespace SixLabors.ImageSharp.Benchmarks { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic); + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } + + // RESULTS (2018 October): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-IGUFBA : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-DZFERG : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | SourceSize | DestSize | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------- |-------- |----------- |--------- |----------:|----------:|----------:|-------:|---------:|----------:| + // SystemDrawing | Clr | 3032 | 400 | 101.13 ms | 18.659 ms | 1.0542 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Clr | 3032 | 400 | 122.05 ms | 19.622 ms | 1.1087 ms | 1.21 | 0.01 | 21856 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Clr | 3032 | 400 | 41.34 ms | 54.841 ms | 3.0986 ms | 0.41 | 0.03 | 28000 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Clr | 3032 | 400 | 31.68 ms | 12.782 ms | 0.7222 ms | 0.31 | 0.01 | 28256 B | + // | | | | | | | | | | + // SystemDrawing | Core | 3032 | 400 | 100.37 ms | 18.479 ms | 1.0441 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | 3032 | 400 | 73.03 ms | 10.540 ms | 0.5955 ms | 0.73 | 0.01 | 21368 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Core | 3032 | 400 | 22.59 ms | 4.863 ms | 0.2748 ms | 0.23 | 0.00 | 25220 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Core | 3032 | 400 | 21.10 ms | 23.362 ms | 1.3200 ms | 0.21 | 0.01 | 25539 B | + } public class Resize_BicubicCompand : ResizeBenchmarkBase { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic, true); + ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true); } + + // RESULTS (2018 October): + // + // BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17134 + // Intel Core i7-7700HQ CPU 2.80GHz (Kaby Lake), 1 CPU, 8 logical and 4 physical cores + // Frequency=2742191 Hz, Resolution=364.6719 ns, Timer=TSC + // .NET Core SDK=2.1.403 + // [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // Job-IGUFBA : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 + // Job-DZFERG : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + // + // Method | Runtime | SourceSize | DestSize | Mean | Error | StdDev | Scaled | ScaledSD | Allocated | + // ----------------------------------------- |-------- |----------- |--------- |----------:|----------:|----------:|-------:|---------:|----------:| + // SystemDrawing | Clr | 3032 | 400 | 100.63 ms | 13.864 ms | 0.7833 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Clr | 3032 | 400 | 156.83 ms | 28.631 ms | 1.6177 ms | 1.56 | 0.02 | 21856 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Clr | 3032 | 400 | 53.43 ms | 38.493 ms | 2.1749 ms | 0.53 | 0.02 | 28512 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Clr | 3032 | 400 | 38.47 ms | 11.969 ms | 0.6763 ms | 0.38 | 0.01 | 28000 B | + // | | | | | | | | | | + // SystemDrawing | Core | 3032 | 400 | 99.87 ms | 23.459 ms | 1.3255 ms | 1.00 | 0.00 | 0 B | + // 'ImageSharp, MaxDegreeOfParallelism = 1' | Core | 3032 | 400 | 108.19 ms | 38.562 ms | 2.1788 ms | 1.08 | 0.02 | 21368 B | + // 'ImageSharp, MaxDegreeOfParallelism = 4' | Core | 3032 | 400 | 36.21 ms | 53.802 ms | 3.0399 ms | 0.36 | 0.03 | 25300 B | + // 'ImageSharp, MaxDegreeOfParallelism = 8' | Core | 3032 | 400 | 26.52 ms | 2.173 ms | 0.1228 ms | 0.27 | 0.00 | 25589 B | } } diff --git a/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs new file mode 100644 index 0000000000..f898576af0 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Samplers/Rotate.cs @@ -0,0 +1,45 @@ +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Benchmarks.Samplers +{ + [Config(typeof(Config.ShortClr))] + public class Rotate + { + [Benchmark] + public Size DoRotate() + { + using (var image = new Image(Configuration.Default, 400, 400, Rgba32.BlanchedAlmond)) + { + image.Mutate(x => x.Rotate(37.5F)); + + return image.Size(); + } + } + } +} + +// Nov 7 2018 +//BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 +//Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores +//.NET Core SDK = 2.1.403 + +// [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT +// Job-KKDIMW : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 +// Job-IUZRFA : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + +//LaunchCount=1 TargetCount=3 WarmupCount=3 + +// #### BEFORE ####: +// Method | Runtime | Mean | Error | StdDev | Allocated | +//--------- |-------- |---------:|----------:|----------:|----------:| +// DoRotate | Clr | 85.19 ms | 13.379 ms | 0.7560 ms | 6 KB | +// DoRotate | Core | 53.51 ms | 9.512 ms | 0.5375 ms | 4.29 KB | + +// #### AFTER ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//--------- |-------- |---------:|---------:|---------:|----------:| +// DoRotate | Clr | 77.08 ms | 23.97 ms | 1.354 ms | 6 KB | +// DoRotate | Core | 40.36 ms | 47.43 ms | 2.680 ms | 4.36 KB | \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Samplers/Skew.cs b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs new file mode 100644 index 0000000000..84819750af --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Samplers/Skew.cs @@ -0,0 +1,45 @@ +using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Benchmarks.Samplers +{ + [Config(typeof(Config.ShortClr))] + public class Skew + { + [Benchmark] + public Size DoSkew() + { + using (var image = new Image(Configuration.Default, 400, 400, Rgba32.BlanchedAlmond)) + { + image.Mutate(x => x.Skew(20, 10)); + + return image.Size(); + } + } + } +} + +// Nov 7 2018 +//BenchmarkDotNet=v0.10.14, OS=Windows 10.0.17763 +//Intel Core i7-6600U CPU 2.60GHz(Skylake), 1 CPU, 4 logical and 2 physical cores +//.NET Core SDK = 2.1.403 + +// [Host] : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT +// Job-KKDIMW : .NET Framework 4.7.1 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.3190.0 +// Job-IUZRFA : .NET Core 2.1.5 (CoreCLR 4.6.26919.02, CoreFX 4.6.26919.02), 64bit RyuJIT + +//LaunchCount=1 TargetCount=3 WarmupCount=3 + +// #### BEFORE ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//------- |-------- |---------:|---------:|----------:|----------:| +// DoSkew | Clr | 78.14 ms | 8.383 ms | 0.4736 ms | 6 KB | +// DoSkew | Core | 44.22 ms | 4.109 ms | 0.2322 ms | 4.28 KB | + +// #### AFTER ####: +//Method | Runtime | Mean | Error | StdDev | Allocated | +//------- |-------- |---------:|----------:|----------:|----------:| +// DoSkew | Clr | 71.63 ms | 25.589 ms | 1.4458 ms | 6 KB | +// DoSkew | Core | 38.99 ms | 8.640 ms | 0.4882 ms | 4.36 KB | \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 0ca3cffa18..4d7b7de759 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -11,7 +11,7 @@ James Jackson-South and contributors James Jackson-South SixLabors.ImageSharp.Sandbox46 - 7.2 + 7.3 @@ -19,7 +19,7 @@ - + diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index fa1d63878a..02d4f80c55 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -3,17 +3,15 @@ // Licensed under the Apache License, Version 2.0. // +using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; +using SixLabors.ImageSharp.Tests.ProfilingBenchmarks; + namespace SixLabors.ImageSharp.Sandbox46 { using System; - using System.Runtime.DesignerServices; - - using SixLabors.ImageSharp.Tests; - using SixLabors.ImageSharp.Tests.Colors; using SixLabors.ImageSharp.Tests.Formats.Jpg; using SixLabors.ImageSharp.Tests.PixelFormats; using SixLabors.ImageSharp.Tests.Processing.Processors.Transforms; - using SixLabors.ImageSharp.Tests.Processing.Transforms; using Xunit.Abstractions; @@ -21,15 +19,9 @@ namespace SixLabors.ImageSharp.Sandbox46 { private class ConsoleOutput : ITestOutputHelper { - public void WriteLine(string message) - { - Console.WriteLine(message); - } + public void WriteLine(string message) => Console.WriteLine(message); - public void WriteLine(string format, params object[] args) - { - Console.WriteLine(format, args); - } + public void WriteLine(string format, params object[] args) => Console.WriteLine(format, args); } /// @@ -58,20 +50,20 @@ namespace SixLabors.ImageSharp.Sandbox46 private static void RunResizeProfilingTest() { - ResizeProfilingBenchmarks test = new ResizeProfilingBenchmarks(new ConsoleOutput()); + var test = new ResizeProfilingBenchmarks(new ConsoleOutput()); test.ResizeBicubic(2000, 2000); } private static void RunToVector4ProfilingTest() { - PixelOperationsTests.Rgba32 tests = new PixelOperationsTests.Rgba32(new ConsoleOutput()); + var tests = new PixelOperationsTests.Rgba32OperationsTests(new ConsoleOutput()); tests.Benchmark_ToVector4(); } private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); - JpegProfilingBenchmarks benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); + var benchmarks = new JpegProfilingBenchmarks(new ConsoleOutput()); foreach (object[] data in JpegProfilingBenchmarks.DecodeJpegData) { string fileName = (string)data[0]; diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs new file mode 100644 index 0000000000..f6397dbd09 --- /dev/null +++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs @@ -0,0 +1,15 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Advanced +{ + public class AotCompilerTests + { + [Fact] + public void AotCompiler_NoExceptions() => AotCompilerTools.Seed(); + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index eb9a50d185..38c0c21bc9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 7fb5770ddb..96628977fe 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs index 14a1c6fd37..39011bb292 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs index 9a42a9d47d..f7dc365b81 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs index 944fab574e..43300ab88c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs index 836be1bf27..4ab309fe14 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs index fb1982bfc8..e7ff34f494 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs index 7e3c4251bf..844cda4760 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs index a43f0095d7..74ed180f38 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs index 62d08263a6..a3db00e804 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs index 1b30412752..fc202ccc96 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs index 53d33af2b1..3e481d4f64 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs index e465757ef7..078ba44daf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs index 18b8a47397..a65f618835 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs index d00a164c08..49990fb908 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs index d3ff04a759..924b45b4a0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs index 852e56110b..0991657310 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs index 80b72cb2c2..a7a819d1f7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs index 314734ff2e..b83b861be8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs index 389528dcd3..932fdc4105 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs index a2bd7eadc7..4d04418d99 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs index e7f511bab1..3cdaa42792 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs index 3bc4fd519b..6829c62b50 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs index f3940e4d14..0c62ffcc31 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs index 61bfe79634..3b41204f7c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs index 7bc430aa37..bfc0d2ecf1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs index 23cc5082c4..f11b17fff3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs index 04699bde46..de2329c2ec 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs index 98914a6b92..3a1bd10c41 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs index 306d60b531..f3881f10f7 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs index 21cf08dede..644f4577bf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs index 8c07c38d60..41b9dba091 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs index fb415f43ba..5b36beaab9 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs index 3c8aee807a..da77378759 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs index 1fcbb75cb2..96d14c98a6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs index 8c45378ed4..0339730945 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLinearRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs index 67ec26f6d4..fb0e06e6bb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToLms(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs index e309e2d555..5bbcd90875 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs index 3e33f05192..1ee84ef2e5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs index 746e37c0e6..49b99b7052 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieLab(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs index 89d78ece1f..77f0c69699 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs index fbd602d9a0..24e134d732 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLchuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs index c0856a2bc1..761b9851e3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieLuv(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs index 3f5ea4cfd8..2b0350cea1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs index 8443722641..cd1c9f2c3e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs index 327d660c6c..8112f6a198 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs index d162940151..2fed3e9c55 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToHunterLab(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs index 484d302e9a..75634eb51e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToLms(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs index eacdc7ffba..9ea890f101 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs index 4a0c88c841..dbb0c6e200 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLch(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs index 2131ba630b..5fcc59090b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieLuv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs index ac93aaf25b..7ff80c170b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyy(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs index cbb8f7dc4e..8017302059 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCieXyz(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs index 1c9ad170d3..3464fdbbde 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs index 6fd1ba88ec..26af5ddd30 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs index e92ac2e528..dc40ee518e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHunterLab(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs index 575122661a..00569ced2e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs index a3b0cbd953..8a2cd1159e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToRgb(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = converter.ToCieXyz(input); - converter.Convert(inputSpan, actualSpan, actualSpan.Length); + converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs index 2b03ee9883..b01e3a854c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToCmyk(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs index 22f5c6d514..502df84133 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsl(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs index e84ce97237..9adc94af7c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToHsv(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs index f5c7dbae66..94879eee7a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToRgb(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Act var actual = Converter.ToYCbCr(input); - Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + Converter.Convert(inputSpan, actualSpan); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs index cfd48b694d..b1427f4d5f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion Span actualSpan = new CieXyz[5]; - adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint, inputSpan.Length); + adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint); for (int i = 0; i < inputSpan.Length; i++) { diff --git a/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs new file mode 100644 index 0000000000..e1b4fc790c --- /dev/null +++ b/tests/ImageSharp.Tests/Common/EncoderExtensionsTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Text; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Common +{ + public class EncoderExtensionsTests + { + [Fact] + public void GetString_EmptyBuffer_ReturnsEmptyString() + { + var buffer = new ReadOnlySpan(); + + string result = Encoding.UTF8.GetString(buffer); + + Assert.Equal(string.Empty, result); + } + + [Fact] + public void GetString_Buffer_ReturnsString() + { + var buffer = new ReadOnlySpan(new byte[] { 73, 109, 97, 103, 101, 83, 104, 97, 114, 112 }); + + string result = Encoding.UTF8.GetString(buffer); + + Assert.Equal("ImageSharp", result); + } + } +} diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c6c3b68f33..4f8a2cdaf7 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Common { float[] data = new float[Vector.Count]; - var rnd = new Random(); + var rnd = new Random(seed); for (int i = 0; i < Vector.Count; i++) { @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(normalized, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(normalized, dest); byte[] expected = orig.Select(f => (byte)(f)).ToArray(); @@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Tests.Common [InlineData(1, 8)] [InlineData(2, 16)] [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByte_WithNonRoundedData(int seed, int count) { if (this.SkipOnNonAvx2()) { @@ -153,39 +153,168 @@ namespace SixLabors.ImageSharp.Tests.Common byte[] dest = new byte[count]; - SimdUtils.BulkConvertNormalizedFloatToByte(source, dest); + SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByte(source, dest); byte[] expected = source.Select(f => (byte)Math.Round(f * 255f)).ToArray(); Assert.Equal(expected, dest); } - private static float Clamp255(float x) => Math.Min(255f, Math.Max(0f, x)); + public static readonly TheoryData ArraySizesDivisibleBy8 = new TheoryData { 0, 8, 16, 1024 }; + public static readonly TheoryData ArraySizesDivisibleBy4 = new TheoryData { 0, 4, 8, 28, 1020 }; + + public static readonly TheoryData ArraySizesDivisibleBy32 = new TheoryData { 0, 32, 512 }; + + public static readonly TheoryData ArbitraryArraySizes = + new TheoryData + { + 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 520, + }; [Theory] - [InlineData(1, 0)] - [InlineData(1, 8)] - [InlineData(2, 16)] - [InlineData(3, 128)] - public void BulkConvertNormalizedFloatToByteClampOverflows(int seed, int count) + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics256_BulkConvertByteToNormalizedFloat(int count) { if (this.SkipOnNonAvx2()) { return; } - float[] orig = new Random(seed).GenerateRandomRoundedFloatArray(count, -50, 444); - float[] normalized = orig.Select(f => f / 255f).ToArray(); + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } - byte[] dest = new byte[count]; + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertByteToNormalizedFloat(int count) + { + TestImpl_BulkConvertByteToNormalizedFloat( + count, + (s, d) => SimdUtils.BulkConvertByteToNormalizedFloat(s.Span, d.Span)); + } - SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(normalized, dest); + private static void TestImpl_BulkConvertByteToNormalizedFloat( + int count, + Action, Memory> convert) + { + byte[] source = new Random(count).GenerateRandomByteArray(count); + float[] result = new float[count]; + float[] expected = source.Select(b => (float)b / 255f).ToArray(); - byte[] expected = orig.Select(f => (byte)Clamp255(f)).ToArray(); + convert(source, result); - Assert.Equal(expected, dest); + Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy4))] + public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy8))] + public void BasicIntrinsics256_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + if (this.SkipOnNonAvx2()) + { + return; + } + + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesDivisibleBy32))] + public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + } + + [Theory] + [InlineData(1234)] + public void ExtendedIntrinsics_ConvertToSingle(short scale) + { + int n = Vector.Count; + short[] sData = new Random(scale).GenerateRandomInt16Array(2 * n, (short)-scale, scale); + float[] fData = sData.Select(u => (float)u).ToArray(); + + var source = new Vector(sData); + + var expected1 = new Vector(fData, 0); + var expected2 = new Vector(fData, n); + + // Act: + SimdUtils.ExtendedIntrinsics.ConvertToSingle(source, out Vector actual1, out Vector actual2); + + // Assert: + Assert.Equal(expected1, actual1); + Assert.Equal(expected2, actual2); + } + + [Theory] + [MemberData(nameof(ArbitraryArraySizes))] + public void BulkConvertNormalizedFloatToByteClampOverflows(int count) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows(count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span) + ); + + // for small values, let's stress test the implementation a bit: + if (count > 0 && count < 10) + { + for (int i = 0; i < 20; i++) + { + TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + count, + (s, d) => SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(s.Span, d.Span), + i + 42); + } + } + } + + private static void TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( + int count, + Action, Memory> convert, int seed = -1) + { + seed = seed > 0 ? seed : count; + float[] source = new Random(seed).GenerateRandomFloatArray(count, -0.2f, 1.2f); + byte[] expected = source.Select(NormalizedFloatToByte).ToArray(); + byte[] actual = new byte[count]; + + convert(source, actual); + + Assert.Equal(expected, actual); + } + + private static byte NormalizedFloatToByte(float f) => (byte)Math.Min(255f, Math.Max(0f, f * 255f + 0.5f)); + [Theory] [InlineData(0)] [InlineData(7)] @@ -211,7 +340,7 @@ namespace SixLabors.ImageSharp.Tests.Common float[] source = { 0, 7, 42, 255, 0.5f, 1.1f, 2.6f, 16f }; - var expected = source.Select(f => (byte)Math.Round(f)).ToArray(); + byte[] expected = source.Select(f => (byte)Math.Round(f)).ToArray(); source = source.Select(f => f / 255f).ToArray(); @@ -245,8 +374,6 @@ namespace SixLabors.ImageSharp.Tests.Common iiRef = x; - //Tuple8.OfUInt32 ii = Unsafe.As, Tuple8.OfUInt32>(ref x); - ref Tuple8.OfByte d = ref MemoryMarshal.Cast(dest)[0]; d.LoadFrom(ref ii); diff --git a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs b/tests/ImageSharp.Tests/ComplexIntegrationTests.cs deleted file mode 100644 index a260ec33ca..0000000000 --- a/tests/ImageSharp.Tests/ComplexIntegrationTests.cs +++ /dev/null @@ -1,35 +0,0 @@ -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; - -using Xunit; - -namespace SixLabors.ImageSharp.Tests -{ - /// - /// Might be useful to catch complex bugs - /// - public class ComplexIntegrationTests - { - [Theory] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio420)] - [WithFile(TestImages.Jpeg.Baseline.Snake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - [WithFile(TestImages.Jpeg.Baseline.Lake, PixelTypes.Rgba32, 75, JpegSubsample.Ratio444)] - public void LoadResizeSave(TestImageProvider provider, int quality, JpegSubsample subsample) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage(x => x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))) - { - - image.MetaData.ExifProfile = null; // Reduce the size of the file - JpegEncoder options = new JpegEncoder { Subsample = subsample, Quality = quality }; - - provider.Utility.TestName += $"{subsample}_Q{quality}"; - provider.Utility.SaveTestOutputFile(image, "png"); - provider.Utility.SaveTestOutputFile(image, "jpg", options); - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 963d674466..208387e6d1 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -6,6 +6,7 @@ using System.Linq; using Moq; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.IO; + using Xunit; // ReSharper disable InconsistentNaming diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 496692d969..374454afba 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; @@ -75,21 +73,15 @@ namespace SixLabors.ImageSharp.Tests using (Image image = provider.GetImage()) using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(45F); - Matrix3x2 scale = Matrix3x2Extensions.CreateScale(new SizeF(.25F, .25F)); - Matrix3x2 matrix = rotate * scale; + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(45F) + .AppendScale(new SizeF(.25F, .25F)) + .AppendTranslation(new PointF(10, 10)); - // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor - Rectangle srcBounds = blend.Bounds(); - Rectangle destBounds = TransformHelpers.GetTransformedBoundingRectangle(srcBounds, matrix); - Matrix3x2 centeredMatrix = TransformHelpers.GetCenteredTransformMatrix(srcBounds, destBounds, matrix); - - // We pass a new rectangle here based on the dest bounds since we've offset the matrix - blend.Mutate(x => x.Transform( - centeredMatrix, - KnownResamplers.Bicubic, - new Rectangle(0, 0, destBounds.Width, destBounds.Height))); + // Apply a background color so we can see the translation. + blend.Mutate(x => x.Transform(builder).BackgroundColor(NamedColors.HotPink)); + // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); image.Mutate(x => x.DrawImage(blend, position, mode, .75F)); image.DebugSave(provider, new[] { "Transformed" }); diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index d65796d37f..556ec9c9ca 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -283,10 +283,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing { // 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]; + + // TODO: This is incorrect. from -0 to < 0 ?? int orthoCount = 0; for (int offset = -orthoCount; offset < orthoCount; offset++) { - Assert.Equal(colorOnDiagonal, image[i + horizontalSign * offset, i + verticalSign * offset]); + Assert.Equal(colorOnDiagonal, image[i + (horizontalSign * offset), i + (verticalSign * offset)]); } } @@ -302,8 +304,8 @@ namespace SixLabors.ImageSharp.Tests.Drawing [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})] + [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, @@ -312,20 +314,22 @@ namespace SixLabors.ImageSharp.Tests.Drawing int[] stopColorCodes) where TPixel : struct, IPixel { - TPixel[] colors = { - NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, - NamedColors.Red - }; + TPixel[] colors = + { + NamedColors.Navy, NamedColors.LightGreen, NamedColors.Yellow, + NamedColors.Red + }; var coloringVariant = new StringBuilder(); - ColorStop[] colorStops = new ColorStop[stopPositions.Length]; - Rgba32 rgba = default; + var colorStops = new ColorStop[stopPositions.Length]; + for (int i = 0; i < stopPositions.Length; i++) { TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; - color.ToRgba32(ref rgba); colorStops[i] = new ColorStop(position, color); + Rgba32 rgba = default; + color.ToRgba32(ref rgba); coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position); } @@ -333,15 +337,15 @@ namespace SixLabors.ImageSharp.Tests.Drawing provider.VerifyOperation( image => - { - var unicolorLinearGradientBrush = new LinearGradientBrush( - new SixLabors.Primitives.Point(startX, startY), - new SixLabors.Primitives.Point(endX, endY), - GradientRepetitionMode.None, - colorStops); + { + 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)); - }, + image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); + }, variant, false, false); diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 32f723e72a..639b3fe81a 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing vec.W = alpha; TPixel fillColor = default; - fillColor.PackFromVector4(vec); + fillColor.FromVector4(vec); using (Image image = provider.GetImage()) { diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index a8fb187ced..94e12f8581 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var c = NamedColors.Red.ToVector4(); c.W *= 0.5f; var pixel = default(TPixel); - pixel.PackFromVector4(c); + pixel.FromVector4(c); img.Mutate( x => x.Fill( diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs index 44bb160ce3..20ccb25a54 100644 --- a/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawTextOnImageTests.cs @@ -11,6 +11,8 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; +using Xunit.Abstractions; + // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Drawing.Text @@ -22,8 +24,50 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text private const string TestText = "Sphinx of black quartz, judge my vow\n0123456789"; - public static ImageComparer TextDrawingComparer = ImageComparer.TolerantPercentage(0.01f); - public static ImageComparer OutlinedTextDrawingComparer = ImageComparer.TolerantPercentage(0.5f, 3); + public static ImageComparer TextDrawingComparer = ImageComparer.TolerantPercentage(1e-5f); + public static ImageComparer OutlinedTextDrawingComparer = ImageComparer.TolerantPercentage(5e-4f); + + public DrawTextOnImageTests(ITestOutputHelper output) + { + this.Output = output; + } + + private ITestOutputHelper Output { get; } + + [Theory] + [WithSolidFilledImages(276, 336, "White", PixelTypes.Rgba32)] + public void DoesntThrowExceptionWhenOverlappingRightEdge_Issue688(TestImageProvider provider) + where TPixel : struct, IPixel + { + Font font = CreateFont("OpenSans-Regular.ttf", 36); + TPixel color = NamedColors.Black; + float padding = 5; + var text = "A short piece of text"; + + using (var img = provider.GetImage()) + { + float targetWidth = img.Width - (padding * 2); + float targetHeight = img.Height - (padding * 2); + + // measure the text size + SizeF size = TextMeasurer.Measure(text, new RendererOptions(font)); + + //find out how much we need to scale the text to fill the space (up or down) + float scalingFactor = Math.Min(img.Width / size.Width, img.Height / size.Height); + + //create a new font + Font scaledFont = new Font(font, scalingFactor * font.Size); + + var center = new PointF(img.Width / 2, img.Height / 2); + var textGraphicOptions = new TextGraphicsOptions(true) + { + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center + }; + + img.Mutate(i => i.DrawText(textGraphicOptions, text, scaledFont, color, center)); + } + } [Theory] [WithSolidFilledImages(200, 100, "White", PixelTypes.Rgba32, 50, 0, 0, "SixLaborsSampleAB.woff", AB)] @@ -87,8 +131,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text TPixel color = NamedColors.Black; + // Based on the reported 0.0270% difference with AccuracyMultiple = 8 + // We should avoid quality regressions leading to higher difference! + var comparer = ImageComparer.TolerantPercentage(0.03f); + provider.VerifyOperation( - TextDrawingComparer, + comparer, img => { img.Mutate(c => c.DrawText(textOptions, sb.ToString(), font, color, new PointF(10, 5))); @@ -151,6 +199,31 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text appendSourceFileOrDescription: true); } + [Theory] + [WithSolidFilledImages(1000, 1500, "White", PixelTypes.Rgba32, "OpenSans-Regular.ttf")] + public void TextPositioningIsRobust(TestImageProvider provider, string fontName) + where TPixel : struct, IPixel + { + Font font = CreateFont(fontName, 30); + + string text = Repeat("Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!\n", + 20); + var textOptions = new TextGraphicsOptions(true) { WrapTextWidth = 1000 }; + + string details = fontName.Replace(" ", ""); + + // Based on the reported 0.1755% difference with AccuracyMultiple = 8 + // We should avoid quality regressions leading to higher difference! + var comparer = ImageComparer.TolerantPercentage(0.2f); + + provider.RunValidatingProcessorTest( + x => x.DrawText(textOptions, text, font, NamedColors.Black, new PointF(10, 50)), + details, + comparer, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } + private static string Repeat(string str, int times) => string.Concat(Enumerable.Repeat(str, times)); private static string ToTestOutputDisplayText(string text) @@ -167,5 +240,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Text Font font = fontCollection.Install(fontPath).CreateFont(size); return font; } + + } } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 1d21c65fda..158a085d5a 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -67,7 +67,8 @@ namespace SixLabors.ImageSharp.Tests new TheoryData { nameof(KnownQuantizers.Octree), - nameof(KnownQuantizers.Palette), + nameof(KnownQuantizers.WebSafe), + nameof(KnownQuantizers.Werner), nameof(KnownQuantizers.Wu) }; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 6d2a74c03b..5bfbb058be 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -1,20 +1,20 @@ // 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.Text; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; -using System.IO; -using SixLabors.ImageSharp.Advanced; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Gif { - using System.Collections.Generic; - using SixLabors.ImageSharp.MetaData; - using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; - public class GifDecoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; @@ -70,6 +70,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } + [Fact] + public unsafe void Decode_NonTerminatedFinalFrame() + { + var testFile = TestFile.Create(TestImages.Gif.Rings); + + int length = testFile.Bytes.Length - 2; + + fixed (byte* data = testFile.Bytes.AsSpan(0, length)) + { + using (var stream = new UnmanagedMemoryStream(data, length)) + { + var decoder = new GifDecoder(); + + using (Image image = decoder.Decode(Configuration.Default, stream)) + { + Assert.Equal((200, 200), (image.Width, image.Height)); + } + } + } + } + [Theory] [MemberData(nameof(RatioFiles))] public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index c5c971962c..b74a7a85f9 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif public class GifEncoderTests { private const PixelTypes TestPixelTypes = PixelTypes.Rgba32 | PixelTypes.RgbaVector | PixelTypes.Argb32; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.001F); + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0015F); public static readonly TheoryData RatioFiles = new TheoryData @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif { // Use the palette quantizer without dithering to ensure results // are consistant - Quantizer = new PaletteQuantizer(false) + Quantizer = new WebSafePaletteQuantizer(false) }; // Always save as we need to compare the encoded output. diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs index c720fdd4a7..4b1abf9094 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.CopyToBufferArea.cs @@ -7,14 +7,16 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Tests.Formats.Jpg.Utils; +using SixLabors.Memory; using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Formats.Jpg { - public partial class Block8x8FTests : JpegFixture + public partial class Block8x8FTests { public class CopyToBufferArea : JpegFixture { @@ -37,17 +39,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - // TODO: This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative. - [Fact(Skip = "This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative.")] - //[Fact] - public void Unscaled() + [Fact] + public void Copy1x1Scale() { Block8x8F block = CreateRandomFloatBlock(0, 100); - using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(20, 20, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(5, 10, 8, 8); - block.CopyTo(area); + block.Copy1x1Scale(area); Assert.Equal(block[0, 0], buffer[5, 10]); Assert.Equal(block[1, 0], buffer[6, 10]); @@ -59,22 +59,20 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - // TODO: This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative. - [Theory(Skip = "This test occasionally fails from the same reason certain ICC tests are failing. Should be false negative.")] - //[Theory] + [Theory] [InlineData(1, 1)] [InlineData(1, 2)] [InlineData(2, 1)] [InlineData(2, 2)] [InlineData(4, 2)] [InlineData(4, 4)] - public void Scaled(int horizontalFactor, int verticalFactor) + public void CopyTo(int horizontalFactor, int verticalFactor) { Block8x8F block = CreateRandomFloatBlock(0, 100); var start = new Point(50, 50); - using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100)) + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(100, 100, AllocationOptions.Clean)) { BufferArea area = buffer.GetArea(start.X, start.Y, 8 * horizontalFactor, 8 * verticalFactor); block.CopyTo(area, horizontalFactor, verticalFactor); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs index e72f4945b7..81c76390c1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs @@ -408,5 +408,47 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg Assert.Equal(original[i] * 42f, actual[i]); } } + + [Fact] + public void LoadFromUInt16Scalar() + { + if (this.SkipOnNonAvx2Runner()) + { + return; + } + + short[] data = Create8x8ShortData(); + + var source = new Block8x8(data); + + Block8x8F dest = default; + dest.LoadFromInt16Scalar(ref source); + + for (int i = 0; i < Block8x8F.Size; i++) + { + Assert.Equal((float)data[i], dest[i]); + } + } + + [Fact] + public void LoadFromUInt16ExtendedAvx2() + { + if (this.SkipOnNonAvx2Runner()) + { + return; + } + + short[] data = Create8x8ShortData(); + + var source = new Block8x8(data); + + Block8x8F dest = default; + dest.LoadFromInt16ExtendedAvx2(ref source); + + for (int i = 0; i < Block8x8F.Size; i++) + { + Assert.Equal((float)data[i], dest[i]); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs index dedb094bc2..341d67f0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/GenericBlock8x8Tests.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { var rgba = new Rgba32((byte)(i + 1), (byte)(j + 1), (byte)200, (byte)255); var color = default(TPixel); - color.PackFromRgba32(rgba); + color.FromRgba32(rgba); pixels[i, j] = color; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 6bc559978c..40de25b30a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -10,7 +10,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public static string[] BaselineTestJpegs = { TestImages.Jpeg.Baseline.Calliphora, - TestImages.Jpeg.Baseline.Cmyk, TestImages.Jpeg.Baseline.Ycck, + TestImages.Jpeg.Baseline.Cmyk, + TestImages.Jpeg.Baseline.Ycck, TestImages.Jpeg.Baseline.Jpeg400, TestImages.Jpeg.Baseline.Testorig420, @@ -19,14 +20,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Jpeg444, TestImages.Jpeg.Baseline.Bad.BadEOF, - TestImages.Jpeg.Issues.MultiHuffmanBaseline394, TestImages.Jpeg.Baseline.MultiScanBaselineCMYK, TestImages.Jpeg.Baseline.Bad.BadRST, TestImages.Jpeg.Issues.MultiHuffmanBaseline394, TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, TestImages.Jpeg.Issues.InvalidEOI695, TestImages.Jpeg.Issues.ExifResizeOutOfRange696, - TestImages.Jpeg.Issues.InvalidAPP0721 + TestImages.Jpeg.Issues.InvalidAPP0721, + TestImages.Jpeg.Issues.ExifGetString750Load, + TestImages.Jpeg.Issues.ExifGetString750Transform }; public static string[] ProgressiveTestJpegs = @@ -42,22 +44,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Progressive.Bad.ExifUndefType, TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, - TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, TestImages.Jpeg.Issues.DhtHasWrongLength624, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723A, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723B, TestImages.Jpeg.Issues.OrderedInterleavedProgressive723C }; - /// - /// 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 { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 5977e59cf3..15f7f92a83 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -49,7 +49,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, TestImages.Jpeg.Issues.InvalidEOI695, - TestImages.Jpeg.Issues.ExifResizeOutOfRange696 + TestImages.Jpeg.Issues.ExifResizeOutOfRange696, + TestImages.Jpeg.Issues.ExifGetString750Transform }; return !TestEnvironment.Is64BitProcess && largeImagesToSkipOn32Bit.Contains(provider.SourceFileOrDescription); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs index cfa421a82b..b3219115db 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var imageFrame = new ImageFrame(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight)) { pp.DoPostProcessorStep(imageFrame); @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { string imageFile = provider.SourceFileOrDescription; using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile)) - using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder)) + using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder)) using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight)) { pp.PostProcess(image.Frames.RootFrame); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs index d14fbc3fc3..89fdd5745e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/JpegFixture.cs @@ -58,7 +58,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils { for (int j = 0; j < 8; j++) { - result[i * 8 + j] = (short)(i * 10 + j); + short val = (short)(i * 10 + j); + if ((i + j) % 2 == 0) + { + val *= -1; + } + result[i * 8 + j] = val; } } return result; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 57d92fa151..e4fcd10c5f 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -67,9 +67,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils for (int y = 0; y < result.HeightInBlocks; y++) { + Span blockRow = c.SpectralBlocks.GetRowSpan(y); for (int x = 0; x < result.WidthInBlocks; x++) { - short[] data = c.GetBlockReference(x, y).ToArray(); + short[] data = blockRow[x].ToArray(); result.MakeBlock(data, y, x); } } @@ -103,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils var v = new Vector4(val, val, val, 1); Rgba32 color = default; - color.PackFromVector4(v); + color.FromVector4(v); int yy = by * 8 + y; int xx = bx * 8 + x; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs index bcfabca390..f5618d26d2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils var v = new Vector4(val0, val1, val2, 1); Rgba32 color = default; - color.PackFromVector4(v); + color.FromVector4(v); int yy = by * 8 + y; int xx = bx * 8 + x; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index e4cd06ab1b..894d902b78 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png Assert.Equal(PngChunkType.Palette, GetType("PLTE")); Assert.Equal(PngChunkType.Data, GetType("IDAT")); Assert.Equal(PngChunkType.End, GetType("IEND")); - Assert.Equal(PngChunkType.PaletteAlpha, GetType("tRNS")); + Assert.Equal(PngChunkType.Transparency, GetType("tRNS")); Assert.Equal(PngChunkType.Text, GetType("tEXt")); Assert.Equal(PngChunkType.Gamma, GetType("gAMA")); Assert.Equal(PngChunkType.Physical, GetType("pHYs")); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index 2a7d696164..6a0119f0f1 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png [Theory] [InlineData((uint)PngChunkType.Gamma)] // gAMA - [InlineData((uint)PngChunkType.PaletteAlpha)] // tRNS + [InlineData((uint)PngChunkType.Transparency)] // tRNS [InlineData((uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks. //[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 54f3e397c3..f51f9b6c5c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -40,7 +40,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png TestImages.Png.VimImage2, TestImages.Png.Rgb24BppTrans, - TestImages.Png.GrayAlpha8Bit + TestImages.Png.GrayAlpha8Bit, + TestImages.Png.Gray1BitTrans }; public static readonly string[] TestImages48Bpp = diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5d328db361..9079b15fb0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -25,6 +25,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { TestImages.Png.Bpp1, PngBitDepth.Bit1 } }; + public static readonly TheoryData PngTrnsFiles = + new TheoryData + { + { TestImages.Png.Gray1BitTrans, PngBitDepth.Bit1, PngColorType.Grayscale }, + { TestImages.Png.Gray2BitTrans, PngBitDepth.Bit2, PngColorType.Grayscale }, + { TestImages.Png.Gray4BitTrans, PngBitDepth.Bit4, PngColorType.Grayscale }, + { TestImages.Png.Gray8BitTrans, PngBitDepth.Bit8, PngColorType.Grayscale }, + { TestImages.Png.GrayTrns16BitInterlaced, PngBitDepth.Bit16, PngColorType.Grayscale }, + { TestImages.Png.Rgb24BppTrans, PngBitDepth.Bit8, PngColorType.Rgb }, + { TestImages.Png.Rgb48BppTrans, PngBitDepth.Bit16, PngColorType.Rgb } + }; + /// /// All types except Palette /// @@ -249,6 +261,61 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [MemberData(nameof(PngTrnsFiles))] + public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) + { + var options = new PngEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + PngMetaData inMeta = input.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(inMeta.HasTrans); + + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PngMetaData outMeta = output.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(outMeta.HasTrans); + + switch (pngColorType) + { + case PngColorType.Grayscale: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentGray16.HasValue); + Assert.Equal(inMeta.TransparentGray16, outMeta.TransparentGray16); + } + else + { + Assert.True(outMeta.TransparentGray8.HasValue); + Assert.Equal(inMeta.TransparentGray8, outMeta.TransparentGray8); + } + + break; + case PngColorType.Rgb: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentRgb48.HasValue); + Assert.Equal(inMeta.TransparentRgb48, outMeta.TransparentRgb48); + } + else + { + Assert.True(outMeta.TransparentRgb24.HasValue); + Assert.Equal(inMeta.TransparentRgb24, outMeta.TransparentRgb24); + } + + break; + } + } + } + } + } + private static void TestPngEncoderCore( TestImageProvider provider, PngColorType pngColorType, diff --git a/tests/ImageSharp.Tests/GraphicsOptionsTests.cs b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs new file mode 100644 index 0000000000..6ff38626d6 --- /dev/null +++ b/tests/ImageSharp.Tests/GraphicsOptionsTests.cs @@ -0,0 +1,21 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class GraphicsOptionsTests + { + [Fact] + public void IsOpaqueColor() + { + Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/GuardTests.cs b/tests/ImageSharp.Tests/Helpers/GuardTests.cs index 0d1bb5ce9f..b847e581f5 100644 --- a/tests/ImageSharp.Tests/Helpers/GuardTests.cs +++ b/tests/ImageSharp.Tests/Helpers/GuardTests.cs @@ -3,7 +3,10 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; + using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Helpers { @@ -16,6 +19,35 @@ namespace SixLabors.ImageSharp.Tests.Helpers { } + [Theory] + [InlineData(0, 0)] + [InlineData(0, 1)] + [InlineData(0, 42)] + [InlineData(1, 1)] + [InlineData(10, 42)] + [InlineData(42, 42)] + public void DestinationShouldNotBeTooShort_WhenOk(int sourceLength, int destLength) + { + ReadOnlySpan source = new int[sourceLength]; + Span dest = new float[destLength]; + + Guard.DestinationShouldNotBeTooShort(source, dest, nameof(dest)); + } + + [Theory] + [InlineData(1, 0)] + [InlineData(42, 41)] + public void DestinationShouldNotBeTooShort_WhenThrows(int sourceLength, int destLength) + { + Assert.ThrowsAny( + () => + { + ReadOnlySpan source = new int[sourceLength]; + Span dest = new float[destLength]; + Guard.DestinationShouldNotBeTooShort(source, dest, nameof(dest)); + }); + } + /// /// Tests that the method throws when the argument is null. /// diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 6c2979fe9e..018fabd982 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -2,13 +2,80 @@ // Licensed under the Apache License, Version 2.0. using System; +using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers { - using Xunit; - public class ImageMathsTests { + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(4)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + public void Modulo4(int x) + { + int actual = ImageMaths.Modulo4(x); + Assert.Equal(x % 4, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(6)] + [InlineData(7)] + [InlineData(8)] + [InlineData(100)] + [InlineData(123)] + [InlineData(53436353)] + [InlineData(975)] + public void Modulo8(int x) + { + int actual = ImageMaths.Modulo8(x); + Assert.Equal(x % 8, actual); + } + + [Theory] + [InlineData(0, 2)] + [InlineData(1, 2)] + [InlineData(2, 2)] + [InlineData(0, 4)] + [InlineData(3, 4)] + [InlineData(5, 4)] + [InlineData(5, 8)] + [InlineData(8, 8)] + [InlineData(8, 16)] + [InlineData(15, 16)] + [InlineData(17, 16)] + [InlineData(17, 32)] + [InlineData(31, 32)] + [InlineData(32, 32)] + [InlineData(33, 32)] + public void Modulo2P(int x, int m) + { + int actual = ImageMaths.ModuloP2(x, m); + Assert.Equal(x % m, actual); + } + + [Theory] + [InlineData(0, 0, 0, 0)] + [InlineData(0.5f, 0, 1, 0.5f)] + [InlineData(-0.5f, -0.1f, 10, -0.1f)] + [InlineData(-0.05f, -0.1f, 10, -0.05f)] + [InlineData(9.9f, -0.1f, 10, 9.9f)] + [InlineData(10f, -0.1f, 10, 10f)] + [InlineData(10.1f, -0.1f, 10, 10f)] + public void Clamp(float x, float min, float max, float expected) + { + float actual = x.Clamp(min, max); + Assert.Equal(expected, actual); + } + [Fact] public void FasAbsResultMatchesMath() { diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs index f092da7082..629b3cdeb3 100644 --- a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -1,9 +1,9 @@ -using System; -using System.Runtime.CompilerServices; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers @@ -35,4 +35,4 @@ namespace SixLabors.ImageSharp.Tests.Helpers } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs new file mode 100644 index 0000000000..6c7a1f2752 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/TolerantMathTests.cs @@ -0,0 +1,168 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using Xunit; +// ReSharper disable InconsistentNaming + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class TolerantMathTests + { + private readonly TolerantMath tolerantMath = new TolerantMath(0.1); + + [Theory] + [InlineData(0)] + [InlineData(0.01)] + [InlineData(-0.05)] + public void IsZero_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsZero(a)); + } + + [Theory] + [InlineData(0.11)] + [InlineData(-0.101)] + [InlineData(42)] + public void IsZero_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsZero(a)); + } + + [Theory] + [InlineData(0.11)] + [InlineData(100)] + public void IsPositive_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsPositive(a)); + } + + [Theory] + [InlineData(0.09)] + [InlineData(-0.1)] + [InlineData(-1000)] + public void IsPositive_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsPositive(a)); + } + + [Theory] + [InlineData(-0.11)] + [InlineData(-100)] + public void IsNegative_WhenTrue(double a) + { + Assert.True(this.tolerantMath.IsNegative(a)); + } + + [Theory] + [InlineData(-0.09)] + [InlineData(0.1)] + [InlineData(1000)] + public void IsNegative_WhenFalse(double a) + { + Assert.False(this.tolerantMath.IsNegative(a)); + } + + [Theory] + [InlineData(4.2, 4.2)] + [InlineData(4.2, 4.25)] + [InlineData(-Math.PI, -Math.PI + 0.05)] + [InlineData(999999.2, 999999.25)] + public void AreEqual_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.AreEqual(a, b)); + } + + [Theory] + [InlineData(1, 2)] + [InlineData(-1000000, -1000000.2)] + public void AreEqual_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.AreEqual(a, b)); + } + + [Theory] + [InlineData(2, 1.8)] + [InlineData(-20, -20.2)] + [InlineData(0.1, -0.1)] + [InlineData(100, 10)] + public void IsGreater_IsLess_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.IsGreater(a, b)); + Assert.True(this.tolerantMath.IsLess(b, a)); + } + + [Theory] + [InlineData(2, 1.95)] + [InlineData(-20, -20.02)] + [InlineData(0.01, -0.01)] + [InlineData(999999, 999999.09)] + public void IsGreater_IsLess_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.IsGreater(a, b)); + Assert.False(this.tolerantMath.IsLess(b, a)); + } + + [Theory] + [InlineData(3, 2)] + [InlineData(3, 2.99)] + [InlineData(2.99, 3)] + [InlineData(-5, -6)] + [InlineData(-5, -5.05)] + [InlineData(-5.05, -5)] + public void IsGreaterOrEqual_IsLessOrEqual_WhenTrue(double a, double b) + { + Assert.True(this.tolerantMath.IsGreaterOrEqual(a, b)); + Assert.True(this.tolerantMath.IsLessOrEqual(b, a)); + } + + [Theory] + [InlineData(2, 3)] + [InlineData(2.89, 3)] + [InlineData(-3, -2.89)] + public void IsGreaterOrEqual_IsLessOrEqual_WhenFalse(double a, double b) + { + Assert.False(this.tolerantMath.IsGreaterOrEqual(a, b)); + Assert.False(this.tolerantMath.IsLessOrEqual(b, a)); + } + + [Theory] + [InlineData(3.5, 4.0)] + [InlineData(3.89, 4.0)] + [InlineData(4.09, 4.0)] + [InlineData(4.11, 5.0)] + [InlineData(0.11, 1)] + [InlineData(0.05, 0)] + [InlineData(-0.5, 0)] + [InlineData(-0.95, -1)] + [InlineData(-1.05, -1)] + [InlineData(-1.5, -1)] + public void Ceiling(double value, double expected) + { + double actual = this.tolerantMath.Ceiling(value); + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(1, 1)] + [InlineData(0.99, 1)] + [InlineData(0.5, 0)] + [InlineData(0.01, 0)] + [InlineData(-0.09, 0)] + [InlineData(-0.11, -1)] + [InlineData(-100.11, -101)] + [InlineData(-100.09, -100)] + public void Floor(double value, double expected) + { + double plz1 = Math.IEEERemainder(1.1, 1); + double plz2 = Math.IEEERemainder(0.9, 1); + + double plz3 = Math.IEEERemainder(-1.1, 1); + double plz4 = Math.IEEERemainder(-0.9, 1); + + double actual = this.tolerantMath.Floor(value); + Assert.Equal(expected, actual); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index f3c04d5e14..c5c7d19e1e 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.Memory; + using Xunit; // ReSharper disable InconsistentNaming @@ -46,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests } [Fact] - public void Configuration_Width_Height_BackroundColor() + public void Configuration_Width_Height_BackgroundColor() { Configuration configuration = Configuration.Default.Clone(); Rgba32 color = Rgba32.Aquamarine; @@ -61,6 +64,26 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(configuration, image.GetConfiguration()); } } + + [Fact] + public void CreateUninitialized() + { + Configuration configuration = Configuration.Default.Clone(); + + byte dirtyValue = 123; + configuration.MemoryAllocator = new TestMemoryAllocator(dirtyValue); + var metadata = new ImageMetaData(); + + using (Image image = Image.CreateUninitialized(configuration, 21, 22, metadata)) + { + Assert.Equal(21, image.Width); + Assert.Equal(22, image.Height); + Assert.Same(configuration, image.GetConfiguration()); + Assert.Same(metadata, image.MetaData); + + Assert.Equal(dirtyValue, image[5, 5].PackedValue); + } + } } } } diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 5ef8f0111f..86c1a7a259 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,8 +1,8 @@  - net462;net471;netcoreapp2.1 + net462;net472;netcoreapp2.1 True - 7.3 + latest full portable True @@ -11,15 +11,15 @@ AnyCPU;x64;x86 - true + false - true + false - true + false @@ -27,7 +27,7 @@ - + diff --git a/tests/ImageSharp.Tests/Issues/Issue412.cs b/tests/ImageSharp.Tests/Issues/Issue412.cs index 6123c822b8..b0374ce1fa 100644 --- a/tests/ImageSharp.Tests/Issues/Issue412.cs +++ b/tests/ImageSharp.Tests/Issues/Issue412.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Issues [WithBlankImages(40, 30, PixelTypes.Rgba32)] public void AllPixelsExpectedToBeRedWhenAntialiasedDisabled(TestImageProvider provider) where TPixel : struct, IPixel { - using (var image = provider.GetImage()) + using (Image image = provider.GetImage()) { image.Mutate( context => diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 81fd59885a..927f0a5edc 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -31,9 +31,9 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0, scaled.Z); Assert.Equal(0, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(NormalizedByte4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); // Test Ordering @@ -43,51 +43,51 @@ namespace SixLabors.ImageSharp.Tests.Issues float w = -0.7f; Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); var n = default(NormalizedByte4); - n.PackFromRgba32(new Rgba32(141, 90, 192, 39)); + n.FromRgba32(new Rgba32(141, 90, 192, 39)); Assert.Equal(0xA740DA0D, n.PackedValue); Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); - new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 - var r = default(NormalizedByte4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r.PackedValue = 0xff4af389; - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); - - r = default(NormalizedByte4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //var r = default(NormalizedByte4); + //r.FromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r.PackedValue = 0xff4af389; + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.FromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + + //r = default(NormalizedByte4); + //r.FromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -114,9 +114,9 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(1, scaled.Z); Assert.Equal(1, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(NormalizedShort4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); // Test Ordering @@ -127,41 +127,41 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); Assert.Equal((ulong)4150390751449251866, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) + //new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(141, 90, 192)); + //new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(141, 90, 192)); - new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); - new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(141, 90, 192, 39)); + //new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - var r = default(NormalizedShort4); - r.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); + //var r = default(NormalizedShort4); + //r.FromRgba32(new Rgba32(9, 115, 202, 127)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromBgra32(new Bgra32(9, 115, 202, 127)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.FromBgra32(new Bgra32(9, 115, 202, 127)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); - r = default(NormalizedShort4); - r.PackFromArgb32(new Argb32(9, 115, 202, 127)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(9, 115, 202, 127)); + //r = default(NormalizedShort4); + //r.FromArgb32(new Argb32(9, 115, 202, 127)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue @@ -190,9 +190,9 @@ namespace SixLabors.ImageSharp.Tests.Issues Assert.Equal(1, scaled.Z); Assert.Equal(1, scaled.W); - // Test PackFromScaledVector4. + // Test FromScaledVector4. var pixel = default(Short4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue); // Test clamping. @@ -212,41 +212,41 @@ namespace SixLabors.ImageSharp.Tests.Issues w = 193; Assert.Equal((ulong)0x00c173b7316d2d1b, new Short4(x, y, z, w).PackedValue); - var rgb = default(Rgb24); - var rgba = default(Rgba32); - var bgr = default(Bgr24); - var bgra = default(Bgra32); - var argb = default(Argb32); + //var rgb = default(Rgb24); + //var rgba = default(Rgba32); + //var bgr = default(Bgr24); + //var bgra = default(Bgra32); + //var argb = default(Argb32); - new Short4(x, y, z, w).ToRgb24(ref rgb); - Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) + //new Short4(x, y, z, w).ToRgb24(ref rgb); + //Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) - new Short4(x, y, z, w).ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToBgr24(ref bgr); - Assert.Equal(bgr, new Bgr24(172, 177, 243)); + //new Short4(x, y, z, w).ToBgr24(ref bgr); + //Assert.Equal(bgr, new Bgr24(172, 177, 243)); - new Short4(x, y, z, w).ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); - new Short4(x, y, z, w).ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(172, 177, 243, 128)); + //new Short4(x, y, z, w).ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(172, 177, 243, 128)); - var r = default(Short4); - r.PackFromRgba32(new Rgba32(20, 38, 0, 255)); - r.ToRgba32(ref rgba); - Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); + //var r = default(Short4); + //r.FromRgba32(new Rgba32(20, 38, 0, 255)); + //r.ToRgba32(ref rgba); + //Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromBgra32(new Bgra32(20, 38, 0, 255)); - r.ToBgra32(ref bgra); - Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); + //r = default(Short4); + //r.FromBgra32(new Bgra32(20, 38, 0, 255)); + //r.ToBgra32(ref bgra); + //Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); - r = default(Short4); - r.PackFromArgb32(new Argb32(20, 38, 0, 255)); - r.ToArgb32(ref argb); - Assert.Equal(argb, new Argb32(20, 38, 0, 255)); + //r = default(Short4); + //r.FromArgb32(new Argb32(20, 38, 0, 255)); + //r.ToArgb32(ref argb); + //Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } // Comparison helpers with small tolerance to allow for floating point rounding during computations. diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs index 56a4f8c0ca..845a149b5d 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/DataWriter/IccDataWriter.PrimitivesTests.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Icc byte[] output = writer.GetData(); Assert.Equal(0, count); - Assert.Equal(new byte[0], output); + Assert.Equal(Array.Empty(), output); } [Fact] @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Icc byte[] output = writer.GetData(); Assert.Equal(0, count); - Assert.Equal(new byte[0], output); + Assert.Equal(Array.Empty(), output); } [Theory] diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs index b3215ee7ae..c91076afc9 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccReaderTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Icc IccProfile output = reader.Read(IccTestDataProfiles.Header_Random_Array); - Assert.Equal(0, output.Entries.Count); + Assert.Equal(0, output.Entries.Length); Assert.NotNull(output.Header); IccProfileHeader header = output.Header; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.Icc IccProfile output = reader.Read(IccTestDataProfiles.Profile_Random_Array); - Assert.Equal(2, output.Entries.Count); + Assert.Equal(2, output.Entries.Length); Assert.True(ReferenceEquals(output.Entries[0], output.Entries[1])); } diff --git a/tests/ImageSharp.Tests/Numerics/RationalTests.cs b/tests/ImageSharp.Tests/Numerics/RationalTests.cs index a9b9106c5c..caddd49216 100644 --- a/tests/ImageSharp.Tests/Numerics/RationalTests.cs +++ b/tests/ImageSharp.Tests/Numerics/RationalTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.Primitives; using Xunit; diff --git a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs index 9a29236dba..8f68c9d03f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs @@ -10,200 +10,88 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public class Alpha8Tests { [Fact] - public void Alpha8_PackedValue() + public void Alpha8_Constructor() { // Test the limits. - Assert.Equal(0x0, new Alpha8(0F).PackedValue); - Assert.Equal(0xFF, new Alpha8(1F).PackedValue); + Assert.Equal(byte.MinValue, new Alpha8(0F).PackedValue); + Assert.Equal(byte.MaxValue, new Alpha8(1F).PackedValue); // Test clamping. - Assert.Equal(0x0, new Alpha8(-1234F).PackedValue); - Assert.Equal(0xFF, new Alpha8(1234F).PackedValue); + Assert.Equal(byte.MinValue, new Alpha8(-1234F).PackedValue); + Assert.Equal(byte.MaxValue, new Alpha8(1234F).PackedValue); // Test ordering - Assert.Equal(124, new Alpha8(124F / 0xFF).PackedValue); + Assert.Equal(124, new Alpha8(124F / byte.MaxValue).PackedValue); Assert.Equal(26, new Alpha8(0.1F).PackedValue); } [Fact] - public void Alpha8_ToVector4() - { - // arrange - var alpha = new Alpha8(.5F); - - // act - var actual = alpha.ToVector4(); - - // assert - Assert.Equal(0, actual.X); - Assert.Equal(0, actual.Y); - Assert.Equal(0, actual.Z); - Assert.Equal(.5F, actual.W, 2); - } - - [Fact] - public void Alpha8_ToScaledVector4() + public void Alpha8_Equality() { - // arrange - var alpha = new Alpha8(.5F); - - // act - Vector4 actual = alpha.ToScaledVector4(); + var left = new Alpha8(16); + var right = new Alpha8(32); - // assert - Assert.Equal(0, actual.X); - Assert.Equal(0, actual.Y); - Assert.Equal(0, actual.Z); - Assert.Equal(.5F, actual.W, 2); + Assert.True(left == new Alpha8(16)); + Assert.True(left != right); + Assert.Equal(left, (object)new Alpha8(16)); } [Fact] - public void Alpha8_PackFromScaledVector4() + public void Alpha8_FromScaledVector4() { - // arrange + // Arrange Alpha8 alpha = default; int expected = 128; Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - // act - alpha.PackFromScaledVector4(scaled); + // Act + alpha.FromScaledVector4(scaled); byte actual = alpha.PackedValue; - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgb24() - { - // arrange - Rgb24 actual = default; - Alpha8 alpha = default; - var expected = new Rgb24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba32() - { - // arrange - Rgba32 actual = default; - Alpha8 alpha = default; - var expected = new Rgba32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgr24() - { - // arrange - Bgr24 actual = default; - Alpha8 alpha = default; - var expected = new Bgr24(0, 0, 0); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToBgra32() - { - // arrange - Bgra32 actual = default; - Alpha8 alpha = default; - var expected = new Bgra32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Alpha8_PackFromScaledVector4_ToArgb32() - { - // arrange - Alpha8 alpha = default; - Argb32 actual = default; - var expected = new Argb32(0, 0, 0, 128); - Vector4 scaled = new Alpha8(.5F).ToScaledVector4(); - - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToArgb32(ref actual); - - // assert + // Assert Assert.Equal(expected, actual); } [Fact] - public void Alpha8_PackFromScaledVector4_ToRgba64() + public void Alpha8_ToScaledVector4() { - // arrange - Alpha8 alpha = default; - Rgba64 actual = default; - var expected = new Rgba64(0, 0, 0, 65535); - Vector4 scaled = new Alpha8(1F).ToScaledVector4(); + // Arrange + var alpha = new Alpha8(.5F); - // act - alpha.PackFromScaledVector4(scaled); - alpha.ToRgba64(ref actual); + // Act + Vector4 actual = alpha.ToScaledVector4(); - // assert - Assert.Equal(expected, actual); + // Assert + Assert.Equal(0, actual.X); + Assert.Equal(0, actual.Y); + Assert.Equal(0, actual.Z); + Assert.Equal(.5F, actual.W, 2); } [Fact] - public void Alpha8_PackFromRgb48_ToRgb48() + public void Alpha8_ToVector4() { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgb48); - var expected = new Rgb48(0, 0, 0); + // Arrange + var alpha = new Alpha8(.5F); - // act - alpha.PackFromRgb48(expected); - alpha.ToRgb48(ref actual); + // Act + var actual = alpha.ToVector4(); - // assert - Assert.Equal(expected, actual); + // Assert + Assert.Equal(0, actual.X); + Assert.Equal(0, actual.Y); + Assert.Equal(0, actual.Z); + Assert.Equal(.5F, actual.W, 2); } [Fact] - public void Alpha8_PackFromRgba64_ToRgba64() + public void Alpha8_ToRgba32() { - // arrange - var alpha = default(Alpha8); - var actual = default(Rgba64); - var expected = new Rgba64(0, 0, 0, 65535); - - // act - alpha.PackFromRgba64(expected); - alpha.ToRgba64(ref actual); + var input = new Alpha8(128); + var expected = new Rgba32(0, 0, 0, 128); - // assert + Rgba32 actual = default; + input.ToRgba32(ref actual); Assert.Equal(expected, actual); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 5817b5c329..b9f7414900 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Argb32_PackFromScaledVector4() + public void Argb32_FromScaledVector4() { // arrange Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4(); @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0xFFFFFFFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -66,160 +66,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } - - [Fact] - public void Argb32_ToRgb24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - argb.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToRgba32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgr24() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - argb.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToBgra32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_ToArgb32() - { - // arrange - var argb = new Argb32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba32_ToRgba32() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromRgba32(expected); - argb.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromBgra32_ToBgra32() - { - // arrange - var argb = default(Argb32); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromBgra32(expected); - argb.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromArgb32_ToArgb32() - { - // arrange - var argb = default(Argb32); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - argb.PackFromArgb32(expected); - argb.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgb48_ToRgb48() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - argb.PackFromRgb48(expected); - argb.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Argb32_PackFromRgba64_ToRgba64() - { - // arrange - var argb = default(Argb32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - argb.PackFromRgba64(expected); - argb.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 048a38380e..2295fbe56f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -61,10 +61,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Bgr24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -78,10 +78,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var rgb = default(Bgr24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); + rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -95,81 +95,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - - [Fact] - public void ToRgb24() - { - var rgb = new Bgr24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var rgb = new Bgr24(1, 2, 3); - var rgba = default(Rgba32); - - rgb.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgr24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgr24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Bgr24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index b66cac9ca3..967e358e1e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgr565_PackFromScaledVector4() + public void Bgr565_FromScaledVector4() { // arrange Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4(); @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var pixel = default(Bgr565); // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert @@ -69,112 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()); Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } - - [Fact] - public void Bgr565_ToRgb24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 132); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToRgba32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 132, 255); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgr24() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 132); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToBgra32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 132, 255); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_ToArgb32() - { - // arrange - var bgra = new Bgr565(0.1F, -0.3F, 0.5F); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 132, 255); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgr565_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgr565); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 70f8c35dfc..a5c53ed8b0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -67,10 +67,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var c = default(Bgra32); - c.PackFromVector4(Vec(1, 2, 3, 4)); + c.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); @@ -102,81 +102,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } - - [Fact] - public void ToRgb24() - { - var c = new Bgra32(1, 2, 3, 4); - var dest = default(Rgb24); - - c.ToRgb24(ref dest); - - Assert.Equal(new Rgb24(1, 2, 3), dest); - } - - [Fact] - public void ToRgba32() - { - var c = new Bgra32(1, 2, 3, 4); - var rgba = default(Rgba32); - - c.ToRgba32(ref rgba); - - Assert.Equal(new Rgba32(1, 2, 3, 4), rgba); - } - - [Fact] - public void ToBgr24() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Bgra32(1, 2, 3, 4); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 4), bgra); - } - - [Fact] - public void Bgra32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index f643d152ef..8b56ec19fe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgra4444_PackFromScaledVector4() + public void Bgra4444_FromScaledVector4() { // arrange Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4(); @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var bgra = default(Bgra4444); // act - bgra.PackFromScaledVector4(scaled); + bgra.FromScaledVector4(scaled); ushort actual = bgra.PackedValue; // assert @@ -70,160 +70,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } - - [Fact] - public void Bgra4444_ToRgb24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(34, 0, 136); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToRgba32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgr24() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(34, 0, 136); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToBgra32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_ToArgb32() - { - // arrange - var bgra = new Bgra4444(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Rgba32); - var expected = new Rgba32(34, 0, 136, 0); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Bgra32); - var expected = new Bgra32(34, 0, 136, 0); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra4444); - var actual = default(Argb32); - var expected = new Argb32(34, 0, 136, 0); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra4444_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra4444); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index b6a0780312..76edee8a73 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -47,16 +47,16 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Bgra5551_PackFromScaledVector4() + public void Bgra5551_FromScaledVector4() { // arrange Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); int expected = 0xFFFF; var pixel = default(Bgra5551); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert @@ -69,160 +69,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } - - [Fact] - public void Bgra5551_ToRgb24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(24, 0, 131); - - // act - bgra.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Rgba32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(24, 0, 131, 0); - - // act - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToBgr24() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(24, 0, 131); - - // act - bgra.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_Bgra32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(24, 0, 131, 0); - - // act - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_ToArgb32() - { - // arrange - var bgra = new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(24, 0, 131, 0); - - // act - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba32_ToRgba32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Rgba32(24, 0, 131, 0); - var actual = default(Rgba32); - - // act - bgra.PackFromRgba32(expected); - bgra.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromBgra32_ToBgra32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Bgra32(24, 0, 131, 0); - var actual = default(Bgra32); - - // act - bgra.PackFromBgra32(expected); - bgra.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromArgb32_ToArgb32() - { - // arrange - var bgra = default(Bgra5551); - var expected = new Argb32(24, 0, 131, 0); - var actual = default(Argb32); - - // act - bgra.PackFromArgb32(expected); - bgra.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Bgra5551_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Bgra5551); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 28555a7dff..8391ef25ae 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Byte4_PackFromScaledVector4() + public void Byte4_FromScaledVector4() { // arrange Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4(); @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0xFFFFFFFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -67,160 +67,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } - - [Fact] - public void Byte4_ToRgb24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - byte4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Rgba32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 0); - - // act - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_ToBgr24() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - byte4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Bgra32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 0); - - // act - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_Argb32() - { - // arrange - var byte4 = new Byte4(127.5f, -12.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 0); - - // act - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba32_ToRgba32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); - - // act - byte4.PackFromRgba32(expected); - byte4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromBgra32_ToBgra32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 0, 255); - - // act - byte4.PackFromBgra32(expected); - byte4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromArgb32_ToArgb32() - { - // arrange - var byte4 = default(Byte4); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 0, 255); - - // act - byte4.PackFromArgb32(expected); - byte4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Byte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Byte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Byte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs deleted file mode 100644 index b0d5929f49..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorConstructorTests.cs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorConstructorTests - { - public static IEnumerable Vector4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4), vector4Components }; - yield return new object[] { new Bgra4444(vector4), vector4Components }; - yield return new object[] { new Bgra5551(vector4), vector4Components }; - yield return new object[] { new Byte4(vector4), vector4Components }; - yield return new object[] { new HalfVector4(vector4), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4), vector4Components }; - yield return new object[] { new Rgba1010102(vector4), vector4Components }; - yield return new object[] { new Rgba64(vector4), vector4Components }; - yield return new object[] { new Short4(vector4), vector4Components }; - } - } - } - - public static IEnumerable Vector3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3), vector4Components }; - yield return new object[] { new Bgr565(vector3), vector4Components }; - } - } - } - - public static IEnumerable Float4Data - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra4444(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Bgra5551(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Byte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new HalfVector4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedByte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new NormalizedShort4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba1010102(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Rgba64(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - yield return new object[] { new Short4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components }; - } - } - } - - public static IEnumerable Float3Data - { - get - { - Dictionary vector3Values = new Dictionary() - { - { Vector3.One, Vector4.One }, - { Vector3.Zero, new Vector4(0, 0, 0, 1) }, - { Vector3.UnitX, new Vector4(1, 0, 0, 1) }, - { Vector3.UnitY, new Vector4(0, 1, 0, 1) }, - { Vector3.UnitZ, new Vector4(0, 0, 1, 1) }, - }; - - foreach (Vector3 vector3 in vector3Values.Keys) - { - Vector4 vector4 = vector3Values[vector3]; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { new Argb32(vector3.X, vector3.Y, vector3.Z), vector4Components }; - yield return new object[] { new Bgr565(vector3.X, vector3.Y, vector3.Z), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4Data))] - [MemberData(nameof(Vector3Data))] - [MemberData(nameof(Float4Data))] - [MemberData(nameof(Float3Data))] - public void ConstructorToVector4(IPixel packedVector, float[] expectedVector4Components) - { - // Arrange - int precision = 2; - // using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData - Vector4 expectedVector4 = new Vector4(expectedVector4Components[0], expectedVector4Components[1], expectedVector4Components[2], expectedVector4Components[3]); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(expectedVector4.X, vector4.X, precision); - Assert.Equal(expectedVector4.Y, vector4.Y, precision); - Assert.Equal(expectedVector4.Z, vector4.Z, precision); - Assert.Equal(expectedVector4.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs deleted file mode 100644 index d3815f2eb6..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorEqualityTests.cs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - /// - /// Test implementations of IEquatable - /// - public class ColorEqualityTests - { - public static readonly TheoryData EqualityData = - new TheoryData() - { - { new Alpha8(.5F), new Alpha8(.5F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.One), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.One), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.One), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.One * 255), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(-1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, -0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.One), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.One), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.One), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.One), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.One), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.One), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.One), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.One), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataNulls = - new TheoryData() - { - // Valid object against null - { new Alpha8(.5F), null, typeof(Alpha8) }, - { new Argb32(Vector4.One), null, typeof(Argb32) }, - { new Bgr565(Vector3.One), null, typeof(Bgr565) }, - { new Bgra4444(Vector4.One), null, typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), null, typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), null, typeof(Byte4) }, - { new HalfSingle(-1F), null, typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), null, typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), null, typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), null, typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), null, typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), null, typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), null, typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), null, typeof(Rg32) }, - { new Rgba1010102(Vector4.One), null, typeof(Rgba1010102) }, - { new Rgba64(Vector4.One), null, typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), null, typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), null, typeof(Short4) }, - }; - - public static readonly TheoryData NotEqualityDataDifferentObjects = - new TheoryData() - { - // Valid objects of different types but not equal - { new Alpha8(.5F), new Argb32(Vector4.Zero), null }, - { new HalfSingle(-1F), new NormalizedShort2(Vector2.Zero), null }, - { new Rgba1010102(Vector4.One), new Bgra5551(Vector4.Zero), null }, - }; - - public static readonly TheoryData NotEqualityData = - new TheoryData() - { - // Valid objects of the same type but not equal - { new Alpha8(.5F), new Alpha8(.8F), typeof(Alpha8) }, - { new Argb32(Vector4.One), new Argb32(Vector4.Zero), typeof(Argb32) }, - { new Bgr565(Vector3.One), new Bgr565(Vector3.Zero), typeof(Bgr565) }, - { new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) }, - { new Bgra5551(Vector4.One), new Bgra5551(Vector4.Zero), typeof(Bgra5551) }, - { new Byte4(Vector4.One * 255), new Byte4(Vector4.Zero), typeof(Byte4) }, - { new HalfSingle(-1F), new HalfSingle(1F), typeof(HalfSingle) }, - { new HalfVector2(0.1f, -0.3f), new HalfVector2(0.1f, 0.3f), typeof(HalfVector2) }, - { new HalfVector4(Vector4.One), new HalfVector4(Vector4.Zero), typeof(HalfVector4) }, - { new NormalizedByte2(-Vector2.One), new NormalizedByte2(-Vector2.Zero), typeof(NormalizedByte2) }, - { new NormalizedByte4(Vector4.One), new NormalizedByte4(Vector4.Zero), typeof(NormalizedByte4) }, - { new NormalizedShort2(Vector2.One), new NormalizedShort2(Vector2.Zero), typeof(NormalizedShort2) }, - { new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.Zero), typeof(NormalizedShort4) }, - { new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) }, - { new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.Zero), typeof(Rgba1010102) }, - { new Rgba32(Vector4.One), new Rgba32(Vector4.Zero), typeof(Rgba32) }, - { new Rgba64(Vector4.One), new Rgba64(Vector4.Zero), typeof(Rgba64) }, - { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) }, - { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) }, - }; - - [Theory] - [MemberData(nameof(EqualityData))] - public void Equality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataNulls))] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - [MemberData(nameof(NotEqualityData))] - public void NotEquality(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void HashCodeEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - public void HashCodeNotEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityObject(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void NotEqualityObject(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void EqualityOperator(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject == secondObject; - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void NotEqualityOperator(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic notEqual = firstObject != secondObject; - - // Assert - Assert.True(notEqual); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs deleted file mode 100644 index c9a1c8fe7e..0000000000 --- a/tests/ImageSharp.Tests/PixelFormats/ColorPackingTests.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Collections.Generic; -using System.Numerics; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colors -{ - public class ColorPackingTests - { - public static IEnumerable Vector4PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.Zero, - Vector4.One, - Vector4.UnitX, - Vector4.UnitY, - Vector4.UnitZ, - Vector4.UnitW, - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { default(Bgra4444), vector4Components }; - yield return new object[] { default(Bgra5551), vector4Components }; - yield return new object[] { default(Byte4), vector4Components }; - yield return new object[] { default(HalfVector4), vector4Components }; - yield return new object[] { default(NormalizedByte4), vector4Components }; - yield return new object[] { default(NormalizedShort4), vector4Components }; - yield return new object[] { default(Rgba1010102), vector4Components }; - yield return new object[] { default(Rgba64), vector4Components }; - yield return new object[] { default(Short4), vector4Components }; - } - } - } - - public static IEnumerable Vector3PackData - { - get - { - Vector4[] vector4Values = new Vector4[] - { - Vector4.One, - new Vector4(0, 0, 0, 1), - new Vector4(1, 0, 0, 1), - new Vector4(0, 1, 0, 1), - new Vector4(0, 0, 1, 1), - }; - - foreach (Vector4 vector4 in vector4Values) - { - float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W }; - - yield return new object[] { default(Argb32), vector4Components }; - yield return new object[] { new Bgr565(), vector4Components }; - } - } - } - - [Theory] - [MemberData(nameof(Vector4PackData))] - [MemberData(nameof(Vector3PackData))] - public void FromVector4ToVector4(IPixel packedVector, float[] vector4ComponentsToPack) - { - // Arrange - int precision = 2; - Vector4 vector4ToPack = new Vector4(vector4ComponentsToPack[0], vector4ComponentsToPack[1], vector4ComponentsToPack[2], vector4ComponentsToPack[3]); - packedVector.PackFromVector4(vector4ToPack); - - // Act - Vector4 vector4 = packedVector.ToVector4(); - - // Assert - Assert.Equal(vector4ToPack.X, vector4.X, precision); - Assert.Equal(vector4ToPack.Y, vector4.Y, precision); - Assert.Equal(vector4ToPack.Z, vector4.Z, precision); - Assert.Equal(vector4ToPack.W, vector4.W, precision); - } - } -} diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs new file mode 100644 index 0000000000..cb19c031d0 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs @@ -0,0 +1,130 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray16Tests + { + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + [InlineData(42)] + public void Gray16_PackedValue_EqualsInput(ushort input) + => Assert.Equal(input, new Gray16(input).PackedValue); + + [Fact] + public void Gray16_FromScaledVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + Vector4 scaled = new Gray16(expected).ToScaledVector4(); + + // Act + gray.FromScaledVector4(scaled); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToScaledVector4(ushort input) + { + // Arrange + var gray = new Gray16(input); + + // Act + Vector4 actual = gray.ToScaledVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); + } + + [Fact] + public void Gray16_FromVector4() + { + // Arrange + Gray16 gray = default; + const ushort expected = 32767; + var vector = new Gray16(expected).ToVector4(); + + // Act + gray.FromVector4(vector); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(32767)] + public void Gray16_ToVector4(ushort input) + { + // Arrange + var gray = new Gray16(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float vectorInput = input / 65535F; + Assert.Equal(vectorInput, actual.X); + Assert.Equal(vectorInput, actual.Y); + Assert.Equal(vectorInput, actual.Z); + Assert.Equal(1F, actual.W); + } + + [Fact] + public void Gray16_FromRgba32() + { + // Arrange + Gray16 gray = default; + const byte rgb = 128; + ushort scaledRgb = ImageMaths.UpscaleFrom8BitTo16Bit(rgb); + ushort expected = ImageMaths.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); + + // Act + gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(0)] + [InlineData(65535)] + [InlineData(8100)] + public void Gray16_ToRgba32(ushort input) + { + // Arrange + ushort expected = ImageMaths.DownScaleFrom16BitTo8Bit(input); + var gray = new Gray16(input); + + // Act + Rgba32 actual = default; + gray.ToRgba32(ref actual); + + // Assert + Assert.Equal(expected, actual.R); + Assert.Equal(expected, actual.G); + Assert.Equal(expected, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } + } +} diff --git a/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs new file mode 100644 index 0000000000..1e17985e60 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs @@ -0,0 +1,252 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Diagnostics; +using System.Numerics; + +using SixLabors.ImageSharp.Common.Helpers; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +// ReSharper disable InconsistentNaming +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public class Gray8Tests + { + public static readonly TheoryData LuminanceData = new TheoryData() + { + 0, + 1, + 2, + 3, + 5, + 13, + 31, + 71, + 73, + 79, + 83, + 109, + 127, + 128, + 131, + 199, + 250, + 251, + 254, + 255 + }; + + [Theory] + [InlineData(0)] + [InlineData(255)] + [InlineData(10)] + [InlineData(42)] + public void Gray8_PackedValue_EqualsInput(byte input) + => Assert.Equal(input, new Gray8(input).PackedValue); + + [Fact] + public void Gray8_FromScaledVector4() + { + // Arrange + Gray8 gray = default; + const byte expected = 128; + Vector4 scaled = new Gray8(expected).ToScaledVector4(); + + // Act + gray.FromScaledVector4(scaled); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_ToScaledVector4(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + Vector4 actual = gray.ToScaledVector4(); + + // Assert + float scaledInput = input / 255F; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromVector4(byte luminance) + { + // Arrange + Gray8 gray = default; + var vector = new Gray8(luminance).ToVector4(); + + // Act + gray.FromVector4(vector); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(luminance, actual); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_ToVector4(byte input) + { + // Arrange + var gray = new Gray8(input); + + // Act + var actual = gray.ToVector4(); + + // Assert + float scaledInput = input / 255F; + Assert.Equal(scaledInput, actual.X); + Assert.Equal(scaledInput, actual.Y); + Assert.Equal(scaledInput, actual.Z); + Assert.Equal(1, actual.W); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromRgba32(byte rgb) + { + // Arrange + Gray8 gray = default; + byte expected = ImageMaths.Get8BitBT709Luminance(rgb, rgb, rgb); + + // Act + gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); + byte actual = gray.PackedValue; + + // Assert + Assert.Equal(expected, actual); + } + + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_ToRgba32(byte luminance) + { + // Arrange + var gray = new Gray8(luminance); + + // Act + Rgba32 actual = default; + gray.ToRgba32(ref actual); + + // Assert + Assert.Equal(luminance, actual.R); + Assert.Equal(luminance, actual.G); + Assert.Equal(luminance, actual.B); + Assert.Equal(byte.MaxValue, actual.A); + } + + public class Rgba32Compatibility + { + // ReSharper disable once MemberHidesStaticFromOuterClass + public static readonly TheoryData LuminanceData = Gray8Tests.LuminanceData; + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Gray8_FromRgba32_IsInverseOf_ToRgba32(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Gray8 mirror = default; + mirror.FromRgba32(rgba); + + Assert.Equal(original, mirror); + } + + + [Theory] + [MemberData(nameof(LuminanceData))] + public void Rgba32_ToGray8_IsInverseOf_Gray8_ToRgba32(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Gray8 mirror = default; + mirror.FromRgba32(rgba); + + Assert.Equal(original, mirror); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void ToVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + var gray8Vector = original.ToVector4(); + var rgbaVector = original.ToVector4(); + + Assert.Equal(gray8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void FromVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 rgbaVector = original.ToVector4(); + + Gray8 mirror = default; + mirror.FromVector4(rgbaVector); + + Assert.Equal(original, mirror); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void ToScaledVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 gray8Vector = original.ToScaledVector4(); + Vector4 rgbaVector = original.ToScaledVector4(); + + Assert.Equal(gray8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); + } + + [Theory] + [MemberData(nameof(LuminanceData))] + public void FromScaledVector4_IsRgba32Compatible(byte luminance) + { + var original = new Gray8(luminance); + + Rgba32 rgba = default; + original.ToRgba32(ref rgba); + + Vector4 rgbaVector = original.ToScaledVector4(); + + Gray8 mirror = default; + mirror.FromScaledVector4(rgbaVector); + + Assert.Equal(original, mirror); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 3376645f34..85a3b8b320 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfSingle_PackFromScaledVector4() + public void HalfSingle_FromScaledVector4() { // arrange Vector4 scaled = new HalfSingle(-1F).ToScaledVector4(); @@ -60,118 +60,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var halfSingle = default(HalfSingle); // act - halfSingle.PackFromScaledVector4(scaled); + halfSingle.FromScaledVector4(scaled); ushort actual = halfSingle.PackedValue; // assert Assert.Equal(expected, actual); } - - [Fact] - public void HalfSingle_ToRgb24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 0, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Rgba32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 0, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_ToBgr24() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 0, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Bgra32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 0, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_Argb32() - { - // arrange - var halfVector = new HalfSingle(.5F); - var actual = default(Argb32); - var expected = new Argb32(128, 0, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfSingle_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfSingle); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index c2a524f0dc..ccdd23e8fb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfVector2_PackFromScaledVector4() + public void HalfVector2_FromScaledVector4() { // arrange Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4(); @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var halfVector = default(HalfVector2); // act - halfVector.PackFromScaledVector4(scaled); + halfVector.FromScaledVector4(scaled); uint actual = halfVector.PackedValue; // assert @@ -71,112 +71,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void HalfVector2_ToRgb24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgb24); - var expected = new Rgb24(128, 64, 0); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Rgba32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Rgba32); - var expected = new Rgba32(128, 64, 0, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_ToBgr24() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgr24); - var expected = new Bgr24(128, 64, 0); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Bgra32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Bgra32); - var expected = new Bgra32(128, 64, 0, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_Argb32() - { - // arrange - var halfVector = new HalfVector2(.5F, .25F); - var actual = default(Argb32); - var expected = new Argb32(128, 64, 0, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 8b28dd8277..c61dd97d2a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void HalfVector4_PackFromScaledVector4() + public void HalfVector4_FromScaledVector4() { // arrange var halfVector4 = default(HalfVector4); @@ -59,166 +59,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats ulong expected = 13547034390470638592uL; // act - halfVector4.PackFromScaledVector4(scaled); + halfVector4.FromScaledVector4(scaled); ulong actual = halfVector4.PackedValue; // assert Assert.Equal(expected, actual); } - - [Fact] - public void HalfVector4_ToRgb24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgb24); - var expected = new Rgb24(64, 128, 191); - - // act - halfVector.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Rgba32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halfVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_ToBgr24() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgr24); - var expected = new Bgr24(64, 128, 191); - - // act - halfVector.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Bgra32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halfVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_Argb32() - { - // arrange - var halfVector = new HalfVector4(.25F, .5F, .75F, 1F); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halfVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba32_ToRgba32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Rgba32); - var expected = new Rgba32(64, 128, 191, 255); - - // act - halVector.PackFromRgba32(expected); - halVector.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromBgra32_ToBgra32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Bgra32); - var expected = new Bgra32(64, 128, 191, 255); - - // act - halVector.PackFromBgra32(expected); - halVector.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromArgb32_ToArgb32() - { - // arrange - var halVector = default(HalfVector4); - var actual = default(Argb32); - var expected = new Argb32(64, 128, 191, 255); - - // act - halVector.PackFromArgb32(expected); - halVector.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void HalfVector4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(HalfVector4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 83f22e2aa0..506ebe0fe0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedByte2_PackFromScaledVector4() + public void NormalizedByte2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4(); @@ -60,134 +60,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x8181; // act - byte2.PackFromScaledVector4(scaled); + byte2.FromScaledVector4(scaled); uint actual = byte2.PackedValue; // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedByte2_PackFromRgba32() - { - // arrange - var byte2 = new NormalizedByte2(); - var rgba = new Rgba32(141, 90, 0, 0); - int expected = 0xda0d; - - // act - byte2.PackFromRgba32(rgba); - ushort actual = byte2.PackedValue; - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgb24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToRgba32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgr24() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToBgra32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_ToArgb32() - { - // arrange - var short4 = new NormalizedByte2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 16516496f8..19a49e5d8a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedByte4_PackFromScaledVector4() + public void NormalizedByte4_FromScaledVector4() { // arrange var pixel = default(NormalizedByte4); @@ -54,151 +54,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x81818181; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedByte4_ToRgb24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToRgba32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToBgr24() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_ToArgb32() - { - // arrange - var short4 = new NormalizedByte4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Rgba32); - var expected = new Rgba32(9, 115, 202, 127); - - // act - short4.PackFromRgba32(new Rgba32(9, 115, 202, 127)); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromBgra32_ToRgba32() - { - // arrange - var actual = default(Bgra32); - var short4 = default(NormalizedByte4); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedByte4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedByte4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedByte4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 2fb7f05aca..216ed4ad75 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedShort2_PackFromScaledVector4() + public void NormalizedShort2_FromScaledVector4() { // arrange Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4(); @@ -63,135 +63,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats uint expected = 0x80018001; // act - short2.PackFromScaledVector4(scaled); + short2.FromScaledVector4(scaled); uint actual = short2.PackedValue; // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedShort2_PackFromRgba32_ToRgb24() - { - // arrange - var actual = default(Rgb24); - var short2 = new NormalizedShort2(); - var rgba = new Rgba32(141, 90, 0, 0); - var expected = new Rgb24(141, 90, 0); - - // act - short2.PackFromRgba32(rgba); - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgb24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToRgba32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 0, 255); - - // act - short2.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgr24() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToBgra32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Bgra32); - var expected = new Bgra32(141, 90, 0, 255); - - // act - short2.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_ToArgb32() - { - // arrange - var short2 = new NormalizedShort2(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort2_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 7dcdd9c88b..d06d46d06f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -47,159 +47,19 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void NormalizedShort4_PackFromScaledVector4() + public void NormalizedShort4_FromScaledVector4() { // arrange var pixel = default(NormalizedShort4); Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); - ulong expected = (ulong)0x7FFF7FFF7FFF7FFF; + ulong expected = 0x7FFF7FFF7FFF7FFF; // act - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); } - - [Fact] - public void NormalizedShort4_ToRgb24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(141, 90, 192); - - // act - short4.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToRgba32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(141, 90, 192, 39); - - // act - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToBgr24() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(141, 90, 192); - - // act - short4.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_ToArgb32() - { - // arrange - var short4 = new NormalizedShort4(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(141, 90, 192, 39); - - // act - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var expected = new Rgba32(9, 115, 202, 127); - var actual = default(Rgba32); - - // act - short4.PackFromRgba32(expected); - short4.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromBgra32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Bgra32); - var expected = new Bgra32(9, 115, 202, 127); - - // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromArgb32_ToRgba32() - { - // arrange - var short4 = default(NormalizedShort4); - var actual = default(Argb32); - var expected = new Argb32(9, 115, 202, 127); - - // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void NormalizedShort4_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(NormalizedShort4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs index 3ea9bcad40..7de1cbb190 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders { new TestPixel(1,1,1,1), new TestPixel(0,0,0,.8f), .5f, new TestPixel(0.6f, 0.6f, 0.6f, 1) }, }; - private MemoryAllocator MemoryAllocator { get; } = Configuration.Default.MemoryAllocator; + private Configuration Configuration => Configuration.Default; [Theory] [MemberData(nameof(NormalBlendFunctionData))] @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.NormalSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.NormalSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.MultiplySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.MultiplySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.AddSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.AddSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.SubtractSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.SubtractSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.ScreenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.ScreenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.DarkenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.DarkenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.LightenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.LightenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.OverlaySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.OverlaySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } @@ -362,7 +362,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders where TPixel : struct, IPixel { var dest = new Span(new TPixel[1]); - new DefaultPixelBlenders.HardLightSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); + new DefaultPixelBlenders.HardLightSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount)); VectorAssert.Equal(expected, dest[0], 2); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs new file mode 100644 index 0000000000..c539e9dcf0 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs @@ -0,0 +1,160 @@ +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.PixelFormats.Utils; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.PixelFormats +{ + public abstract class PixelConverterTests + { + public static readonly TheoryData RgbaData = + new TheoryData + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 255 }, + { 0, 0, 255, 0 }, + { 0, 255, 0, 0 }, + { 255, 0, 0, 0 }, + { 255, 255, 255, 255 }, + { 0, 0, 0, 1 }, + { 0, 0, 1, 0 }, + { 0, 1, 0, 0 }, + { 1, 0, 0, 0 }, + { 3, 5, 7, 11 }, + { 67, 71, 101, 109 } + }; + + public class FromRgba32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromRgba32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromArgb32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToBgra32(byte r, byte g, byte b, byte a) + { + Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromArgb32.ToBgra32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + public class FromBgra32 : PixelConverterTests + { + [Theory] + [MemberData(nameof(RgbaData))] + public void ToArgb32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToArgb32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + + [Theory] + [MemberData(nameof(RgbaData))] + public void ToRgba32(byte r, byte g, byte b, byte a) + { + Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a); + + // Act: + uint actualPacked = PixelConverter.FromBgra32.ToRgba32(s.PackedValue); + + // Assert: + uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue; + + Assert.Equal(expectedPacked, actualPacked); + } + } + + + private static class ReferenceImplementations + { + public static Rgba32 MakeRgba32(byte r, byte g, byte b, byte a) + { + Rgba32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Argb32 MakeArgb32(byte r, byte g, byte b, byte a) + { + Argb32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + + public static Bgra32 MakeBgra32(byte r, byte g, byte b, byte a) + { + Bgra32 d = default; + d.R = r; + d.G = g; + d.B = b; + d.A = a; + return d; + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs new file mode 100644 index 0000000000..c881ae96ba --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Argb32OperationsTests : PixelOperationsTests + { + + public Argb32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs new file mode 100644 index 0000000000..323d3914cf --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgr24OperationsTests : PixelOperationsTests + { + public Bgr24OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs new file mode 100644 index 0000000000..1c966951fc --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Bgra32OperationsTests : PixelOperationsTests + { + public Bgra32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs new file mode 100644 index 0000000000..c3de335470 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs @@ -0,0 +1,114 @@ +// 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.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray16OperationsTests : PixelOperationsTests + { + public Gray16OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray16[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray16[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs new file mode 100644 index 0000000000..acd6ef23ac --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs @@ -0,0 +1,114 @@ +// 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.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Gray8OperationsTests : PixelOperationsTests + { + public Gray8OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray8Bytes(int count) + { + byte[] source = CreateByteTestData(count); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + expected[i].FromGray8(new Gray8(source[i])); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray8Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count]; + var gray = default(Gray8); + + for (int i = 0; i < count; i++) + { + gray.FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = gray.PackedValue; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void FromGray16Bytes(int count) + { + byte[] source = CreateByteTestData(count * 2); + Span sourceSpan = source.AsSpan(); + var expected = new Gray8[count]; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + expected[i].FromGray16(MemoryMarshal.Cast(sourceSpan.Slice(i2, 2))[0]); + } + + TestOperation( + source, + expected, + (s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToGray16Bytes(int count) + { + Gray8[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 2]; + Gray16 gray = default; + + for (int i = 0; i < count; i++) + { + int i2 = i * 2; + gray.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes bytes = Unsafe.As(ref gray); + expected[i2] = bytes[0]; + expected[i2 + 1] = bytes[1]; + } + + TestOperation( + source, + expected, + (s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count) + ); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs new file mode 100644 index 0000000000..0a28db6b0a --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgb48OperationsTests : PixelOperationsTests + { + public Rgb48OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs new file mode 100644 index 0000000000..1ecbaf3615 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Buffers; +using System.Numerics; + +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba32OperationsTests : PixelOperationsTests + { + public Rgba32OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + + [Fact(Skip = SkipProfilingBenchmarks)] + public void Benchmark_ToVector4() + { + const int times = 200000; + const int count = 1024; + + using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) + using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) + { + this.Measure( + times, + () => PixelOperations.Instance.ToVector4( + this.Configuration, + source.GetSpan(), + dest.GetSpan())); + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs new file mode 100644 index 0000000000..6787602bb2 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class Rgba64OperationsTests : PixelOperationsTests + { + public Rgba64OperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs new file mode 100644 index 0000000000..f9cc042a77 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations +{ + public partial class PixelOperationsTests + { + public class RgbaVectorOperationsTests : PixelOperationsTests + { + public RgbaVectorOperationsTests(ITestOutputHelper output) + : base(output) + { + } + + [Fact] + public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs similarity index 65% rename from tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs rename to tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index 9e41fd94f3..d9845e4741 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -6,113 +6,69 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; + using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.PixelFormats +namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations { public partial class PixelOperationsTests { - public class Rgba32 : PixelOperationsTests - { - public Rgba32(ITestOutputHelper output) - : base(output) - { - } - - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - [Fact] - public void IsSpecialImplementation() - { - Assert.IsType(PixelOperations.Instance); - } - - [Fact] - public void ToVector4SimdAligned() - { - if (!Vector.IsHardwareAccelerated) - { - return; - } - - ImageSharp.PixelFormats.Rgba32[] source = CreatePixelTestData(64); - Vector4[] expected = CreateExpectedVector4Data(source); - - TestOperation( - source, - expected, - (s, d) => ImageSharp.PixelFormats.Rgba32.PixelOperations.ToVector4SimdAligned(s, d.GetSpan(), 64) - ); - } - - - // [Fact] // Profiling benchmark - enable manually! -#pragma warning disable xUnit1013 // Public method should be marked as test - public void Benchmark_ToVector4() -#pragma warning restore xUnit1013 // Public method should be marked as test - { - int times = 200000; - int count = 1024; - - using (IMemoryOwner source = Configuration.Default.MemoryAllocator.Allocate(count)) - using (IMemoryOwner dest = Configuration.Default.MemoryAllocator.Allocate(count)) - { - this.Measure( - times, - () => - { - PixelOperations.Instance.ToVector4(source.GetSpan(), dest.GetSpan(), count); - }); - } - } - } - - public class Argb32 : PixelOperationsTests - { - // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public Argb32(ITestOutputHelper output) - : base(output) - { - } - - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - } - [Theory] [WithBlankImages(1, 1, PixelTypes.All)] - public void GetGlobalInstance(TestImageProvider dummy) - where TPixel : struct, IPixel - { - Assert.NotNull(PixelOperations.Instance); - } - - [Fact] - public void IsOpaqueColor() - { - Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - - Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Transparent)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal,PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(ImageSharp.PixelFormats.Rgba32.Red)); - } + public void GetGlobalInstance(TestImageProvider _) + where T : struct, IPixel => Assert.NotNull(PixelOperations.Instance); } public abstract class PixelOperationsTests : MeasureFixture where TPixel : struct, IPixel { + public const string SkipProfilingBenchmarks = +#if true + "Profiling benchmark - enable manually!"; +#else + null; +#endif + protected PixelOperationsTests(ITestOutputHelper output) : base(output) { } - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - private static PixelOperations Operations => PixelOperations.Instance; + public static TheoryData ArraySizesData => + new TheoryData + { + 0, + 1, + 2, + 7, + 16, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 1111 + }; + + protected Configuration Configuration => Configuration.Default; + + internal static PixelOperations Operations => PixelOperations.Instance; internal static TPixel[] CreateExpectedPixelData(Vector4[] source) { @@ -120,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < expected.Length; i++) { - expected[i].PackFromVector4(source[i]); + expected[i].FromVector4(source[i]); } return expected; } @@ -131,14 +87,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < expected.Length; i++) { - expected[i].PackFromScaledVector4(source[i]); + expected[i].FromScaledVector4(source[i]); } return expected; } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) + public void FromVector4(int count) { Vector4[] source = CreateVector4TestData(count); TPixel[] expected = CreateExpectedPixelData(source); @@ -146,13 +102,13 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromVector4(this.Configuration, s, d.GetSpan()) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromScaledVector4(int count) + public void FromScaledVector4(int count) { Vector4[] source = CreateVector4TestData(count); TPixel[] expected = CreateScaledExpectedPixelData(source); @@ -160,32 +116,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.PackFromScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.FromScaledVector4(this.Configuration, s, d.GetSpan()) ); } - internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToVector4(); - } - return expected; - } - - internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) - { - var expected = new Vector4[source.Length]; - - for (int i = 0; i < expected.Length; i++) - { - expected[i] = source[i].ToScaledVector4(); - } - return expected; - } - [Theory] [MemberData(nameof(ArraySizesData))] public void ToVector4(int count) @@ -196,7 +130,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToVector4(s, d.GetSpan(), count) + (s, d) => Operations.ToVector4(this.Configuration, s, d.GetSpan()) ); } @@ -210,389 +144,359 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats TestOperation( source, expected, - (s, d) => Operations.ToScaledVector4(s, d.GetSpan(), count) + (s, d) => Operations.ToScaledVector4(this.Configuration, s, d.GetSpan()) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb24Bytes(int count) + public void FromArgb32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255)); + expected[i].FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb24Bytes(int count) + public void ToArgb32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); + byte[] expected = new byte[count * 4]; + var argb = default(Argb32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - source[i].ToRgb24(ref rgb); - expected[i3] = rgb.R; - expected[i3 + 1] = rgb.G; - expected[i3 + 2] = rgb.B; + int i4 = i * 4; + argb.FromScaledVector4(source[i].ToScaledVector4()); + + expected[i4] = argb.A; + expected[i4 + 1] = argb.R; + expected[i4 + 2] = argb.G; + expected[i4 + 3] = argb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToArgb32Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba32Bytes(int count) + public void FromBgr24Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; + int i3 = i * 3; - expected[i].PackFromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i].FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba32Bytes(int count) + public void ToBgr24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); + byte[] expected = new byte[count * 3]; + var bgr = default(Bgr24); for (int i = 0; i < count; i++) { - int i4 = i * 4; - source[i].ToRgba32(ref rgba); - expected[i4] = rgba.R; - expected[i4 + 1] = rgba.G; - expected[i4 + 2] = rgba.B; - expected[i4 + 3] = rgba.A; + int i3 = i * 3; + bgr.FromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = bgr.B; + expected[i3 + 1] = bgr.G; + expected[i3 + 2] = bgr.R; } TestOperation( source, expected, - (s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgr24Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgb48Bytes(int count) + public void FromBgra32Bytes(int count) { - byte[] source = CreateByteTestData(count * 6); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; - var rgba64 = new Rgba64(0, 0, 0, 65535); for (int i = 0; i < count; i++) { - int i6 = i * 6; - rgba64.Rgb = MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]; - expected[i].PackFromRgba64(rgba64); + int i4 = i * 4; + + expected[i].FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgb48Bytes(int count) + public void ToBgra32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; + byte[] expected = new byte[count * 4]; + var bgra = default(Bgra32); for (int i = 0; i < count; i++) { - int i6 = i * 6; - source[i].ToRgb48(ref rgb); - Rgba64Bytes rgb48Bytes = Unsafe.As(ref rgb); - expected[i6] = rgb48Bytes[0]; - expected[i6 + 1] = rgb48Bytes[1]; - expected[i6 + 2] = rgb48Bytes[2]; - expected[i6 + 3] = rgb48Bytes[3]; - expected[i6 + 4] = rgb48Bytes[4]; - expected[i6 + 5] = rgb48Bytes[5]; + int i4 = i * 4; + bgra.FromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = bgra.B; + expected[i4 + 1] = bgra.G; + expected[i4 + 2] = bgra.R; + expected[i4 + 3] = bgra.A; } TestOperation( source, expected, - (s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToBgra32Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromRgba64Bytes(int count) + public void FromRgb24Bytes(int count) { - byte[] source = CreateByteTestData(count * 8); - Span sourceSpan = source.AsSpan(); + byte[] source = CreateByteTestData(count * 3); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i8 = i * 8; - expected[i].PackFromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + int i3 = i * 3; + + expected[i].FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( source, expected, - (s, d) => Operations.PackFromRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToRgba64Bytes(int count) + public void ToRgb24Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; + byte[] expected = new byte[count * 3]; + var rgb = default(Rgb24); for (int i = 0; i < count; i++) { - int i8 = i * 8; - source[i].ToRgba64(ref rgba); - Rgba64Bytes rgba64Bytes = Unsafe.As(ref rgba); - expected[i8] = rgba64Bytes[0]; - expected[i8 + 1] = rgba64Bytes[1]; - expected[i8 + 2] = rgba64Bytes[2]; - expected[i8 + 3] = rgba64Bytes[3]; - expected[i8 + 4] = rgba64Bytes[4]; - expected[i8 + 5] = rgba64Bytes[5]; - expected[i8 + 6] = rgba64Bytes[6]; - expected[i8 + 7] = rgba64Bytes[7]; + int i3 = i * 3; + rgb.FromScaledVector4(source[i].ToScaledVector4()); + expected[i3] = rgb.R; + expected[i3 + 1] = rgb.G; + expected[i3 + 2] = rgb.B; } TestOperation( source, expected, - (s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb24Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgr24Bytes(int count) + public void FromRgba32Bytes(int count) { - byte[] source = CreateByteTestData(count * 3); + byte[] source = CreateByteTestData(count * 4); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i3 = i * 3; + int i4 = i * 4; - expected[i].PackFromRgba32(new Rgba32(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255)); + expected[i].FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToBgr24Bytes(int count) + public void ToRgba32Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); + byte[] expected = new byte[count * 4]; + var rgba = default(Rgba32); for (int i = 0; i < count; i++) { - int i3 = i * 3; - source[i].ToBgr24(ref bgr); - expected[i3] = bgr.B; - expected[i3 + 1] = bgr.G; - expected[i3 + 2] = bgr.R; + int i4 = i * 4; + rgba.FromScaledVector4(source[i].ToScaledVector4()); + expected[i4] = rgba.R; + expected[i4 + 1] = rgba.G; + expected[i4 + 2] = rgba.B; + expected[i4 + 3] = rgba.A; } TestOperation( source, expected, - (s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba32Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromBgra32Bytes(int count) + public void FromRgb48Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 6); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + int i6 = i * 6; + expected[i].FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToZyxwBytes(int count) + public void ToRgb48Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); + byte[] expected = new byte[count * 6]; + Rgb48 rgb = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - source[i].ToBgra32(ref bgra); - expected[i4] = bgra.B; - expected[i4 + 1] = bgra.G; - expected[i4 + 2] = bgra.R; - expected[i4 + 3] = bgra.A; + int i6 = i * 6; + rgb.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgb48Bytes = Unsafe.As(ref rgb); + expected[i6] = rgb48Bytes[0]; + expected[i6 + 1] = rgb48Bytes[1]; + expected[i6 + 2] = rgb48Bytes[2]; + expected[i6 + 3] = rgb48Bytes[3]; + expected[i6 + 4] = rgb48Bytes[4]; + expected[i6 + 5] = rgb48Bytes[5]; } TestOperation( source, expected, - (s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgb48Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromArgb32Bytes(int count) + public void FromRgba64Bytes(int count) { - byte[] source = CreateByteTestData(count * 4); + byte[] source = CreateByteTestData(count * 8); + Span sourceSpan = source.AsSpan(); var expected = new TPixel[count]; for (int i = 0; i < count; i++) { - int i4 = i * 4; - - expected[i].PackFromRgba32(new Rgba32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + int i8 = i * 8; + expected[i].FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( source, expected, - (s, d) => Operations.PackFromArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.FromRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void ToArgb32Bytes(int count) + public void ToRgba64Bytes(int count) { TPixel[] source = CreatePixelTestData(count); - byte[] expected = new byte[count * 4]; - var argb = default(Argb32); + byte[] expected = new byte[count * 8]; + Rgba64 rgba = default; for (int i = 0; i < count; i++) { - int i4 = i * 4; - source[i].ToArgb32(ref argb); - expected[i4] = argb.A; - expected[i4 + 1] = argb.R; - expected[i4 + 2] = argb.G; - expected[i4 + 3] = argb.B; + int i8 = i * 8; + rgba.FromScaledVector4(source[i].ToScaledVector4()); + OctetBytes rgba64Bytes = Unsafe.As(ref rgba); + expected[i8] = rgba64Bytes[0]; + expected[i8 + 1] = rgba64Bytes[1]; + expected[i8 + 2] = rgba64Bytes[2]; + expected[i8 + 3] = rgba64Bytes[3]; + expected[i8 + 4] = rgba64Bytes[4]; + expected[i8 + 5] = rgba64Bytes[5]; + expected[i8 + 6] = rgba64Bytes[6]; + expected[i8 + 7] = rgba64Bytes[7]; } TestOperation( source, expected, - (s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count) + (s, d) => Operations.ToRgba64Bytes(this.Configuration, s, d.GetSpan(), count) ); } - private class TestBuffers : IDisposable - where TSource : struct - where TDest : struct + internal static Vector4[] CreateExpectedVector4Data(TPixel[] source) { - public TSource[] SourceBuffer { get; } - public IMemoryOwner ActualDestBuffer { get; } - public TDest[] ExpectedDestBuffer { get; } - - public TestBuffers(TSource[] source, TDest[] expectedDest) - { - this.SourceBuffer = source; - this.ExpectedDestBuffer = expectedDest; - this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); - } + var expected = new Vector4[source.Length]; - public void Dispose() + for (int i = 0; i < expected.Length; i++) { - this.ActualDestBuffer.Dispose(); + expected[i] = source[i].ToVector4(); } + return expected; + } - private const float Tolerance = 0.0001f; + internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source) + { + var expected = new Vector4[source.Length]; - public void Verify() + for (int i = 0; i < expected.Length; i++) { - int count = this.ExpectedDestBuffer.Length; - - if (typeof(TDest) == typeof(Vector4)) - { - - Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); - Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - - for (int i = 0; i < count; i++) - { - // ReSharper disable PossibleNullReferenceException - Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); - // ReSharper restore PossibleNullReferenceException - } - } - else - { - Span expected = this.ExpectedDestBuffer.AsSpan(); - Span actual = this.ActualDestBuffer.GetSpan(); - for (int i = 0; i < count; i++) - { - Assert.Equal(expected[i], actual[i]); - } - } + expected[i] = source[i].ToScaledVector4(); } + return expected; } internal static void TestOperation( @@ -630,7 +534,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); + result[i].FromVector4(v); } return result; @@ -645,7 +549,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats for (int i = 0; i < result.Length; i++) { Vector4 v = GetVector(rnd); - result[i].PackFromScaledVector4(v); + result[i].FromScaledVector4(v); } return result; @@ -674,7 +578,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [StructLayout(LayoutKind.Sequential)] - private unsafe struct Rgba64Bytes + internal unsafe struct OctetBytes { public fixed byte Data[8]; @@ -683,10 +587,56 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - ref byte self = ref Unsafe.As(ref this); + ref byte self = ref Unsafe.As(ref this); return Unsafe.Add(ref self, idx); } } } + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct + { + public TSource[] SourceBuffer { get; } + public IMemoryOwner ActualDestBuffer { get; } + public TDest[] ExpectedDestBuffer { get; } + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = source; + this.ExpectedDestBuffer = expectedDest; + this.ActualDestBuffer = Configuration.Default.MemoryAllocator.Allocate(expectedDest.Length); + } + + public void Dispose() => this.ActualDestBuffer.Dispose(); + + public void Verify() + { + int count = this.ExpectedDestBuffer.Length; + + if (typeof(TDest) == typeof(Vector4)) + { + Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); + Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); + + var comparer = new ApproximateFloatComparer(0.001f); + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], comparer); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + Span expected = this.ExpectedDestBuffer.AsSpan(); + Span actual = this.ActualDestBuffer.GetSpan(); + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } + } + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 3a80c3436d..46e5fbc3cd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rg32_PackFromScaledVector4() + public void Rg32_FromScaledVector4() { // arrange var rg32 = new Rg32(Vector2.One); @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rg32.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -68,97 +68,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()); Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } - - [Fact] - public void Rg32_ToRgb24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 0); - - // act - rg32.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToRgba32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Rgba32); - var expected = new Rgba32(25, 0, 0, 255); - - // act - rg32.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToBgr24() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 0); - - // act - rg32.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_ToArgb32() - { - // arrange - var rg32 = new Rg32(0.1f, -0.3f); - var actual = default(Argb32); - var expected = new Argb32(25, 0, 0, 255); - - // act - rg32.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rg32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rg32_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rg32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index d056bf30d2..92e8d302d4 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -11,7 +10,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public class Rgb24Tests { public static readonly TheoryData ColorData = - new TheoryData() { { 1, 2, 3 }, { 4, 5, 6 }, { 0, 255, 42 } }; + new TheoryData() + { + { 1, 2, 3 }, + { 4, 5, 6 }, + { 0, 255, 42 } + }; [Theory] [MemberData(nameof(ColorData))] @@ -61,10 +65,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void PackFromRgba32() + public void FromRgba32() { var rgb = default(Rgb24); - rgb.PackFromRgba32(new Rgba32(1, 2, 3, 4)); + rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -78,10 +82,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats a / 255f); [Fact] - public void PackFromVector4() + public void FromVector4() { var rgb = default(Rgb24); - rgb.PackFromVector4(Vec(1, 2, 3, 4)); + rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -96,80 +100,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } - [Fact] - public void ToRgb24() - { - var rgb = new Rgb24(1, 2, 3); - var dest = default(Rgb24); - - rgb.ToRgb24(ref dest); - - Assert.Equal(rgb, dest); - } - [Fact] public void ToRgba32() { var rgb = new Rgb24(1, 2, 3); - var rgba = default(Rgba32); - + Rgba32 rgba = default; rgb.ToRgba32(ref rgba); Assert.Equal(new Rgba32(1, 2, 3, 255), rgba); } - - [Fact] - public void ToBgr24() - { - var rgb = new Rgb24(1, 2, 3); - var bgr = default(Bgr24); - - rgb.ToBgr24(ref bgr); - - Assert.Equal(new Bgr24(1, 2, 3), bgr); - } - - [Fact] - public void ToBgra32() - { - var rgb = new Rgb24(1, 2, 3); - var bgra = default(Bgra32); - - rgb.ToBgra32(ref bgra); - - Assert.Equal(new Bgra32(1, 2, 3, 255), bgra); - } - - [Fact] - public void Rgb24_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb24_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb24); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 77d6544f00..d30e498609 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -18,182 +18,45 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(9830, rgb.G); Assert.Equal(19660, rgb.B); Assert.Equal(29491, rgb.A); - - rgb = new Rgba64(5243 / 65535F, 9830 / 65535F, 19660 / 65535F, 29491 / 65535F); - - Assert.Equal(5243, rgb.R); - Assert.Equal(9830, rgb.G); - Assert.Equal(19660, rgb.B); - Assert.Equal(29491, rgb.A); } [Fact] public void Rgb48_ToVector4() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One).ToVector4()); - } + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); [Fact] public void Rgb48_ToScaledVector4() - { - // arrange - var short2 = new Rgb48(Vector3.One); - - // act - Vector4 actual = short2.ToScaledVector4(); - - // assert - Assert.Equal(1, actual.X); - Assert.Equal(1, actual.Y); - Assert.Equal(1, actual.Z); - Assert.Equal(1, actual.W); - } + => Assert.Equal(Vector4.One, new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); [Fact] - public void Rgb48_PackFromScaledVector4() + public void Rgb48_FromScaledVector4() { // arrange var pixel = default(Rgb48); - var short3 = new Rgb48(Vector3.One); - var expected = new Rgb48(Vector3.One); + var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 scaled = short3.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); // assert Assert.Equal(expected, pixel); } - [Fact] - public void Rgb48_Clamping() - { - Assert.Equal(new Vector4(0, 0, 0, 1), new Rgb48(Vector3.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgb48(Vector3.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgb48_ToRgb24() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba48.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Rgb48_ToRgba32() { // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Rgba32); + var rgba48 = new Rgb48(5140, 9766, 19532); var expected = new Rgba32(20, 38, 76, 255); // act + Rgba32 actual = default; rgba48.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); } - - [Fact] - public void Rgb48_ToArgb32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 255); - - // act - rgba48.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgb48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgb48.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_ToBgra32() - { - // arrange - var rgba48 = new Rgb48(0.08f, 0.15f, 0.30f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 255); - - // act - rgba48.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba32_ToRgba32() - { - // arrange - var rgb48 = default(Rgb48); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 255); - - // act - rgb48.PackFromRgba32(expected); - rgb48.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgb48); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index fcb3b6c7c8..a897dd4cdb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba1010102_PackFromScaledVector4() + public void Rgba1010102_FromScaledVector4() { // arrange var rgba = new Rgba1010102(Vector4.One); @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rgba.ToScaledVector4(); - actual.PackFromScaledVector4(scaled); + actual.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -71,144 +71,19 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()); } - [Fact] - public void Rgba1010102_ToRgb24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(25, 0, 128); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Rgba1010102_ToRgba32() { // arrange var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Rgba32); var expected = new Rgba32(25, 0, 128, 0); // act + Rgba32 actual = default; rgba.ToRgba32(ref actual); // assert Assert.Equal(expected, actual); } - - [Fact] - public void Rgba1010102_ToBgr24() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(25, 0, 128); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_ToBgra32() - { - // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(25, 0, 128, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba32_ToRgba32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Rgba32(25, 0, 128, 0); - var actual = default(Rgba32); - - // act - rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromBgra32_ToBgra32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Bgra32(25, 0, 128, 0); - var actual = default(Bgra32); - - // act - rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromArgb32_ToArgb32() - { - // arrange - var rgba = default(Rgba1010102); - var expected = new Argb32(25, 0, 128, 0); - var actual = default(Argb32); - - // act - rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba1010102_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba1010102); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 65535); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 4b2c187765..ad1d137406 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using SixLabors.ImageSharp.PixelFormats; using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.PixelFormats { @@ -19,12 +20,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - Rgba32 color1 = new Rgba32(0, 0, 0); - Rgba32 color2 = new Rgba32(0, 0, 0, 1F); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000F"); - Rgba32 color5 = Rgba32.FromHex("#000000"); - Rgba32 color6 = Rgba32.FromHex("#000000FF"); + var color1 = new Rgba32(0, 0, 0); + var color2 = new Rgba32(0, 0, 0, 1F); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000F"); + var color5 = Rgba32.FromHex("#000000"); + var color6 = Rgba32.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +40,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - Rgba32 color1 = new Rgba32(255, 0, 0, 255); - Rgba32 color2 = new Rgba32(0, 0, 0, 255); - Rgba32 color3 = Rgba32.FromHex("#000"); - Rgba32 color4 = Rgba32.FromHex("#000000"); - Rgba32 color5 = Rgba32.FromHex("#FF000000"); + var color1 = new Rgba32(255, 0, 0, 255); + var color2 = new Rgba32(0, 0, 0, 255); + var color3 = Rgba32.FromHex("#000"); + var color4 = Rgba32.FromHex("#000000"); + var color5 = Rgba32.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,25 +58,25 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - Rgba32 color1 = new Rgba32(1, .1f, .133f, .864f); + var color1 = new Rgba32(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - Rgba32 color2 = new Rgba32(1, .1f, .133f); + var color2 = new Rgba32(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - Rgba32 color4 = new Rgba32(new Vector3(1, .1f, .133f)); + var color4 = new Rgba32(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - Rgba32 color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); + var color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -112,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public unsafe void ByteLayout() { - Rgba32 color = new Rgba32(1, 2, 3, 4); + var color = new Rgba32(1, 2, 3, 4); byte* colorBase = (byte*)&color; Assert.Equal(1, colorBase[0]); Assert.Equal(2, colorBase[1]); @@ -159,7 +160,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba32_PackFromScaledVector4() + public void Rgba32_FromScaledVector4() { // arrange var rgba = new Rgba32(Vector4.One); @@ -168,7 +169,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // act Vector4 scaled = rgba.ToScaledVector4(); - actual.PackFromScaledVector4(scaled); + actual.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -181,23 +182,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One, new Rgba32(Vector4.One * +1234.0f).ToVector4()); } - [Fact] - public void Rgba32_ToRgb24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgb24); - var expected = new Rgb24(0x1a, 0, 0x80); - - // act - rgba.ToRgb24(ref actual); - - // assert - Assert.Equal(expected.R, actual.R); - Assert.Equal(expected.G, actual.G); - Assert.Equal(expected.B, actual.B); - } - [Fact] public void Rgba32_ToRgba32() { @@ -207,59 +191,14 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgr24() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgr24); - var expected = new Bgr24(0x1a, 0, 0x80); - - // act - rgba.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToBgra32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); - - // act - rgba.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba32_ToArgb32() - { - // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); - - // act - rgba.ToArgb32(ref actual); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgba32_ToRgba32() + public void Rgba32_FromRgba32_ToRgba32() { // arrange var rgba = default(Rgba32); @@ -267,15 +206,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(0x1a, 0, 0x80, 0); // act - rgba.PackFromRgba32(expected); - rgba.ToRgba32(ref actual); + rgba.FromRgba32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromBgra32_ToRgba32() + public void Rgba32_FromBgra32_ToRgba32() { // arrange var rgba = default(Rgba32); @@ -283,15 +222,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Bgra32(0x1a, 0, 0x80, 0); // act - rgba.PackFromBgra32(expected); - rgba.ToBgra32(ref actual); + rgba.FromBgra32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromArgb32_ToArgb32() + public void Rgba32_FromArgb32_ToArgb32() { // arrange var rgba = default(Rgba32); @@ -299,15 +238,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Argb32(0x1a, 0, 0x80, 0); // act - rgba.PackFromArgb32(expected); - rgba.ToArgb32(ref actual); + rgba.FromArgb32(expected); + actual.FromRgba32(rgba); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgb48_ToRgb48() + public void Rgba32_FromRgb48() { // arrange var input = default(Rgba32); @@ -315,15 +254,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Rgba32_PackFromRgba64_ToRgba64() + public void Rgba32_FromRgba64() { // arrange var input = default(Rgba32); @@ -331,8 +270,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 92b36a1c62..3e5d7a56ed 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -13,33 +13,31 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats public void Rgba64_PackedValues() { Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(5243, 9830, 19660, 29491).PackedValue); - Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(0.08f, 0.15f, 0.30f, 0.45f).PackedValue); - var rgba = new Rgba64(0x73334CCC2666147B); - Assert.Equal(5243, rgba.R); - Assert.Equal(9830, rgba.G); - Assert.Equal(19660, rgba.B); - Assert.Equal(29491, rgba.A); // Test the limits. - Assert.Equal((ulong)0x0, new Rgba64(Vector4.Zero).PackedValue); - Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64(Vector4.One).PackedValue); + Assert.Equal((ulong)0x0, new Rgba64(0, 0, 0, 0).PackedValue); + Assert.Equal(0xFFFFFFFFFFFFFFFF, new Rgba64( + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue, + ushort.MaxValue).PackedValue); + // Test data ordering - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(((float)0x1EB8) / 0xffff, ((float)0x570A) / 0xffff, ((float)0x8F5C) / 0xffff, ((float)0xC7AD) / 0xffff).PackedValue); - Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0.12f, 0.34f, 0.56f, 0.78f).PackedValue); + Assert.Equal(0xC7AD8F5C570A1EB8, new Rgba64(0x1EB8, 0x570A, 0x8F5C, 0xC7AD).PackedValue); } [Fact] public void Rgba64_ToVector4() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.Zero).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One).ToVector4()); + Assert.Equal(Vector4.Zero, new Rgba64(0, 0, 0, 0).ToVector4()); + Assert.Equal(Vector4.One, new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue).ToVector4()); } [Fact] public void Rgba64_ToScaledVector4() { // arrange - var short2 = new Rgba64(Vector4.One); + var short2 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 actual = short2.ToScaledVector4(); @@ -52,16 +50,16 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Rgba64_PackFromScaledVector4() + public void Rgba64_FromScaledVector4() { // arrange var pixel = default(Rgba64); - var short4 = new Rgba64(Vector4.One); + var short4 = new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); const ulong expected = 0xFFFFFFFFFFFFFFFF; // act Vector4 scaled = short4.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -71,30 +69,19 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void Rgba64_Clamping() { - Assert.Equal(Vector4.Zero, new Rgba64(Vector4.One * -1234.0f).ToVector4()); - Assert.Equal(Vector4.One, new Rgba64(Vector4.One * 1234.0f).ToVector4()); - } - - [Fact] - public void Rgba64_ToRgb24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Rgb24); - var expected = new Rgb24(20, 38, 76); - - // act - rgba64.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); + var zero = default(Rgba64); + var one = default(Rgba64); + zero.FromVector4(Vector4.One * -1234.0f); + one.FromVector4(Vector4.One * 1234.0f); + Assert.Equal(Vector4.Zero, zero.ToVector4()); + Assert.Equal(Vector4.One, one.ToVector4()); } [Fact] public void Rgba64_ToRgba32() { // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); + var rgba64 = new Rgba64(5140, 9766, 19532, 29555); var actual = default(Rgba32); var expected = new Rgba32(20, 38, 76, 115); @@ -104,98 +91,5 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats // assert Assert.Equal(expected, actual); } - - [Fact] - public void Rgba64_ToArgb32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 76, 115); - - // act - rgba64.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgr24() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgr24); - var expected = new Bgr24(20, 38, 76); - - // act - rgba64.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_ToBgra32() - { - // arrange - var rgba64 = new Rgba64(0.08f, 0.15f, 0.30f, 0.45f); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 76, 115); - - // act - rgba64.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_PackFromRgba32_ToRgba32() - { - // arrange - var rgba64 = default(Rgba64); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); - - // act - rgba64.PackFromRgba32(expected); - rgba64.ToRgba32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgb48_PackFromRgb48_ToRgb48() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); - - // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Rgba64_PackFromRgba64_ToRgba64() - { - // arrange - var input = default(Rgba64); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); - - // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); - - // assert - Assert.Equal(expected, actual); - } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index a21b647a74..e880e38517 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -19,12 +19,12 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreEqual() { - RgbaVector color1 = new RgbaVector(0, 0, 0F); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1F); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000F"); - RgbaVector color5 = RgbaVector.FromHex("#000000"); - RgbaVector color6 = RgbaVector.FromHex("#000000FF"); + var color1 = new RgbaVector(0, 0, 0F); + var color2 = new RgbaVector(0, 0, 0, 1F); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000F"); + var color5 = RgbaVector.FromHex("#000000"); + var color6 = RgbaVector.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void AreNotEqual() { - RgbaVector color1 = new RgbaVector(1, 0, 0, 1); - RgbaVector color2 = new RgbaVector(0, 0, 0, 1); - RgbaVector color3 = RgbaVector.FromHex("#000"); - RgbaVector color4 = RgbaVector.FromHex("#000000"); - RgbaVector color5 = RgbaVector.FromHex("#FF000000"); + var color1 = new RgbaVector(1, 0, 0, 1); + var color2 = new RgbaVector(0, 0, 0, 1); + var color3 = RgbaVector.FromHex("#000"); + var color4 = RgbaVector.FromHex("#000000"); + var color5 = RgbaVector.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,29 +57,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void ConstructorAssignsProperties() { - RgbaVector color1 = new RgbaVector(1, .1F, .133F, .864F); + var color1 = new RgbaVector(1, .1F, .133F, .864F); Assert.Equal(1F, color1.R); Assert.Equal(.1F, color1.G); Assert.Equal(.133F, color1.B); Assert.Equal(.864F, color1.A); - RgbaVector color2 = new RgbaVector(1, .1f, .133f); + var color2 = new RgbaVector(1, .1f, .133f); Assert.Equal(1F, color2.R); Assert.Equal(.1F, color2.G); Assert.Equal(.133F, color2.B); Assert.Equal(1F, color2.A); - - RgbaVector color4 = new RgbaVector(new Vector3(1, .1f, .133f)); - Assert.Equal(1F, color4.R); - Assert.Equal(.1F, color4.G); - Assert.Equal(.133F, color4.B); - Assert.Equal(1F, color4.A); - - RgbaVector color5 = new RgbaVector(new Vector4(1, .1f, .133f, .5f)); - Assert.Equal(1F, color5.R); - Assert.Equal(.1F, color5.G); - Assert.Equal(.133F, color5.B); - Assert.Equal(.5F, color5.A); } /// @@ -88,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FromAndToHex() { - RgbaVector color = RgbaVector.FromHex("#AABBCCDD"); + var color = RgbaVector.FromHex("#AABBCCDD"); Assert.Equal(170 / 255F, color.R); Assert.Equal(187 / 255F, color.G); Assert.Equal(204 / 255F, color.B); @@ -116,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats [Fact] public void FloatLayout() { - RgbaVector color = new RgbaVector(1F, 2, 3, 4); + var color = new RgbaVector(1F, 2, 3, 4); Vector4 colorBase = Unsafe.As(ref Unsafe.Add(ref color, 0)); float[] ordered = new float[4]; colorBase.CopyTo(ordered); @@ -128,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void RgbaVector_PackFromRgb48_ToRgb48() + public void RgbaVector_FromRgb48() { // arrange var input = default(RgbaVector); @@ -136,15 +124,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void RgbaVector_PackFromRgba64_ToRgba64() + public void RgbaVector_FromRgba64() { // arrange var input = default(RgbaVector); @@ -152,8 +140,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 5c75fcbbbc..c9a3b33c9a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -63,37 +63,22 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromScaledVector4() + public void Short2_FromScaledVector4() { // arrange var pixel = default(Short2); var short2 = new Short2(Vector2.One * 0x7FFF); - ulong expected = 0x7FFF7FFF; + const ulong expected = 0x7FFF7FFF; // act Vector4 scaled = short2.ToScaledVector4(); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); } - [Fact] - public void Short2_ToRgb24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Rgb24); - var expected = new Rgb24(128, 127, 0); - - // act - short2.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short2_ToRgba32() { @@ -110,52 +95,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_ToBgr24() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgr24); - var expected = new Bgr24(128, 127, 0); - - // act - short2.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToArgb32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Argb32); - var expected = new Argb32(128, 127, 0, 255); - - // act - short2.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_ToBgra32() - { - // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Bgra32); - var expected = new Bgra32(128, 127, 0, 255); - - // act - short2.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short2_PackFromRgba32_ToRgba32() + public void Short2_FromRgba32_ToRgba32() { // arrange var short2 = default(Short2); @@ -163,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 0, 255); // act - short2.PackFromRgba32(expected); + short2.FromRgba32(expected); short2.ToRgba32(ref actual); // assert @@ -171,7 +111,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short2_PackFromRgb48_ToRgb48() + public void Short2_FromRgb48() { // arrange var input = default(Short2); @@ -179,15 +119,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 65535, 0); // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Short2_PackFromRgba64_ToRgba64() + public void Short2_FromRgba64() { // arrange var input = default(Short2); @@ -195,8 +135,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 65535, 0, 65535); // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 59dc385d4d..247342a053 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -51,16 +51,16 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromScaledVector4() + public void Short4_FromScaledVector4() { // arrange var short4 = new Short4(Vector4.One * 0x7FFF); Vector4 scaled = short4.ToScaledVector4(); - long expected = 0x7FFF7FFF7FFF7FFF; + const long expected = 0x7FFF7FFF7FFF7FFF; // act var pixel = default(Short4); - pixel.PackFromScaledVector4(scaled); + pixel.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -83,36 +83,6 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats Assert.Equal(Vector4.One * -0x8000, vector2); } - [Fact] - public void Short4_ToRgb24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Rgb24); - var expected = new Rgb24(172, 177, 243); - - // act - shortValue.ToRgb24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToBgr24() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgr24); - var expected = new Bgr24(172, 177, 243); - - // act - shortValue.ToBgr24(ref actual); - - // assert - Assert.Equal(expected, actual); - } - [Fact] public void Short4_ToRgba32() { @@ -129,37 +99,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_ToBgra32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Bgra32); - var expected = new Bgra32(172, 177, 243, 128); - - // act - shortValue.ToBgra32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_ToArgb32() - { - // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Argb32); - var expected = new Argb32(172, 177, 243, 128); - - // act - shortValue.ToArgb32(ref actual); - - // assert - Assert.Equal(expected, actual); - } - - [Fact] - public void Short4_PackFromRgba32_ToRgba32() + public void Short4_FromRgba32_ToRgba32() { // arrange var short4 = default(Short4); @@ -167,7 +107,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba32(20, 38, 0, 255); // act - short4.PackFromRgba32(expected); + short4.FromRgba32(expected); short4.ToRgba32(ref actual); // assert @@ -175,7 +115,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats } [Fact] - public void Short4_PackFromBgra32_ToRgba32() + public void Short4_FromBgra32_ToRgba32() { // arrange var short4 = default(Short4); @@ -183,15 +123,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Bgra32(20, 38, 0, 255); // act - short4.PackFromBgra32(expected); - short4.ToBgra32(ref actual); + short4.FromBgra32(expected); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); } [Fact] - public void Short4_PackFromArgb32_ToRgba32() + public void Short4_FromArgb32_ToRgba32() { // arrange var short4 = default(Short4); @@ -199,15 +141,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Argb32(20, 38, 0, 255); // act - short4.PackFromArgb32(expected); - short4.ToArgb32(ref actual); + short4.FromArgb32(expected); + Rgba32 temp = default; + short4.ToRgba32(ref temp); + actual.FromRgba32(temp); // assert Assert.Equal(expected, actual); } [Fact] - public void Short4_PackFromRgb48_ToRgb48() + public void Short4_FromRgb48_ToRgb48() { // arrange var input = default(Short4); @@ -215,15 +159,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgb48(65535, 0, 65535); // act - input.PackFromRgb48(expected); - input.ToRgb48(ref actual); + input.FromRgb48(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); } [Fact] - public void Short4_PackFromRgba64_ToRgba64() + public void Short4_FromRgba64_ToRgba64() { // arrange var input = default(Short4); @@ -231,8 +175,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats var expected = new Rgba64(65535, 0, 65535, 0); // act - input.PackFromRgba64(expected); - input.ToRgba64(ref actual); + input.FromRgba64(expected); + actual.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 1fca398fcd..bd8c647421 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); - var colorVector = new RgbaVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() { var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); - var colorVector = new RgbaVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -73,76 +73,30 @@ namespace SixLabors.ImageSharp.Tests.Colors public void Color_Types_To_Vector4_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.ToVector4(), colorVector.ToVector4()); } - [Fact] - public void Color_Types_To_RgbBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgb = default(Rgb24); - var rgbVector = default(Rgb24); - - color.ToRgb24(ref rgb); - colorVector.ToRgb24(ref rgbVector); - - Assert.Equal(rgb, rgbVector); - } - [Fact] public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var rgba = default(Rgba32); - var rgbaVector = default(Rgba32); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 rgba = default; + Rgba32 rgbaVector = default; color.ToRgba32(ref rgba); colorVector.ToRgba32(ref rgbaVector); Assert.Equal(rgba, rgbaVector); } - [Fact] - public void Color_Types_To_BgrBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgr = default(Bgr24); - var bgrVector = default(Bgr24); - - color.ToBgr24(ref bgr); - colorVector.ToBgr24(ref bgrVector); - - Assert.Equal(bgr, bgrVector); - } - - [Fact] - public void Color_Types_To_BgraBytes_Produce_Equal_OutPut() - { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); - - var bgra = default(Bgra32); - var bgraVector = default(Bgra32); - - color.ToBgra32(ref bgra); - colorVector.ToBgra32(ref bgraVector); - - Assert.Equal(bgra, bgraVector); - } - [Fact] public void Color_Types_To_Hex_Produce_Equal_OutPut() { var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24, 48, 96, 192); + var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); // 183060C0 Assert.Equal(color.ToHex(), colorVector.ToHex()); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs new file mode 100644 index 0000000000..b3900325db --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/OctreeQuantizerTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class OctreeQuantizerTests + { + [Fact] + public void OctreeQuantizerConstructor() + { + var quantizer = new OctreeQuantizer(128); + + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new OctreeQuantizer(false); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Null(quantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson, 128); + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void OctreeQuantizerCanCreateFrameQuantizer() + { + var quantizer = new OctreeQuantizer(); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new OctreeQuantizer(false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new OctreeQuantizer(KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs new file mode 100644 index 0000000000..a4e6edd53e --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/PaletteQuantizerTests.cs @@ -0,0 +1,79 @@ +// 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.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class PaletteQuantizerTests + { + private static readonly Rgba32[] Rgb = new Rgba32[] { Rgba32.Red, Rgba32.Green, Rgba32.Blue }; + + [Fact] + public void PaletteQuantizerConstructor() + { + var quantizer = new PaletteQuantizer(Rgb); + + Assert.Equal(Rgb, quantizer.Palette); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, false); + Assert.Equal(Rgb, quantizer.Palette); + Assert.Null(quantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + Assert.Equal(Rgb, quantizer.Palette); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void PaletteQuantizerCanCreateFrameQuantizer() + { + var quantizer = new PaletteQuantizer(Rgb); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new PaletteQuantizer(Rgb, KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + + [Fact] + public void PaletteQuantizerThrowsOnInvalidGenericMethodCall() + { + var quantizer = new PaletteQuantizer(Rgb); + + Assert.Throws(() => ((IQuantizer)quantizer).CreateFrameQuantizer(Configuration.Default)); + } + + [Fact] + public void KnownQuantizersWebSafeTests() + { + IQuantizer quantizer = KnownQuantizers.WebSafe; + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + } + + [Fact] + public void KnownQuantizersWernerTests() + { + IQuantizer quantizer = KnownQuantizers.Werner; + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs new file mode 100644 index 0000000000..625043c7f1 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/WuQuantizerTests.cs @@ -0,0 +1,58 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization +{ + public class WuQuantizerTests + { + [Fact] + public void WuQuantizerConstructor() + { + var quantizer = new WuQuantizer(128); + + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.FloydSteinberg, quantizer.Diffuser); + + quantizer = new WuQuantizer(false); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Null(quantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson); + Assert.Equal(QuantizerConstants.MaxColors, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson, 128); + Assert.Equal(128, quantizer.MaxColors); + Assert.Equal(KnownDiffusers.Atkinson, quantizer.Diffuser); + } + + [Fact] + public void WuQuantizerCanCreateFrameQuantizer() + { + var quantizer = new WuQuantizer(); + IFrameQuantizer frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.FloydSteinberg, frameQuantizer.Diffuser); + + quantizer = new WuQuantizer(false); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + + Assert.NotNull(frameQuantizer); + Assert.False(frameQuantizer.Dither); + Assert.Null(frameQuantizer.Diffuser); + + quantizer = new WuQuantizer(KnownDiffusers.Atkinson); + frameQuantizer = quantizer.CreateFrameQuantizer(Configuration.Default); + Assert.NotNull(frameQuantizer); + Assert.True(frameQuantizer.Dither); + Assert.Equal(KnownDiffusers.Atkinson, frameQuantizer.Diffuser); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs deleted file mode 100644 index 1b4b3cf6a3..0000000000 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; -using System.Text; - -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; -using SixLabors.Primitives; - -using Xunit; -using Xunit.Abstractions; - -namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms -{ - public class KernelMapTests - { - private ITestOutputHelper Output { get; } - - public KernelMapTests(ITestOutputHelper output) - { - this.Output = output; - } - - [Theory(Skip = "TODO: Add asserionts")] - [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] - [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] - [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] - [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] - [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] - [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] - [InlineData(10, 100, nameof(KnownResamplers.Lanczos8))] - public void PrintKernelMap(int srcSize, int destSize, string resamplerName) - { - var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); - - var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); - - var bld = new StringBuilder(); - - foreach (ResizeKernel window in kernelMap.Kernels) - { - Span span = window.GetSpan(); - for (int i = 0; i < window.Length; i++) - { - float value = span[i]; - bld.Append($"{value,7:F4}"); - bld.Append("| "); - } - - bld.AppendLine(); - } - - string outDir = TestEnvironment.CreateOutputDirectory("." + nameof(this.PrintKernelMap)); - string fileName = $@"{outDir}\{resamplerName}_{srcSize}_{destSize}.MD"; - - File.WriteAllText(fileName, bld.ToString()); - - this.Output.WriteLine(bld.ToString()); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs new file mode 100644 index 0000000000..7d842c4e1e --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.ReferenceKernelMap.cs @@ -0,0 +1,111 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using System.Linq; + +using SixLabors.ImageSharp.Processing.Processors.Transforms; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +{ + public partial class ResizeKernelMapTests + { + /// + /// Simplified reference implementation for functionality. + /// + internal class ReferenceKernelMap + { + private readonly ReferenceKernel[] kernels; + + public ReferenceKernelMap(ReferenceKernel[] kernels) + { + this.kernels = kernels; + } + + public int DestinationSize => this.kernels.Length; + + public ReferenceKernel GetKernel(int destinationIndex) => this.kernels[destinationIndex]; + + public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize, bool normalize = true) + { + double ratio = (double)sourceSize / destinationSize; + double scale = ratio; + + if (scale < 1F) + { + scale = 1F; + } + + TolerantMath tolerantMath = TolerantMath.Default; + + double radius = tolerantMath.Ceiling(scale * sampler.Radius); + + var result = new List(); + + for (int i = 0; i < destinationSize; i++) + { + double center = ((i + .5) * ratio) - .5; + + // Keep inside bounds. + int left = (int)tolerantMath.Ceiling(center - radius); + if (left < 0) + { + left = 0; + } + + int right = (int)tolerantMath.Floor(center + radius); + if (right > sourceSize - 1) + { + right = sourceSize - 1; + } + + double sum = 0; + + double[] values = new double[right - left + 1]; + + for (int j = left; j <= right; j++) + { + double weight = sampler.GetValue((float)((j - center) / scale)); + sum += weight; + + values[j - left] = weight; + } + + if (sum > 0 && normalize) + { + for (int w = 0; w < values.Length; w++) + { + values[w] /= sum; + } + } + + float[] floatVals = values.Select(v => (float)v).ToArray(); + + result.Add(new ReferenceKernel(left, floatVals)); + } + + return new ReferenceKernelMap(result.ToArray()); + } + } + + internal struct ReferenceKernel + { + public ReferenceKernel(int left, float[] values) + { + this.Left = left; + this.Values = values; + } + + public int Left { get; } + + public float[] Values { get; } + + public int Length => this.Values.Length; + + public static implicit operator ReferenceKernel(ResizeKernel orig) + { + return new ReferenceKernel(orig.Left, orig.Values.ToArray()); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs new file mode 100644 index 0000000000..08b2949139 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeKernelMapTests.cs @@ -0,0 +1,241 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +{ + public partial class ResizeKernelMapTests + { + private ITestOutputHelper Output { get; } + + public ResizeKernelMapTests(ITestOutputHelper output) + { + this.Output = output; + } + + /// + /// resamplerName, srcSize, destSize + /// + public static readonly TheoryData KernelMapData = new TheoryData + { + { nameof(KnownResamplers.Bicubic), 15, 10 }, + { nameof(KnownResamplers.Bicubic), 10, 15 }, + { nameof(KnownResamplers.Bicubic), 20, 20 }, + { nameof(KnownResamplers.Bicubic), 50, 40 }, + { nameof(KnownResamplers.Bicubic), 40, 50 }, + { nameof(KnownResamplers.Bicubic), 500, 200 }, + { nameof(KnownResamplers.Bicubic), 200, 500 }, + + { nameof(KnownResamplers.Bicubic), 10, 25 }, + + { nameof(KnownResamplers.Lanczos3), 16, 12 }, + { nameof(KnownResamplers.Lanczos3), 12, 16 }, + { nameof(KnownResamplers.Lanczos3), 12, 9 }, + { nameof(KnownResamplers.Lanczos3), 9, 12 }, + { nameof(KnownResamplers.Lanczos3), 6, 8 }, + { nameof(KnownResamplers.Lanczos3), 8, 6 }, + { nameof(KnownResamplers.Lanczos3), 20, 12 }, + + { nameof(KnownResamplers.Lanczos3), 5, 25 }, + { nameof(KnownResamplers.Lanczos3), 5, 50 }, + + { nameof(KnownResamplers.Lanczos3), 25, 5 }, + { nameof(KnownResamplers.Lanczos3), 50, 5 }, + { nameof(KnownResamplers.Lanczos3), 49, 5 }, + { nameof(KnownResamplers.Lanczos3), 31, 5 }, + + { nameof(KnownResamplers.Lanczos8), 500, 200 }, + { nameof(KnownResamplers.Lanczos8), 100, 10 }, + { nameof(KnownResamplers.Lanczos8), 100, 80 }, + { nameof(KnownResamplers.Lanczos8), 10, 100 }, + + // Resize_WorksWithAllResamplers_Rgba32_CalliphoraPartial_Box-0.5: + { nameof(KnownResamplers.Box), 378, 149 }, + { nameof(KnownResamplers.Box), 349, 174 }, + + // Accuracy-related regression-test cases cherry-picked from GeneratedImageResizeData + { nameof(KnownResamplers.Box), 201, 100 }, + { nameof(KnownResamplers.Box), 199, 99 }, + { nameof(KnownResamplers.Box), 10, 299 }, + { nameof(KnownResamplers.Box), 299, 10 }, + { nameof(KnownResamplers.Box), 301, 300 }, + { nameof(KnownResamplers.Box), 1180, 480 }, + + { nameof(KnownResamplers.Lanczos2), 3264, 3032 }, + + { nameof(KnownResamplers.Bicubic), 1280, 2240 }, + { nameof(KnownResamplers.Bicubic), 1920, 1680 }, + { nameof(KnownResamplers.Bicubic), 3072, 2240 }, + + { nameof(KnownResamplers.Welch), 300, 2008 }, + + // ResizeKernel.Length -related regression tests cherry-picked from GeneratedImageResizeData + { nameof(KnownResamplers.Bicubic), 10, 50 }, + { nameof(KnownResamplers.Bicubic), 49, 301 }, + { nameof(KnownResamplers.Bicubic), 301, 49 }, + { nameof(KnownResamplers.Bicubic), 1680, 1200 }, + { nameof(KnownResamplers.Box), 13, 299 }, + { nameof(KnownResamplers.Lanczos5), 3032, 600 }, + }; + + public static TheoryData GeneratedImageResizeData = + GenerateImageResizeData(); + + + [Theory(Skip = "Only for debugging and development")] + [MemberData(nameof(KernelMapData))] + public void PrintNonNormalizedKernelMap(string resamplerName, int srcSize, int destSize) + { + IResampler resampler = TestUtils.GetResampler(resamplerName); + + var kernelMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize, false); + + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); + } + + [Theory] + [MemberData(nameof(KernelMapData))] + public void KernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) + { + this.VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + } + + // Comprehensive but expensive tests, for ResizeKernelMap. + // Enabling them can kill you, but sometimes you have to wear the burden! + // AppVeyor will never follow you to these shadows of Mordor. +#if false + [Theory] + [MemberData(nameof(GeneratedImageResizeData))] + public void KernelMapContentIsCorrect_ExtendedGeneratedValues(string resamplerName, int srcSize, int destSize) + { + this.VerifyKernelMapContentIsCorrect(resamplerName, srcSize, destSize); + } +#endif + + private void VerifyKernelMapContentIsCorrect(string resamplerName, int srcSize, int destSize) + { + IResampler resampler = TestUtils.GetResampler(resamplerName); + + var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize); + var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + +#if DEBUG + this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n"); + this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n"); +#endif + var comparer = new ApproximateFloatComparer(1e-6f); + + for (int i = 0; i < kernelMap.DestinationLength; i++) + { + ResizeKernel kernel = kernelMap.GetKernel(i); + + ReferenceKernel referenceKernel = referenceMap.GetKernel(i); + + Assert.True( + referenceKernel.Length == kernel.Length, + $"referenceKernel.Length != kernel.Length: {referenceKernel.Length} != {kernel.Length}"); + Assert.True( + referenceKernel.Left == kernel.Left, + $"referenceKernel.Left != kernel.Left: {referenceKernel.Left} != {kernel.Left}"); + float[] expectedValues = referenceKernel.Values; + Span actualValues = kernel.Values; + + Assert.Equal(expectedValues.Length, actualValues.Length); + + + + for (int x = 0; x < expectedValues.Length; x++) + { + Assert.True( + comparer.Equals(expectedValues[x], actualValues[x]), + $"{expectedValues[x]} != {actualValues[x]} @ (Row:{i}, Col:{x})"); + } + } + } + + private static string PrintKernelMap(ResizeKernelMap kernelMap) => + PrintKernelMap(kernelMap, km => km.DestinationLength, (km, i) => km.GetKernel(i)); + + private static string PrintKernelMap(ReferenceKernelMap kernelMap) => + PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i)); + + private static string PrintKernelMap( + TKernelMap kernelMap, + Func getDestinationSize, + Func getKernel) + { + var bld = new StringBuilder(); + + if (kernelMap is ResizeKernelMap actualMap) + { + bld.AppendLine(actualMap.Info); + } + + int destinationSize = getDestinationSize(kernelMap); + + for (int i = 0; i < destinationSize; i++) + { + ReferenceKernel kernel = getKernel(kernelMap, i); + bld.Append($"[{i:D3}] (L{kernel.Left:D3}) || "); + Span span = kernel.Values; + + for (int j = 0; j < kernel.Length; j++) + { + float value = span[j]; + bld.Append($"{value,8:F5}"); + bld.Append(" | "); + } + + bld.AppendLine(); + } + + return bld.ToString(); + } + + + private static TheoryData GenerateImageResizeData() + { + var result = new TheoryData(); + + string[] resamplerNames = typeof(KnownResamplers).GetProperties(BindingFlags.Public | BindingFlags.Static) + .Select(p => p.Name) + .Where(name => name != nameof(KnownResamplers.NearestNeighbor)) + .ToArray(); + + int[] dimensionVals = + { + // Arbitrary, small dimensions: + 9, 10, 11, 13, 49, 50, 53, 99, 100, 199, 200, 201, 299, 300, 301, + + // Typical image sizes: + 640, 480, 800, 600, 1024, 768, 1280, 960, 1536, 1180, 1600, 1200, 2048, 1536, 2240, 1680, 2560, + 1920, 3032, 2008, 3072, 2304, 3264, 2448 + }; + + IOrderedEnumerable<(int s, int d)> source2Dest = dimensionVals + .SelectMany(s => dimensionVals.Select(d => (s, d))) + .OrderBy(x => x.s + x.d); + + foreach (string resampler in resamplerNames) + { + foreach ((int s, int d) x in source2Dest) + { + result.Add(resampler, x.s, x.d); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index bec64e4d37..b4aff53e82 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -11,6 +11,7 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; +// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { @@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F); - public static readonly TheoryData AllReSamplers = + public static readonly TheoryData AllResamplers = new TheoryData { { "Bicubic", KnownResamplers.Bicubic }, @@ -40,9 +41,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms }; [Theory] - [WithTestPatternImages(nameof(AllReSamplers), 100, 100, DefaultPixelType, 0.5f)] - [WithFileCollection(nameof(CommonTestImages), nameof(AllReSamplers), DefaultPixelType, 0.5f)] - [WithFileCollection(nameof(CommonTestImages), nameof(AllReSamplers), DefaultPixelType, 0.3f)] + [WithTestPatternImages(nameof(AllResamplers), 100, 100, DefaultPixelType, 0.5f)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.5f)] + [WithFileCollection(nameof(CommonTestImages), nameof(AllResamplers), DefaultPixelType, 0.3f)] public void Resize_WorksWithAllResamplers(TestImageProvider provider, string name, IResampler sampler, float ratio) where TPixel : struct, IPixel { diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs index d1d2ea0771..29c51543fc 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/SkewTest.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { foreach (string resamplerName in ResamplerNames) { - IResampler sampler = GetResampler(resamplerName); + IResampler sampler = TestUtils.GetResampler(resamplerName); using (Image image = provider.GetImage()) { image.Mutate(i => i.Skew(x, y, sampler)); @@ -68,17 +68,5 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } } - - private static IResampler GetResampler(string name) - { - PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); - - if (property is null) - { - throw new Exception($"No resampler named '{name}"); - } - - return (IResampler)property.GetValue(null); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs new file mode 100644 index 0000000000..70159e18ac --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformBuilderTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public class AffineTransformBuilderTests : TransformBuilderTestBase + { + protected override AffineTransformBuilder CreateBuilder(Rectangle rectangle) => new AffineTransformBuilder(); + + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees) + => builder.AppendRotationDegrees(degrees); + + protected override void AppendRotationDegrees(AffineTransformBuilder builder, float degrees, Vector2 origin) + => builder.AppendRotationDegrees(degrees, origin); + + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians) + => builder.AppendRotationRadians(radians); + + protected override void AppendRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) + => builder.AppendRotationRadians(radians, origin); + + protected override void AppendScale(AffineTransformBuilder builder, SizeF scale) + => builder.AppendScale(scale); + + protected override void AppendSkewDegrees(AffineTransformBuilder builder, float degreesX, float degreesY) + => builder.AppendSkewDegrees(degreesX, degreesY); + + protected override void AppendSkewDegrees(AffineTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) + => builder.AppendSkewDegrees(degreesX, degreesY, origin); + + protected override void AppendSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY) + => builder.AppendSkewRadians(radiansX, radiansY); + + protected override void AppendSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.AppendSkewRadians(radiansX, radiansY, origin); + + protected override void AppendTranslation(AffineTransformBuilder builder, PointF translate) + => builder.AppendTranslation(translate); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians) + => builder.PrependRotationRadians(radians); + + protected override void PrependRotationRadians(AffineTransformBuilder builder, float radians, Vector2 origin) + => builder.PrependRotationRadians(radians, origin); + + protected override void PrependScale(AffineTransformBuilder builder, SizeF scale) + => builder.PrependScale(scale); + + protected override void PrependSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY) + => builder.PrependSkewRadians(radiansX, radiansY); + + protected override void PrependSkewRadians(AffineTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.PrependSkewRadians(radiansX, radiansY, origin); + + protected override void PrependTranslation(AffineTransformBuilder builder, PointF translate) + => builder.PrependTranslation(translate); + + protected override Vector2 Execute( + AffineTransformBuilder builder, + Rectangle rectangle, + Vector2 sourcePoint) + { + Matrix3x2 matrix = builder.BuildMatrix(rectangle); + return Vector2.Transform(sourcePoint, matrix); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs index edc6994e7a..ed6d3ef2bc 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AffineTransformTests.cs @@ -17,7 +17,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { private readonly ITestOutputHelper Output; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0085f, 3); + // 1 byte difference on one color component. + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0134F, 3); /// /// angleDeg, sx, sy, tx, ty @@ -65,10 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms nameof(KnownResamplers.Lanczos8), }; - public AffineTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public AffineTransformTests(ITestOutputHelper output) => this.Output = output; /// /// The output of an "all white" image should be "all white" or transparent, regardless of the transformation and the resampler. @@ -81,15 +79,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler resampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - var rotate = Matrix3x2.CreateRotation((float)Math.PI / 4F, new Vector2(5 / 2F, 5 / 2F)); - var translate = Matrix3x2.CreateTranslation((7 - 5) / 2F, (7 - 5) / 2F); - - Rectangle sourceRectangle = image.Bounds(); - Matrix3x2 matrix = rotate * translate; + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(30); - Rectangle destRectangle = TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, matrix); - - image.Mutate(c => c.Transform(matrix, resampler, destRectangle)); + image.Mutate(c => c.Transform(builder, resampler)); image.DebugSave(provider, resamplerName); VerifyAllPixelsAreWhiteOrTransparent(image); @@ -107,14 +100,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(angleDeg); - var translate = Matrix3x2.CreateTranslation(tx, ty); - var scale = Matrix3x2.CreateScale(sx, sy); - Matrix3x2 m = rotate * scale * translate; + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(sx, sy)) + .AppendTranslation(new PointF(tx, ty)); - this.PrintMatrix(m); + this.PrintMatrix(builder.BuildMatrix(image.Size())); - image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; image.DebugSave(provider, testOutputDetails); @@ -129,9 +123,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix3x2 m = this.MakeManuallyCenteredMatrix(angleDeg, s, image); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(s, s)); - image.Mutate(i => i.Transform(m, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; image.DebugSave(provider, testOutputDetails); @@ -158,13 +154,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void Transform_FromSourceRectangle1(TestImageProvider provider) where TPixel : struct, IPixel { - var rectangle = new Rectangle(48, 0, 96, 36); + var rectangle = new Rectangle(48, 0, 48, 24); using (Image image = provider.GetImage()) { - var m = Matrix3x2.CreateScale(2.0F, 1.5F); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendScale(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(m, KnownResamplers.Spline, rectangle)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -176,13 +174,14 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void Transform_FromSourceRectangle2(TestImageProvider provider) where TPixel : struct, IPixel { - var rectangle = new Rectangle(0, 24, 48, 48); + var rectangle = new Rectangle(0, 24, 48, 24); using (Image image = provider.GetImage()) { - var m = Matrix3x2.CreateScale(1.0F, 2.0F); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendScale(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(m, KnownResamplers.Spline, rectangle)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); image.DebugSave(provider); image.CompareToReferenceOutput(ValidatorComparer, provider); @@ -197,33 +196,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - Matrix3x2 m = this.MakeManuallyCenteredMatrix(50, 0.6f, image); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(50) + .AppendScale(new SizeF(.6F, .6F)); - image.Mutate(i => - { - i.Transform(m, sampler); - }); + image.Mutate(i => i.Transform(builder, sampler)); image.DebugSave(provider, resamplerName); image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); } } - private Matrix3x2 MakeManuallyCenteredMatrix(float angleDeg, float s, Image image) - where TPixel : struct, IPixel - { - Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(angleDeg); - Vector2 toCenter = 0.5f * new Vector2(image.Width, image.Height); - var translate = Matrix3x2.CreateTranslation(-toCenter); - var translateBack = Matrix3x2.CreateTranslation(toCenter); - var scale = Matrix3x2.CreateScale(s); - - Matrix3x2 m = translate * rotate * scale * translateBack; - - this.PrintMatrix(m); - return m; - } - private static IResampler GetResampler(string name) { PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); @@ -240,12 +223,15 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms where TPixel : struct, IPixel { Span data = image.Frames.RootFrame.GetPixelSpan(); - var rgba = default(Rgba32); var white = new Rgb24(255, 255, 255); foreach (TPixel pixel in data) { + Rgba32 rgba = default; pixel.ToRgba32(ref rgba); - if (rgba.A == 0) continue; + if (rgba.A == 0) + { + continue; + } Assert.Equal(white, rgba.Rgb); } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs new file mode 100644 index 0000000000..d82cd1689d --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformBuilderTests.cs @@ -0,0 +1,62 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public class ProjectiveTransformBuilderTests : TransformBuilderTestBase + { + protected override ProjectiveTransformBuilder CreateBuilder(Rectangle rectangle) => new ProjectiveTransformBuilder(); + + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees) => builder.AppendRotationDegrees(degrees); + + protected override void AppendRotationDegrees(ProjectiveTransformBuilder builder, float degrees, Vector2 origin) => builder.AppendRotationDegrees(degrees, origin); + + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.AppendRotationRadians(radians); + + protected override void AppendRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => builder.AppendRotationRadians(radians, origin); + + protected override void AppendScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.AppendScale(scale); + + protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY) + => builder.AppendSkewDegrees(degreesX, degreesY); + + protected override void AppendSkewDegrees(ProjectiveTransformBuilder builder, float degreesX, float degreesY, Vector2 origin) + => builder.AppendSkewDegrees(degreesX, degreesY, origin); + + protected override void AppendSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY) + => builder.AppendSkewRadians(radiansX, radiansY); + + protected override void AppendSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.AppendSkewRadians(radiansX, radiansY, origin); + + protected override void AppendTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.AppendTranslation(translate); + + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians) => builder.PrependRotationRadians(radians); + + protected override void PrependScale(ProjectiveTransformBuilder builder, SizeF scale) => builder.PrependScale(scale); + + protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY) + => builder.PrependSkewRadians(radiansX, radiansY); + + protected override void PrependSkewRadians(ProjectiveTransformBuilder builder, float radiansX, float radiansY, Vector2 origin) + => builder.PrependSkewRadians(radiansX, radiansY, origin); + + protected override void PrependTranslation(ProjectiveTransformBuilder builder, PointF translate) => builder.PrependTranslation(translate); + + protected override void PrependRotationRadians(ProjectiveTransformBuilder builder, float radians, Vector2 origin) => + builder.PrependRotationRadians(radians, origin); + + protected override Vector2 Execute( + ProjectiveTransformBuilder builder, + Rectangle rectangle, + Vector2 sourcePoint) + { + Matrix4x4 matrix = builder.BuildMatrix(rectangle); + return Vector2.Transform(sourcePoint, matrix); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 5190a71e71..1da660d222 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms private static readonly ImageComparer TolerantComparer = ImageComparer.TolerantPercentage(0.5f, 3); private ITestOutputHelper Output { get; } - + public static readonly TheoryData ResamplerNames = new TheoryData { nameof(KnownResamplers.Bicubic), @@ -60,10 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms }; - public ProjectiveTransformTests(ITestOutputHelper output) - { - this.Output = output; - } + public ProjectiveTransformTests(ITestOutputHelper output) => this.Output = output; [Theory] [WithTestPatternImages(nameof(ResamplerNames), 150, 150, PixelTypes.Rgba32)] @@ -73,9 +70,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms IResampler sampler = GetResampler(resamplerName); using (Image image = provider.GetImage()) { - Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), TaperSide.Right, TaperCorner.Both, .5F); + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() + .AppendTaper(TaperSide.Right, TaperCorner.Both, .5F); - image.Mutate(i => { i.Transform(m, sampler); }); + image.Mutate(i => i.Transform(builder, sampler)); image.DebugSave(provider, resamplerName); image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); @@ -89,8 +87,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { using (Image image = provider.GetImage()) { - Matrix4x4 m = ProjectiveTransformHelper.CreateTaperMatrix(image.Size(), taperSide, taperCorner, .5F); - image.Mutate(i => { i.Transform(m); }); + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() + .AppendTaper(taperSide, taperCorner, .5F); + + image.Mutate(i => i.Transform(builder)); FormattableString testOutputDetails = $"{taperSide}-{taperCorner}"; image.DebugSave(provider, testOutputDetails); @@ -110,10 +110,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms // https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/non-affine using (Image image = provider.GetImage()) { - Matrix4x4 m = Matrix4x4.Identity; - m.M13 = 0.01F; + Matrix4x4 matrix = Matrix4x4.Identity; + matrix.M13 = 0.01F; + + ProjectiveTransformBuilder builder = new ProjectiveTransformBuilder() + .AppendMatrix(matrix); - image.Mutate(i => { i.Transform(m); }); + image.Mutate(i => i.Transform(builder)); image.DebugSave(provider); image.CompareToReferenceOutput(TolerantComparer, provider); diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs new file mode 100644 index 0000000000..71e3b71797 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformBuilderTestBase.cs @@ -0,0 +1,275 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Transforms +{ + public abstract class TransformBuilderTestBase + { + private static readonly ApproximateFloatComparer Comparer = new ApproximateFloatComparer(1e-6f); + + public static readonly TheoryData ScaleTranslate_Data = + new TheoryData + { + // scale, translate, source, expectedDest + { Vector2.One, Vector2.Zero, Vector2.Zero, Vector2.Zero }, + { Vector2.One, Vector2.Zero, new Vector2(10, 20), new Vector2(10, 20) }, + { Vector2.One, new Vector2(3, 1), new Vector2(10, 20), new Vector2(13, 21) }, + { new Vector2(2, 0.5f), new Vector2(3, 1), new Vector2(10, 20), new Vector2(23, 11) }, + }; + + [Theory] + [MemberData(nameof(ScaleTranslate_Data))] + public void _1Scale_2Translate(Vector2 scale, Vector2 translate, Vector2 source, Vector2 expectedDest) + { + // These operations should be size-agnostic: + var size = new Size(123, 321); + TBuilder builder = this.CreateBuilder(size); + + this.AppendScale(builder, new SizeF(scale)); + this.AppendTranslation(builder, translate); + + Vector2 actualDest = this.Execute(builder, new Rectangle(Point.Empty, size), source); + Assert.True(Comparer.Equals(expectedDest, actualDest)); + } + + public static readonly TheoryData TranslateScale_Data = + new TheoryData + { + // translate, scale, source, expectedDest + { Vector2.Zero, Vector2.One, Vector2.Zero, Vector2.Zero }, + { Vector2.Zero, Vector2.One, new Vector2(10, 20), new Vector2(10, 20) }, + { new Vector2(3, 1), new Vector2(2, 0.5f), new Vector2(10, 20), new Vector2(26, 10.5f) }, + }; + + [Theory] + [MemberData(nameof(TranslateScale_Data))] + public void _1Translate_2Scale(Vector2 translate, Vector2 scale, Vector2 source, Vector2 expectedDest) + { + // Translate ans scale are size-agnostic: + var size = new Size(456, 432); + TBuilder builder = this.CreateBuilder(size); + + this.AppendTranslation(builder, translate); + this.AppendScale(builder, new SizeF(scale)); + + Vector2 actualDest = this.Execute(builder, new Rectangle(Point.Empty, size), source); + Assert.Equal(expectedDest, actualDest, Comparer); + } + + [Theory] + [InlineData(10, 20)] + [InlineData(-20, 10)] + public void LocationOffsetIsPrepended(int locationX, int locationY) + { + var rectangle = new Rectangle(locationX, locationY, 10, 10); + TBuilder builder = this.CreateBuilder(rectangle); + + this.AppendScale(builder, new SizeF(2, 2)); + + Vector2 actual = this.Execute(builder, rectangle, Vector2.One); + Vector2 expected = new Vector2(-locationX + 1, -locationY + 1) * 2; + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 42, 84)] + [InlineData(200, 100, 100, 42, 84)] + [InlineData(100, 200, -10, 42, 84)] + public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter( + int width, + int height, + float degrees, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + this.AppendRotationDegrees(builder, degrees); + + // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness + Matrix3x2 matrix = TransformUtils.CreateRotationMatrixDegrees(degrees, size); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 30, 61, 42, 84)] + [InlineData(200, 100, 100, 30, 10, 20, 84)] + [InlineData(100, 200, -10, 30, 20, 11, 84)] + public void AppendRotationDegrees_WithRotationCenter( + int width, + int height, + float degrees, + float cx, + float cy, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + var centerPoint = new Vector2(cx, cy); + this.AppendRotationDegrees(builder, degrees, centerPoint); + + var matrix = Matrix3x2.CreateRotation(GeometryUtilities.DegreeToRadian(degrees), centerPoint); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 10, 42, 84)] + [InlineData(200, 100, 100, 100, 42, 84)] + [InlineData(100, 200, -10, -10, 42, 84)] + public void AppendSkewDegrees_WithoutSpecificSkewCenter_SkewIsCenteredAroundImageCenter( + int width, + int height, + float degreesX, + float degreesY, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + this.AppendSkewDegrees(builder, degreesX, degreesY); + + Matrix3x2 matrix = TransformUtils.CreateSkewMatrixDegrees(degreesX, degreesY, size); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + Assert.Equal(actual, expected, Comparer); + } + + [Theory] + [InlineData(200, 100, 10, 10, 30, 61, 42, 84)] + [InlineData(200, 100, 100, 100, 30, 10, 20, 84)] + [InlineData(100, 200, -10, -10, 30, 20, 11, 84)] + public void AppendSkewDegrees_WithSkewCenter( + int width, + int height, + float degreesX, + float degreesY, + float cx, + float cy, + float x, + float y) + { + var size = new Size(width, height); + TBuilder builder = this.CreateBuilder(size); + + var centerPoint = new Vector2(cx, cy); + this.AppendSkewDegrees(builder, degreesX, degreesY, centerPoint); + + var matrix = Matrix3x2.CreateSkew(GeometryUtilities.DegreeToRadian(degreesX), GeometryUtilities.DegreeToRadian(degreesY), centerPoint); + + var position = new Vector2(x, y); + var expected = Vector2.Transform(position, matrix); + Vector2 actual = this.Execute(builder, new Rectangle(Point.Empty, size), position); + + Assert.Equal(actual, expected, Comparer); + } + + [Fact] + public void AppendPrependOpposite() + { + var rectangle = new Rectangle(-1, -1, 3, 3); + TBuilder b1 = this.CreateBuilder(rectangle); + TBuilder b2 = this.CreateBuilder(rectangle); + + const float pi = (float)Math.PI; + + // Forwards + this.AppendRotationRadians(b1, pi); + this.AppendSkewRadians(b1, pi, pi); + this.AppendScale(b1, new SizeF(2, 0.5f)); + this.AppendRotationRadians(b1, pi / 2, new Vector2(-0.5f, -0.1f)); + this.AppendSkewRadians(b1, pi, pi / 2, new Vector2(-0.5f, -0.1f)); + this.AppendTranslation(b1, new PointF(123, 321)); + + // Backwards + this.PrependTranslation(b2, new PointF(123, 321)); + this.PrependSkewRadians(b2, pi, pi / 2, new Vector2(-0.5f, -0.1f)); + this.PrependRotationRadians(b2, pi / 2, new Vector2(-0.5f, -0.1f)); + this.PrependScale(b2, new SizeF(2, 0.5f)); + this.PrependSkewRadians(b2, pi, pi); + this.PrependRotationRadians(b2, pi); + + Vector2 p1 = this.Execute(b1, rectangle, new Vector2(32, 65)); + Vector2 p2 = this.Execute(b2, rectangle, new Vector2(32, 65)); + + Assert.Equal(p1, p2, Comparer); + } + + [Theory] + [InlineData(0, 1)] + [InlineData(1, 0)] + [InlineData(-1, 0)] + public void ThrowsForInvalidSizes(int width, int height) + { + var size = new Size(width, height); + + Assert.ThrowsAny( + () => + { + TBuilder builder = this.CreateBuilder(size); + this.Execute(builder, new Rectangle(Point.Empty, size), Vector2.Zero); + }); + } + + protected TBuilder CreateBuilder(Size size) => this.CreateBuilder(new Rectangle(Point.Empty, size)); + + protected abstract TBuilder CreateBuilder(Rectangle rectangle); + + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees); + + protected abstract void AppendRotationDegrees(TBuilder builder, float degrees, Vector2 origin); + + protected abstract void AppendRotationRadians(TBuilder builder, float radians); + + protected abstract void AppendRotationRadians(TBuilder builder, float radians, Vector2 origin); + + protected abstract void AppendScale(TBuilder builder, SizeF scale); + + protected abstract void AppendSkewDegrees(TBuilder builder, float degreesX, float degreesY); + + protected abstract void AppendSkewDegrees(TBuilder builder, float degreesX, float degreesY, Vector2 origin); + + protected abstract void AppendSkewRadians(TBuilder builder, float radiansX, float radiansY); + + protected abstract void AppendSkewRadians(TBuilder builder, float radiansX, float radiansY, Vector2 origin); + + protected abstract void AppendTranslation(TBuilder builder, PointF translate); + + protected abstract void PrependRotationRadians(TBuilder builder, float radians); + + protected abstract void PrependRotationRadians(TBuilder builder, float radians, Vector2 origin); + + protected abstract void PrependScale(TBuilder builder, SizeF scale); + + protected abstract void PrependSkewRadians(TBuilder builder, float radiansX, float radiansY); + + protected abstract void PrependSkewRadians(TBuilder builder, float radiansX, float radiansY, Vector2 origin); + + protected abstract void PrependTranslation(TBuilder builder, PointF translate); + + protected abstract Vector2 Execute(TBuilder builder, Rectangle rectangle, Vector2 sourcePoint); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs index 146ed62304..909e505357 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelYDimension).DataType); - TransformHelpers.UpdateDimensionalMetData(img); + TransformProcessorHelpers.UpdateDimensionalMetData(img); Assert.Equal(ExifDataType.Short, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Short, profile.GetValue(ExifTag.PixelYDimension).DataType); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs similarity index 54% rename from tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs index 32538090dc..65989556d2 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/JpegProfilingBenchmarks.cs @@ -13,7 +13,7 @@ using SixLabors.ImageSharp.PixelFormats; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.Formats.Jpg +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { public class JpegProfilingBenchmarks : MeasureFixture { @@ -22,18 +22,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { } - public static readonly TheoryData DecodeJpegData = new TheoryData() + public static readonly TheoryData DecodeJpegData = new TheoryData { - TestImages.Jpeg.Baseline.Cmyk, - TestImages.Jpeg.Baseline.Ycck, - TestImages.Jpeg.Baseline.Calliphora, - TestImages.Jpeg.Baseline.Jpeg400, - TestImages.Jpeg.Baseline.Jpeg420Exif, - TestImages.Jpeg.Baseline.Jpeg444, + TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome, + TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr, + TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr, + TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr, + TestImages.Jpeg.BenchmarkSuite.BadRstProgressive518_Large444YCbCr, + TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr, }; - // [Theory] // Benchmark, enable manually - // [MemberData(nameof(DecodeJpegData))] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [MemberData(nameof(DecodeJpegData))] public void DecodeJpeg(string fileName) { this.DecodeJpegBenchmarkImpl(fileName, new JpegDecoder()); @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg return; } - const int ExecutionCount = 30; + const int ExecutionCount = 20; if (!Vector.IsHardwareAccelerated) { @@ -62,17 +62,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg () => { var img = Image.Load(bytes, decoder); + img.Dispose(); }, // ReSharper disable once ExplicitCallerInfoArgument $"Decode {fileName}"); } // Benchmark, enable manually! - // [Theory] - // [InlineData(1, 75, JpegSubsample.Ratio420)] - // [InlineData(30, 75, JpegSubsample.Ratio420)] - // [InlineData(30, 75, JpegSubsample.Ratio444)] - // [InlineData(30, 100, JpegSubsample.Ratio444)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [InlineData(1, 75, JpegSubsample.Ratio420)] + [InlineData(30, 75, JpegSubsample.Ratio420)] + [InlineData(30, 75, JpegSubsample.Ratio444)] + [InlineData(30, 100, JpegSubsample.Ratio444)] public void EncodeJpeg(int executionCount, int quality, JpegSubsample subsample) { // do not run this on CI even by accident @@ -82,31 +83,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } string[] testFiles = TestImages.Bmp.All - .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }) - .ToArray(); + .Concat(new[] { TestImages.Jpeg.Baseline.Calliphora, TestImages.Jpeg.Baseline.Cmyk }).ToArray(); - Image[] testImages = - testFiles.Select( - tf => TestImageProvider.File(tf, pixelTypeOverride: PixelTypes.Rgba32).GetImage()) - .ToArray(); + Image[] testImages = testFiles.Select( + tf => TestImageProvider.File(tf, pixelTypeOverride: PixelTypes.Rgba32).GetImage()).ToArray(); using (var ms = new MemoryStream()) { - this.Measure(executionCount, + this.Measure( + executionCount, () => - { - foreach (Image img in testImages) { - var options = new JpegEncoder { Quality = quality, Subsample = subsample }; - img.Save(ms, options); - ms.Seek(0, SeekOrigin.Begin); - } - }, + foreach (Image img in testImages) + { + var options = new JpegEncoder { Quality = quality, Subsample = subsample }; + img.Save(ms, options); + ms.Seek(0, SeekOrigin.Begin); + } + }, // ReSharper disable once ExplicitCallerInfoArgument - $@"Encode {testFiles.Length} images" - ); + $@"Encode {testFiles.Length} images"); } - } + foreach (Image image in testImages) + { + image.Dispose(); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs new file mode 100644 index 0000000000..95fe4e48f1 --- /dev/null +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/LoadResizeSaveProfilingBenchmarks.cs @@ -0,0 +1,44 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.IO; + +using SixLabors.ImageSharp.Processing; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks +{ + public class LoadResizeSaveProfilingBenchmarks : MeasureFixture + { + public LoadResizeSaveProfilingBenchmarks(ITestOutputHelper output) + : base(output) + { + } + + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] + [InlineData(TestImages.Jpeg.Baseline.Jpeg420Exif)] + public void LoadResizeSave(string imagePath) + { + var configuration = Configuration.CreateDefaultInstance(); + configuration.MaxDegreeOfParallelism = 1; + + byte[] imageBytes = TestFile.Create(imagePath).Bytes; + + using (var ms = new MemoryStream()) + { + this.Measure(30, + () => + { + using (var image = Image.Load(configuration, imageBytes)) + { + image.Mutate(x => x.Resize(image.Size() / 4)); + image.SaveAsJpeg(ms); + } + ms.Seek(0, SeekOrigin.Begin); + }); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs new file mode 100644 index 0000000000..f9a68d4e7c --- /dev/null +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ProfilingSetup.cs @@ -0,0 +1,18 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// Uncomment to enable local profiling benchmarks. DO NOT PUSH TO MAIN! +// #define PROFILING + +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks +{ + public static class ProfilingSetup + { + public const string SkipProfilingTests = +#if PROFILING + null; +#else + "Profiling benchmark, enable manually!"; +#endif + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs similarity index 82% rename from tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs rename to tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs index e24458d384..8b93559381 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/ProfilingBenchmarks/ResizeProfilingBenchmarks.cs @@ -7,17 +7,10 @@ using SixLabors.ImageSharp.Processing; using Xunit; using Xunit.Abstractions; -namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +namespace SixLabors.ImageSharp.Tests.ProfilingBenchmarks { public class ResizeProfilingBenchmarks : MeasureFixture { - public const string SkipText = -#if false - null; -#else - "Benchmark, enable manually!"; -#endif - private readonly Configuration configuration = Configuration.CreateDefaultInstance(); public ResizeProfilingBenchmarks(ITestOutputHelper output) @@ -28,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public int ExecutionCount { get; set; } = 50; - [Theory(Skip = SkipText)] + [Theory(Skip = ProfilingSetup.SkipProfilingTests)] [InlineData(100, 100)] [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) diff --git a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs index c2b1c26c54..a0d7869e39 100644 --- a/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs +++ b/tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs @@ -10,48 +10,33 @@ namespace SixLabors.ImageSharp.Tests { public class QuantizedImageTests { + private Configuration Configuration => Configuration.Default; + [Fact] public void QuantizersDitherByDefault() { - var palette = new PaletteQuantizer(); + var werner = new WernerPaletteQuantizer(); + var websafe = new WebSafePaletteQuantizer(); var octree = new OctreeQuantizer(); var wu = new WuQuantizer(); - Assert.NotNull(palette.Diffuser); + Assert.NotNull(werner.Diffuser); + Assert.NotNull(websafe.Diffuser); Assert.NotNull(octree.Diffuser); Assert.NotNull(wu.Diffuser); - Assert.True(palette.CreateFrameQuantizer().Dither); - Assert.True(octree.CreateFrameQuantizer().Dither); - Assert.True(wu.CreateFrameQuantizer().Dither); - } - - [Theory] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void PaletteQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - Assert.True(image[0, 0].Equals(default(TPixel))); - - var quantizer = new PaletteQuantizer(dither); - - foreach (ImageFrame frame in image.Frames) - { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); - - int index = this.GetTransparentIndex(quantized); - Assert.Equal(index, quantized.GetPixelSpan()[0]); - } - } + Assert.True(werner.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(websafe.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(octree.CreateFrameQuantizer(this.Configuration).Dither); + Assert.True(wu.CreateFrameQuantizer(this.Configuration).Dither); } [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)] - public void OctreeQuantizerYieldsCorrectTransparentPixel(TestImageProvider provider, bool dither) + public void OctreeQuantizerYieldsCorrectTransparentPixel( + TestImageProvider provider, + bool dither) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -62,7 +47,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -84,7 +70,8 @@ namespace SixLabors.ImageSharp.Tests foreach (ImageFrame frame in image.Frames) { - QuantizedFrame quantized = quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + QuantizedFrame quantized = + quantizer.CreateFrameQuantizer(this.Configuration).QuantizeFrame(frame); int index = this.GetTransparentIndex(quantized); Assert.Equal(index, quantized.GetPixelSpan()[0]); @@ -97,12 +84,12 @@ namespace SixLabors.ImageSharp.Tests { // Transparent pixels are much more likely to be found at the end of a palette int index = -1; - var trans = default(Rgba32); + Rgba32 trans = default; for (int i = quantized.Palette.Length - 1; i >= 0; i--) { quantized.Palette[i].ToRgba32(ref trans); - if (trans.Equals(default(Rgba32))) + if (trans.Equals(default)) { index = i; } diff --git a/tests/ImageSharp.Tests/RunExtendedTests.cmd b/tests/ImageSharp.Tests/RunExtendedTests.cmd index 481e5fb3d8..c2f4b9f537 100644 --- a/tests/ImageSharp.Tests/RunExtendedTests.cmd +++ b/tests/ImageSharp.Tests/RunExtendedTests.cmd @@ -5,3 +5,5 @@ dotnet xunit -nobuild -c Release -f net47 dotnet xunit -nobuild -c Release -f net47 -x86 dotnet xunit -nobuild -c Release -f net471 dotnet xunit -nobuild -c Release -f net471 -x86 +dotnet xunit -nobuild -c Release -f net472 +dotnet xunit -nobuild -c Release -f net472 -x86 diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index fdf586c430..1144a3f7c0 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -45,6 +45,10 @@ namespace SixLabors.ImageSharp.Tests public const string Kaboom = "Png/kaboom.png"; public const string PDSrc = "Png/pd-source.png"; public const string PDDest = "Png/pd-dest.png"; + public const string Gray1BitTrans = "Png/gray-1-trns.png"; + public const string Gray2BitTrans = "Png/gray-2-tRNS.png"; + public const string Gray4BitTrans = "Png/gray-4-tRNS.png"; + public const string Gray8BitTrans = "Png/gray-8-tRNS.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; @@ -159,9 +163,23 @@ namespace SixLabors.ImageSharp.Tests public const string OrderedInterleavedProgressive723A = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg"; public const string OrderedInterleavedProgressive723B = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg"; public const string OrderedInterleavedProgressive723C = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg"; + public const string ExifGetString750Transform = "Jpg/issues/issue750-exif-tranform.jpg"; + public const string ExifGetString750Load = "Jpg/issues/issue750-exif-load.jpg"; } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); + + public static class BenchmarkSuite + { + public const string Jpeg400_SmallMonochrome = Baseline.Jpeg400; + public const string Jpeg420Exif_MidSizeYCbCr = Baseline.Jpeg420Exif; + public const string Lake_Small444YCbCr = Baseline.Lake; + + // A few large images from the "issues" set are actually very useful for benchmarking: + public const string MissingFF00ProgressiveBedroom159_MidSize420YCbCr = Issues.MissingFF00ProgressiveBedroom159; + public const string BadRstProgressive518_Large444YCbCr = Issues.BadRstProgressive518; + public const string ExifGetString750Transform_Huge420YCbCr = Issues.ExifGetString750Transform; + } } public static class Bmp diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index 854e57d8f5..47ca6cccb2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -11,7 +11,8 @@ namespace SixLabors.ImageSharp.Tests /// internal readonly struct ApproximateFloatComparer : IEqualityComparer, - IEqualityComparer + IEqualityComparer, + IEqualityComparer { private readonly float Epsilon; @@ -33,9 +34,17 @@ namespace SixLabors.ImageSharp.Tests public int GetHashCode(float obj) => obj.GetHashCode(); /// - public bool Equals(Vector4 x, Vector4 y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W); + public bool Equals(Vector4 a, Vector4 b) => this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y) && this.Equals(a.Z, b.Z) && this.Equals(a.W, b.W); /// public int GetHashCode(Vector4 obj) => obj.GetHashCode(); + + /// + public bool Equals(Vector2 a, Vector2 b) => this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y); + + public int GetHashCode(Vector2 obj) + { + throw new System.NotImplementedException(); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 8dca11caeb..462782ba5e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -28,14 +28,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison var bBuffer = new Rgba64[width]; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 674603380f..be12f56211 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -74,14 +74,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison float totalDifference = 0F; var differences = new List(); + Configuration configuration = expected.Configuration; for (int y = 0; y < actual.Height; y++) { Span aSpan = expected.GetPixelRowSpan(y); Span bSpan = actual.GetPixelRowSpan(y); - PixelOperations.Instance.ToRgba64(aSpan, aBuffer, width); - PixelOperations.Instance.ToRgba64(bSpan, bBuffer, width); + PixelOperations.Instance.ToRgba64(configuration, aSpan, aBuffer); + PixelOperations.Instance.ToRgba64(configuration, bSpan, bBuffer); for (int x = 0; x < width; x++) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 97ed30b997..d68c37a768 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests { Image image = base.GetImage(); TPixel color = default(TPixel); - color.PackFromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); + color.FromRgba32(new Rgba32(this.r, this.g, this.b, this.a)); image.Mutate(x => x.Fill(color)); return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 71ae60fabc..cc09dc0573 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -163,20 +163,20 @@ namespace SixLabors.ImageSharp.Tests { blue.W = red.W = green.W = (float)x / (float)right; - c.PackFromVector4(red); + c.FromVector4(red); int topBand = top; for (int y = topBand; y < top + height; y++) { pixels[x, y] = c; } topBand = topBand + height; - c.PackFromVector4(green); + c.FromVector4(green); for (int y = topBand; y < topBand + height; y++) { pixels[x, y] = c; } topBand = topBand + height; - c.PackFromVector4(blue); + c.FromVector4(blue); for (int y = topBand; y < bottom; y++) { pixels[x, y] = c; @@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests t.PackedValue += stepsPerPixel; Vector4 v = t.ToVector4(); //v.W = (x - left) / (float)left; - c.PackFromVector4(v); + c.FromVector4(v); pixels[x, y] = c; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 65b32e0880..c91ef56a1a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -72,7 +72,10 @@ namespace SixLabors.ImageSharp.Tests extension = '.' + extension; } - if (fn != string.Empty) fn = '_' + fn; + if (fn != string.Empty) + { + fn = '_' + fn; + } string pixName = ""; @@ -274,17 +277,14 @@ namespace SixLabors.ImageSharp.Tests } public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) - where TPixel : struct, IPixel - { - ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); - } + where TPixel : struct, IPixel => ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { TPixel pixel = img[x, y]; Rgba64 rgbaPixel = default; - pixel.ToRgba64(ref rgbaPixel); + rgbaPixel.FromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests rgbaPixel.A -= perChannelChange; } - pixel.PackFromRgba64(rgbaPixel); + pixel.FromRgba64(rgbaPixel); img[x, y] = pixel; } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 7e942691e9..3dd330e4d3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,14 +31,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); - PixelOperations.Instance.PackFromRgba32Bytes(data, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba32Bytes( + configuration, + data, + resultPixels, + resultPixels.Length); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); - PixelOperations.Instance.PackFromRgba64Bytes(bytes, resultPixels, resultPixels.Length); + PixelOperations.Instance.FromRgba64Bytes( + configuration, + bytes, + resultPixels, + resultPixels.Length); } else { diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index d06f5630f4..7e87c23db5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -33,7 +33,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format32bppArgb) { - throw new ArgumentException($"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From32bppArgbSystemDrawingBitmap)} : pixel format should be {PixelFormat.Format32bppArgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -43,6 +45,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgra32); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -55,7 +58,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.PackFromBgra32(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgra32( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -79,7 +85,9 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs if (bmp.PixelFormat != PixelFormat.Format24bppRgb) { - throw new ArgumentException($"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", nameof(bmp)); + throw new ArgumentException( + $"{nameof(From24bppRgbSystemDrawingBitmap)}: pixel format should be {PixelFormat.Format24bppRgb}!", + nameof(bmp)); } BitmapData data = bmp.LockBits(fullRect, ImageLockMode.ReadWrite, bmp.PixelFormat); @@ -89,6 +97,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs long destRowByteCount = w * sizeof(Bgr24); var image = new Image(w, h); + Configuration configuration = image.GetConfiguration(); using (IMemoryOwner workBuffer = Configuration.Default.MemoryAllocator.Allocate(w)) { @@ -101,7 +110,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs byte* sourcePtr = sourcePtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); - PixelOperations.Instance.PackFromBgr24(workBuffer.GetSpan(), row, row.Length); + PixelOperations.Instance.FromBgr24( + configuration, + workBuffer.GetSpan().Slice(0, w), + row); } } } @@ -112,6 +124,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs internal static unsafe Bitmap To32bppArgbSystemDrawingBitmap(Image image) where TPixel : struct, IPixel { + Configuration configuration = image.GetConfiguration(); int w = image.Width; int h = image.Height; @@ -130,7 +143,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { Span row = image.Frames.RootFrame.GetPixelRowSpan(y); - PixelOperations.Instance.ToBgra32(row, workBuffer.GetSpan(), row.Length); + PixelOperations.Instance.ToBgra32(configuration, row, workBuffer.GetSpan()); byte* destPtr = destPtrBase + (data.Stride * y); Buffer.MemoryCopy(sourcePtr, destPtr, destRowByteCount, sourceRowByteCount); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 0b1b89cc00..e3d8bf3806 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -1,10 +1,24 @@ -using System; +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; using System.Numerics; namespace SixLabors.ImageSharp.Tests { + /// + /// Helper methods that allow the creation of random test data. + /// internal static class TestDataGenerator { + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static float[] GenerateRandomFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; @@ -17,6 +31,14 @@ namespace SixLabors.ImageSharp.Tests return values; } + /// + /// Creates an of the given length consisting of random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . public static Vector4[] GenerateRandomVectorArray(this Random rnd, int length, float minVal, float maxVal) { var values = new Vector4[length]; @@ -33,22 +55,50 @@ namespace SixLabors.ImageSharp.Tests return values; } - public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, int minVal, int maxValExclusive) + /// + /// Creates an of the given length consisting of rounded random values between the two ranges. + /// + /// The pseudo-random number generator. + /// The length. + /// The minimum value. + /// The maximum value. + /// The . + public static float[] GenerateRandomRoundedFloatArray(this Random rnd, int length, float minVal, float maxVal) { float[] values = new float[length]; for (int i = 0; i < length; i++) { - int val = rnd.Next(minVal, maxValExclusive); - values[i] = (float)val; + values[i] = (float)Math.Round(rnd.GetRandomFloat(minVal, maxVal)); } return values; } - private static float GetRandomFloat(Random rnd, float minVal, float maxVal) + /// + /// Creates an of the given length consisting of random values. + /// + /// The pseudo-random number generator. + /// The length. + /// The . + public static byte[] GenerateRandomByteArray(this Random rnd, int length) + { + byte[] values = new byte[length]; + rnd.NextBytes(values); + return values; + } + + public static short[] GenerateRandomInt16Array(this Random rnd, int length, short minVal, short maxVal) { - return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; + short[] values = new short[length]; + for (int i = 0; i < values.Length; i++) + { + values[i] = (short)rnd.Next(minVal, maxVal); + } + + return values; } + + private static float GetRandomFloat(this Random rnd, float minVal, float maxVal) => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal; } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 2384333bfb..29d39596b7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -30,27 +30,29 @@ namespace SixLabors.ImageSharp.Tests { MemoryAllocator memoryAllocator = ctx.MemoryAllocator; - ctx.Apply(img => - { - using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) - { - Span tempSpan = temp.GetSpan(); - foreach (ImageFrame frame in img.Frames) + ctx.Apply( + img => { - Span pixelSpan = frame.GetPixelSpan(); + Configuration configuration = img.GetConfiguration(); + using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) + { + Span tempSpan = temp.GetSpan(); + foreach (ImageFrame frame in img.Frames) + { + Span pixelSpan = frame.GetPixelSpan(); - PixelOperations.Instance.ToScaledVector4(pixelSpan, tempSpan, pixelSpan.Length); + PixelOperations.Instance.ToScaledVector4(configuration, pixelSpan, tempSpan); - for (int i = 0; i < tempSpan.Length; i++) - { - ref Vector4 v = ref tempSpan[i]; - v.W = 1F; - } + for (int i = 0; i < tempSpan.Length; i++) + { + ref Vector4 v = ref tempSpan[i]; + v.W = 1F; + } - PixelOperations.Instance.PackFromScaledVector4(tempSpan, pixelSpan, pixelSpan.Length); - } - } - }); + PixelOperations.Instance.FromScaledVector4(configuration, tempSpan, pixelSpan); + } + } + }); } public static Image DebugSave( @@ -678,7 +680,7 @@ namespace SixLabors.ImageSharp.Tests { float value = bufferSpan[i] * scale; var v = new Vector4(value, value, value, 1f); - pixels[i].PackFromVector4(v); + pixels[i].FromVector4(v); } return image; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index 7ce892edb3..e998ccd3dc 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities public TPixel AsPixel() { TPixel pix = default(TPixel); - pix.PackFromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); + pix.FromVector4(new System.Numerics.Vector4(this.Red, this.Green, this.Blue, this.Alpha)); return pix; } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 5a14f2e26e..5ea0bccf06 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; @@ -80,10 +81,13 @@ namespace SixLabors.ImageSharp.Tests } else { - ca.ToRgb24(ref rgb1); - cb.ToRgb24(ref rgb2); + Rgba32 rgba = default; + ca.ToRgba32(ref rgba); + rgb1 = rgba.Rgb; + cb.ToRgba32(ref rgba); + rgb2 = rgba.Rgb; - if (rgb1.R != rgb2.R || rgb1.G != rgb2.G || rgb1.B != rgb2.B) + if (!rgb1.Equals(rgb2)) { return false; } @@ -94,10 +98,7 @@ namespace SixLabors.ImageSharp.Tests return true; } - public static string ToCsv(this IEnumerable items, string separator = ",") - { - return String.Join(separator, items.Select(o => String.Format(CultureInfo.InvariantCulture, "{0}", o))); - } + public static string ToCsv(this IEnumerable items, string separator = ",") => string.Join(separator, items.Select(o => string.Format(CultureInfo.InvariantCulture, "{0}", o))); public static Type GetClrType(this PixelTypes pixelType) => PixelTypes2ClrTypes[pixelType]; @@ -141,10 +142,7 @@ namespace SixLabors.ImageSharp.Tests internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes)); internal static TPixel GetPixelOfNamedColor(string colorName) - where TPixel : struct, IPixel - { - return (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); - } + where TPixel : struct, IPixel => (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); /// /// Utility for testing image processor extension methods: @@ -287,5 +285,17 @@ namespace SixLabors.ImageSharp.Tests } public static string AsInvariantString(this FormattableString formattable) => System.FormattableString.Invariant(formattable); + + public static IResampler GetResampler(string name) + { + PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); + + if (property is null) + { + throw new Exception($"No resampler named '{name}"); + } + + return (IResampler)property.GetValue(null); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs index 8a3e69059f..30bb16c2a0 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestEnvironmentTests.cs @@ -3,6 +3,8 @@ using System; using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 5305eb2ba3..a8140e39d4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -2,36 +2,26 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.PixelFormats; -using Xunit; -using Xunit.Abstractions; - using System.Collections.Concurrent; using System.IO; - using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests { - using SixLabors.Memory; - public class TestImageProviderTests { - public TestImageProviderTests(ITestOutputHelper output) - { - this.Output = output; - } + public TestImageProviderTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } [Theory] [WithBlankImages(1, 1, PixelTypes.Rgba32)] public void NoOutputSubfolderIsPresentByDefault(TestImageProvider provider) - where TPixel : struct, IPixel - { - Assert.Empty(provider.Utility.OutputSubfolderName); - } + where TPixel : struct, IPixel => Assert.Empty(provider.Utility.OutputSubfolderName); [Theory] [WithBlankImages(42, 666, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.HalfSingle, "hello")] @@ -64,10 +54,7 @@ namespace SixLabors.ImageSharp.Tests [WithBlankImages(1, 1, PixelTypes.Alpha8, PixelTypes.Alpha8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PixelTypes.Argb32)] public void PixelType_PropertyValueIsCorrect(TestImageProvider provider, PixelTypes expected) - where TPixel : struct, IPixel - { - Assert.Equal(expected, provider.PixelType); - } + where TPixel : struct, IPixel => Assert.Equal(expected, provider.PixelType); [Theory] [WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)] @@ -96,7 +83,7 @@ namespace SixLabors.ImageSharp.Tests // Couldn't make xUnit happy without this hackery: - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -160,7 +147,7 @@ namespace SixLabors.ImageSharp.Tests return new Image(42, 42); } - private static ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary invocationCounts = new ConcurrentDictionary(); private string callerName = null; @@ -287,9 +274,8 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(10, img.Width); Assert.Equal(20, img.Height); - var rgba = default(Rgba32); - Buffer2D pixels = img.GetRootFramePixelBuffer(); + Rgba32 rgba = default; for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) @@ -311,10 +297,7 @@ namespace SixLabors.ImageSharp.Tests /// /// public static Image CreateTestImage() - where TPixel : struct, IPixel - { - return new Image(3, 3); - } + where TPixel : struct, IPixel => new Image(3, 3); [Theory] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All)] diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index 655f5b032c..301d0cebe6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests v /= 10; var color = default(TPixel); - color.PackFromVector4(v); + color.FromVector4(v); pixels[i, j] = color; } diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt new file mode 100644 index 0000000000..dc889ab105 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Calliphora.jpg.txt @@ -0,0 +1,331 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Calliphora.jpg] + Filesize: [254766] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 80 + Comment=File source: http://commons.wikimedia.org/wiki/File:Calliphora_sp_Portrait.jpg + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000066 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 10 16 20 24 + DQT, Row #1: 5 5 6 8 10 23 24 22 + DQT, Row #2: 6 5 6 10 16 23 28 22 + DQT, Row #3: 6 7 9 12 20 35 32 25 + DQT, Row #4: 7 9 15 22 27 44 41 31 + DQT, Row #5: 10 14 22 26 32 42 45 37 + DQT, Row #6: 20 26 31 35 41 48 48 40 + DQT, Row #7: 29 37 38 39 45 40 41 40 + Approx quality factor = 79.94 (scaling=40.12 variance=1.43) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000AB + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 10 19 40 40 40 40 + DQT, Row #1: 7 8 10 26 40 40 40 40 + DQT, Row #2: 10 10 22 40 40 40 40 40 + DQT, Row #3: 19 26 40 40 40 40 40 40 + DQT, Row #4: 40 40 40 40 40 40 40 40 + DQT, Row #5: 40 40 40 40 40 40 40 40 + DQT, Row #6: 40 40 40 40 40 40 40 40 + DQT, Row #7: 40 40 40 40 40 40 40 40 + Approx quality factor = 79.87 (scaling=40.26 variance=0.36) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000F0 + Frame header length = 17 + Precision = 8 + Number of Lines = 1198 + Samples per Line = 804 + Image Size = 804 x 1198 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000103 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 01 02 03 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000121 + Huffman table length = 79 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 06 31 + Codes of length 07 bits (004 total): 13 22 41 51 + Codes of length 08 bits (004 total): 14 32 61 71 + Codes of length 09 bits (003 total): 07 81 91 + Codes of length 10 bits (006 total): 15 23 42 52 A1 B1 + Codes of length 11 bits (003 total): 33 62 C1 + Codes of length 12 bits (007 total): 16 24 43 72 82 D1 F0 + Codes of length 13 bits (002 total): 25 E1 + Codes of length 14 bits (003 total): 34 53 92 + Codes of length 15 bits (002 total): A2 F1 + Codes of length 16 bits (015 total): 08 63 B2 26 44 C2 D2 73 27 35 55 74 84 93 A3 + Total number of codes: 060 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000172 + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000018E + Huffman table length = 59 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 03 31 + Codes of length 06 bits (004 total): 12 41 51 F0 + Codes of length 07 bits (003 total): 04 61 71 + Codes of length 08 bits (008 total): 13 22 81 91 A1 B1 C1 D1 + Codes of length 09 bits (002 total): 32 E1 + Codes of length 10 bits (002 total): 42 F1 + Codes of length 11 bits (002 total): 05 23 + Codes of length 12 bits (002 total): 52 62 + Codes of length 13 bits (002 total): 14 33 + Codes of length 14 bits (001 total): 72 + Codes of length 15 bits (004 total): 24 82 92 A2 + Codes of length 16 bits (003 total): 43 B2 E2 + Total number of codes: 040 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000001CB + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000001D9 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0003E32C.0 + + Compression stats: + Compression Ratio: 11.36:1 + Bits per pixel: 2.11:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2628 ( 17%) + # codes of length 03 bits: 10491 ( 69%) + # codes of length 04 bits: 1319 ( 9%) + # codes of length 05 bits: 611 ( 4%) + # codes of length 06 bits: 101 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 23843 ( 79%) + # codes of length 03 bits: 3770 ( 12%) + # codes of length 04 bits: 1945 ( 6%) + # codes of length 05 bits: 653 ( 2%) + # codes of length 06 bits: 89 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 118632 ( 45%) + # codes of length 03 bits: 34447 ( 13%) + # codes of length 04 bits: 57131 ( 22%) + # codes of length 05 bits: 27139 ( 10%) + # codes of length 06 bits: 8648 ( 3%) + # codes of length 07 bits: 9574 ( 4%) + # codes of length 08 bits: 4195 ( 2%) + # codes of length 09 bits: 1503 ( 1%) + # codes of length 10 bits: 1711 ( 1%) + # codes of length 11 bits: 386 ( 0%) + # codes of length 12 bits: 470 ( 0%) + # codes of length 13 bits: 66 ( 0%) + # codes of length 14 bits: 62 ( 0%) + # codes of length 15 bits: 38 ( 0%) + # codes of length 16 bits: 58 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 58553 ( 58%) + # codes of length 03 bits: 21076 ( 21%) + # codes of length 04 bits: 4270 ( 4%) + # codes of length 05 bits: 6075 ( 6%) + # codes of length 06 bits: 6016 ( 6%) + # codes of length 07 bits: 2009 ( 2%) + # codes of length 08 bits: 2750 ( 3%) + # codes of length 09 bits: 429 ( 0%) + # codes of length 10 bits: 213 ( 0%) + # codes of length 11 bits: 91 ( 0%) + # codes of length 12 bits: 44 ( 0%) + # codes of length 13 bits: 22 ( 0%) + # codes of length 14 bits: 5 ( 0%) + # codes of length 15 bits: 9 ( 0%) + # codes of length 16 bits: 3 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[119] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, 0, 0] RGB=[254,254,254] @ MCU[ 35, 37] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0003E32C.0 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0003E32C + + +*** Searching Compression Signatures *** + + Signature: 01DC499064BA9264D591FDE9071DFD89 + Signature (Rotated): 0175BAF3251040E0EFB2930B73328E7F + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + SW :[Apple ImageIO.framework ] [050 (Normal) ] + SW :[IJG Library ] [080 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [080 ] + SW :[IrfanView ] [080 ] + SW :[idImager ] [080 ] + SW :[FastStone Image Viewer ] [080 ] + SW :[NeatImage ] [080 ] + SW :[Paint.NET ] [080 ] + SW :[Photomatix ] [080 ] + SW :[XnView ] [080 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt new file mode 100644 index 0000000000..2c03157afe --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Floorplan.jpg.txt @@ -0,0 +1,266 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Floorplan.jpg] + Filesize: [161577] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 13464 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x000A + [Model ] = "Photosmart Plus B209a-m" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Windows Photo Editor 10.0.10011.16384" + [DateTime ] = "2016:01:02 20:17:37" + [ExifOffset ] = @ 0x091A + Offset to Next IFD = 0x000011B6 + + EXIF IFD1 @ Absolute 0x000011D4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x1214 = @ 0x1232 + [JpegIFByteCount ] = 0x[0000227C] / 8828 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000938 + Dir Length = 0x0008 + [DateTimeOriginal ] = "2016:01:02 19:22:28" + [DateTimeDigitized ] = "2016:01:02 19:22:28" + [SubSecTimeOriginal ] = "00" + [SubSecTimeDigitized ] = "00" + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[00000922] / 2338 + [ExifImageHeight ] = 0x[000008C9] / 2249 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000034AE + Length = 12772 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + |Windows Photo Editor 10.0.10011.163842016-01-02T19:22:28 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00006694 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000066D9 + Frame header length = 11 + Precision = 8 + Number of Lines = 645 + Samples per Line = 976 + Image Size = 976 x 645 + Raw Image Orientation = Landscape + Number of Img components = 1 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000066E6 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006707 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000067BE + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000067C8 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00027727.0 + + Compression stats: + Compression Ratio: 4.66:1 + Bits per pixel: 1.72:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3571 ( 36%) + # codes of length 03 bits: 4320 ( 44%) + # codes of length 04 bits: 925 ( 9%) + # codes of length 05 bits: 456 ( 5%) + # codes of length 06 bits: 313 ( 3%) + # codes of length 07 bits: 291 ( 3%) + # codes of length 08 bits: 6 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 78118 ( 44%) + # codes of length 03 bits: 22349 ( 13%) + # codes of length 04 bits: 35264 ( 20%) + # codes of length 05 bits: 18811 ( 11%) + # codes of length 06 bits: 4312 ( 2%) + # codes of length 07 bits: 8245 ( 5%) + # codes of length 08 bits: 4682 ( 3%) + # codes of length 09 bits: 1584 ( 1%) + # codes of length 10 bits: 1900 ( 1%) + # codes of length 11 bits: 324 ( 0%) + # codes of length 12 bits: 116 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 6 ( 0%) + # codes of length 16 bits: 639 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[231] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 7, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00027726.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00027727 + + +*** Searching Compression Signatures *** + + Signature: 015C645021E37D3469A6B652789383DB + Signature (Rotated): 01D400C125EB43B05762A66347B271F7 + File Offset: 0 bytes + Chroma subsampling: Gray + EXIF Make/Model: OK [???] [Photosmart Plus B209a-m] + EXIF Makernotes: NONE + EXIF Software: OK [Windows Photo Editor 10.0.10011.16384] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [090 Gray ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 Gray ] + SW :[IrfanView ] [090 Gray ] + SW :[idImager ] [090 Gray ] + SW :[FastStone Image Viewer ] [090 Gray ] + SW :[NeatImage ] [090 Gray ] + SW :[Paint.NET ] [090 Gray ] + SW :[Photomatix ] [090 Gray ] + SW :[XnView ] [090 Gray ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt new file mode 100644 index 0000000000..8538e13c86 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Hiyamugi.jpg.txt @@ -0,0 +1,319 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Hiyamugi.jpg] + Filesize: [540458] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.0] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000014 + Length = 65110 + Identifier = [JFXX] + Not known APP0 type. Skipping remainder. + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x0000FE6C + Comment length = 31 + Comment=LEAD Technologies Inc. V1.01. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000FE8D + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 2 2 2 2 2 2 2 + DQT, Row #1: 2 2 2 2 2 2 2 2 + DQT, Row #2: 2 2 2 2 2 2 2 2 + DQT, Row #3: 2 2 2 2 2 3 3 2 + DQT, Row #4: 2 2 2 2 2 4 4 3 + DQT, Row #5: 2 2 2 2 3 4 4 3 + DQT, Row #6: 2 2 3 3 4 4 4 4 + DQT, Row #7: 2 3 3 3 4 4 4 3 + Approx quality factor = 96.75 (scaling=6.50 variance=21.01) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 2 3 3 3 3 + DQT, Row #1: 2 2 2 2 3 3 3 3 + DQT, Row #2: 2 2 2 3 3 3 3 3 + DQT, Row #3: 2 2 3 3 3 3 3 3 + DQT, Row #4: 3 3 3 3 3 3 3 3 + DQT, Row #5: 3 3 3 3 3 3 3 3 + DQT, Row #6: 3 3 3 3 3 3 3 3 + DQT, Row #7: 3 3 3 3 3 3 3 3 + Approx quality factor = 98.06 (scaling=3.88 variance=4.78) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000FF13 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000100B7 + Frame header length = 17 + Precision = 8 + Number of Lines = 794 + Samples per Line = 1123 + Image Size = 1123 x 794 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000100CA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000100D8 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00083F28.0 + + Compression stats: + Compression Ratio: 5.64:1 + Bits per pixel: 4.26:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 727 ( 5%) + # codes of length 03 bits: 7443 ( 52%) + # codes of length 04 bits: 2171 ( 15%) + # codes of length 05 bits: 1627 ( 11%) + # codes of length 06 bits: 1355 ( 10%) + # codes of length 07 bits: 785 ( 6%) + # codes of length 08 bits: 92 ( 1%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2590 ( 36%) + # codes of length 03 bits: 1357 ( 19%) + # codes of length 04 bits: 1187 ( 17%) + # codes of length 05 bits: 856 ( 12%) + # codes of length 06 bits: 616 ( 9%) + # codes of length 07 bits: 346 ( 5%) + # codes of length 08 bits: 109 ( 2%) + # codes of length 09 bits: 39 ( 1%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 223973 ( 44%) + # codes of length 03 bits: 69375 ( 14%) + # codes of length 04 bits: 93550 ( 19%) + # codes of length 05 bits: 58421 ( 12%) + # codes of length 06 bits: 13137 ( 3%) + # codes of length 07 bits: 22630 ( 4%) + # codes of length 08 bits: 9176 ( 2%) + # codes of length 09 bits: 6545 ( 1%) + # codes of length 10 bits: 3947 ( 1%) + # codes of length 11 bits: 1890 ( 0%) + # codes of length 12 bits: 1162 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 77 ( 0%) + # codes of length 16 bits: 1763 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 44319 ( 35%) + # codes of length 03 bits: 21048 ( 17%) + # codes of length 04 bits: 24019 ( 19%) + # codes of length 05 bits: 17303 ( 14%) + # codes of length 06 bits: 9470 ( 7%) + # codes of length 07 bits: 2699 ( 2%) + # codes of length 08 bits: 3432 ( 3%) + # codes of length 09 bits: 2092 ( 2%) + # codes of length 10 bits: 717 ( 1%) + # codes of length 11 bits: 679 ( 1%) + # codes of length 12 bits: 85 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 150 ( 0%) + # codes of length 15 bits: 75 ( 0%) + # codes of length 16 bits: 425 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[117] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 812, 102, -218] RGB=[189,244,250] @ MCU[ 19, 16] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00083F27.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00083F28 + + +*** Searching Compression Signatures *** + + Signature: 0193B6220463E5A621ED25A53EC2FE7D + Signature (Rotated): 010D9693F4FC34B402EFA979BED34733 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[LEAD Technologies Inc ] [002 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt new file mode 100644 index 0000000000..900f52cb78 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Lake.jpg.txt @@ -0,0 +1,683 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Lake.jpg] + Filesize: [206342] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 10392 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Canon" + [Model ] = "Canon EOS DIGITAL REBEL XSi" + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop Camera Raw 9.8 (Windows)" + [DateTime ] = "2016:12:29 12:57:54" + [ExifOffset ] = @ 0x00DE + Offset to Next IFD = 0x000002D6 + + EXIF IFD1 @ Absolute 0x000002E2 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0334 = @ 0x0340 + [JpegIFByteCount ] = 0x[0000255C] / 9564 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000EA + Dir Length = 0x001B + [ExposureTime ] = 1/640 s + [FNumber ] = F8.0 + [ExposureProgram ] = Normal program + [ISOSpeedRatings ] = 200 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2009:07:19 17:00:36" + [DateTimeDigitized ] = "2009:07:19 17:00:36" + [ShutterSpeedValue ] = 9321928/1000000 + [ApertureValue ] = 6/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 4/1 + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 200 mm + [SubSecTimeOriginal ] = "73" + [SubSecTimeDigitized ] = "73" + [ColorSpace ] = Uncalibrated + [FocalPlaneXResolution ] = 4272000/878 + [FocalPlaneYResolution ] = 2848000/584 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000289C + Length = 9752 + Identifier = [Photoshop 3.0] + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 300 pixels per inch + Width unit = inch + Vertical resolution = 300 pixels per inch + Height unit = inch + 8BIM: [0x0404] Name="" Len=[0x003F] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20090719" + IPTC [002:060] Time Created = "170036" + IPTC [002:062] Digital Creation Date = "20090719" + IPTC [002:063] Digital Creation Time = "170036" + 8BIM: [0x040C] Name="" Len=[0x2578] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 256 pixels + Height of thumbnail = 171 pixels + Widthbytes = 768 bytes + Total size = 131328 bytes + Size after compression = 9564 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x0000293E + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x52 C5 4C EC 1E FE 25 B8 CA 88 F7 0D 2B 5F 09 F5 | R.L...%.....+_.. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00004EB6 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000050F8 + Length = 10738 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | + | + | + | + | + | + | + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00007AEC + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00007B72 + Length = 4 + interval = 160 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00007B78 + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00007B88 + Frame header length = 17 + Precision = 8 + Number of Lines = 853 + Samples per Line = 1280 + Image Size = 1280 x 853 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007B9B + Huffman table length = 159 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 03 + Codes of length 03 bits (003 total): 01 02 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 41 + Codes of length 07 bits (003 total): 13 22 51 + Codes of length 08 bits (006 total): 32 61 71 81 91 A1 + Codes of length 09 bits (005 total): 06 14 23 42 B1 + Codes of length 10 bits (002 total): 52 C1 + Codes of length 11 bits (004 total): 15 33 62 D1 + Codes of length 12 bits (004 total): 07 72 E1 F1 + Codes of length 13 bits (005 total): 16 24 43 82 F0 + Codes of length 14 bits (003 total): 34 92 A2 + Codes of length 15 bits (000 total): + Codes of length 16 bits (011 total): 53 63 C2 25 73 B2 D2 26 54 93 E2 + Total number of codes: 054 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 12 21 + Codes of length 07 bits (002 total): 03 31 + Codes of length 08 bits (003 total): 13 41 51 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (000 total): + Codes of length 11 bits (002 total): 04 71 + Codes of length 12 bits (003 total): 14 22 81 + Codes of length 13 bits (001 total): 32 + Codes of length 14 bits (001 total): 42 + Codes of length 15 bits (001 total): 91 + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007C3C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00007C4A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00032604.0 + + Compression stats: + Compression Ratio: 18.77:1 + Bits per pixel: 1.28:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 8237 ( 48%) + # codes of length 03 bits: 7451 ( 44%) + # codes of length 04 bits: 930 ( 5%) + # codes of length 05 bits: 300 ( 2%) + # codes of length 06 bits: 197 ( 1%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 16681 ( 49%) + # codes of length 02 bits: 10125 ( 30%) + # codes of length 03 bits: 5138 ( 15%) + # codes of length 04 bits: 1825 ( 5%) + # codes of length 05 bits: 432 ( 1%) + # codes of length 06 bits: 39 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 104267 ( 49%) + # codes of length 03 bits: 23564 ( 11%) + # codes of length 04 bits: 44372 ( 21%) + # codes of length 05 bits: 19037 ( 9%) + # codes of length 06 bits: 5565 ( 3%) + # codes of length 07 bits: 5437 ( 3%) + # codes of length 08 bits: 5066 ( 2%) + # codes of length 09 bits: 2163 ( 1%) + # codes of length 10 bits: 491 ( 0%) + # codes of length 11 bits: 407 ( 0%) + # codes of length 12 bits: 211 ( 0%) + # codes of length 13 bits: 115 ( 0%) + # codes of length 14 bits: 36 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 26 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 34240 ( 51%) + # codes of length 02 bits: 15658 ( 24%) + # codes of length 03 bits: 7424 ( 11%) + # codes of length 04 bits: 3865 ( 6%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 3125 ( 5%) + # codes of length 07 bits: 1208 ( 2%) + # codes of length 08 bits: 744 ( 1%) + # codes of length 09 bits: 113 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 60 ( 0%) + # codes of length 12 bits: 60 ( 0%) + # codes of length 13 bits: 9 ( 0%) + # codes of length 14 bits: 4 ( 0%) + # codes of length 15 bits: 1 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[122] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 714, -42, 42] RGB=[224,215,206] @ MCU[113, 24] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 106 + Next position in scan buffer: Offset 0x00032604.0 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00032604 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000340 + Length: 0x0000255C (9564) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 171 + Samples per Line = 256 + Image Size = 256 x 171 + + * Embedded Thumb Marker: DHT + Length = 148 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 9212 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01180AF3DE63318828A86409EF4013DD + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS DIGITAL REBEL XSi] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop Camera Raw 9.8 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt new file mode 100644 index 0000000000..cd415a201a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/MultiScanBaselineCMYK.jpg.txt @@ -0,0 +1,282 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\MultiScanBaselineCMYK.jpg] + Filesize: [47443] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00000014 + Length = 14 + DCTEncodeVersion = 25600 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 2 [YCCK] + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000024 + Comment length = 38 + Comment=Created by fCoder Graphics Processor + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000004C + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000091 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000D6 + Frame header length = 20 + Precision = 8 + Number of Lines = 842 + Samples per Line = 595 + Image Size = 595 x 842 + Raw Image Orientation = Portrait + Number of Img components = 4 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cr) + Component[4]: ID=0x04, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000EC + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000010D + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001C4 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001E5 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000029C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00005825 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000766A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A1FA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x04, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B951 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt new file mode 100644 index 0000000000..926da026fd --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/Snake.jpg.txt @@ -0,0 +1,683 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Snake.jpg] + Filesize: [165200] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 11941 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Canon" + [Model ] = "Canon EOS DIGITAL REBEL XSi" + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop Camera Raw 9.8 (Windows)" + [DateTime ] = "2016:12:29 12:57:50" + [ExifOffset ] = @ 0x00DE + Offset to Next IFD = 0x000002D6 + + EXIF IFD1 @ Absolute 0x000002E2 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0334 = @ 0x0340 + [JpegIFByteCount ] = 0x[00002B69] / 11113 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000EA + Dir Length = 0x001B + [ExposureTime ] = 1/25 s + [FNumber ] = F4.0 + [ExposureProgram ] = Shutter priority + [ISOSpeedRatings ] = 250 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2009:07:19 13:25:29" + [DateTimeDigitized ] = "2009:07:19 13:25:29" + [ShutterSpeedValue ] = 4643856/1000000 + [ApertureValue ] = 4/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 4/1 + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 200 mm + [SubSecTimeOriginal ] = "03" + [SubSecTimeDigitized ] = "03" + [ColorSpace ] = Uncalibrated + [FocalPlaneXResolution ] = 4272000/878 + [FocalPlaneYResolution ] = 2848000/584 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00002EA9 + Length = 11302 + Identifier = [Photoshop 3.0] + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 300 pixels per inch + Width unit = inch + Vertical resolution = 300 pixels per inch + Height unit = inch + 8BIM: [0x0404] Name="" Len=[0x003F] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20090719" + IPTC [002:060] Time Created = "132529" + IPTC [002:062] Digital Creation Date = "20090719" + IPTC [002:063] Digital Creation Time = "132529" + 8BIM: [0x040C] Name="" Len=[0x2B85] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 256 pixels + Height of thumbnail = 171 pixels + Widthbytes = 768 bytes + Total size = 131328 bytes + Size after compression = 11113 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x00002F4B + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0xEE 2F A2 47 C5 F8 ED 07 08 CD FF 82 A0 D1 7F F2 | ./.G............ + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00005AD1 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00005D13 + Length = 10733 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | + | + | + | + | + | + | + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | 0, 0 + | 255, 255 + | + | + | + | + | + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00008702 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00008788 + Length = 4 + interval = 160 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000878E + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000879E + Frame header length = 17 + Precision = 8 + Number of Lines = 853 + Samples per Line = 1280 + Image Size = 1280 x 853 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000087B1 + Huffman table length = 153 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 00 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (003 total): 05 12 31 + Codes of length 07 bits (003 total): 13 41 51 + Codes of length 08 bits (003 total): 06 22 61 + Codes of length 09 bits (003 total): 14 32 71 + Codes of length 10 bits (003 total): 42 81 91 + Codes of length 11 bits (003 total): 15 23 A1 + Codes of length 12 bits (004 total): 07 52 B1 C1 + Codes of length 13 bits (001 total): 33 + Codes of length 14 bits (002 total): 24 43 + Codes of length 15 bits (002 total): 62 D1 + Codes of length 16 bits (011 total): 16 34 72 E1 25 53 63 92 82 A2 F0 + Total number of codes: 045 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 03 12 21 + Codes of length 07 bits (001 total): 31 + Codes of length 08 bits (000 total): + Codes of length 09 bits (002 total): 04 41 + Codes of length 10 bits (003 total): 13 22 51 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 32 61 71 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 05 14 42 + Codes of length 15 bits (000 total): + Codes of length 16 bits (003 total): 81 52 62 + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000884C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000885A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0002854E.0 + + Compression stats: + Compression Ratio: 25.14:1 + Bits per pixel: 0.95:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 7183 ( 42%) + # codes of length 03 bits: 7286 ( 43%) + # codes of length 04 bits: 1551 ( 9%) + # codes of length 05 bits: 856 ( 5%) + # codes of length 06 bits: 218 ( 1%) + # codes of length 07 bits: 26 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 12266 ( 36%) + # codes of length 02 bits: 11394 ( 33%) + # codes of length 03 bits: 6548 ( 19%) + # codes of length 04 bits: 2911 ( 9%) + # codes of length 05 bits: 875 ( 3%) + # codes of length 06 bits: 241 ( 1%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 59325 ( 45%) + # codes of length 03 bits: 31160 ( 24%) + # codes of length 04 bits: 18131 ( 14%) + # codes of length 05 bits: 4871 ( 4%) + # codes of length 06 bits: 9522 ( 7%) + # codes of length 07 bits: 4029 ( 3%) + # codes of length 08 bits: 2270 ( 2%) + # codes of length 09 bits: 1006 ( 1%) + # codes of length 10 bits: 515 ( 0%) + # codes of length 11 bits: 268 ( 0%) + # codes of length 12 bits: 195 ( 0%) + # codes of length 13 bits: 24 ( 0%) + # codes of length 14 bits: 29 ( 0%) + # codes of length 15 bits: 20 ( 0%) + # codes of length 16 bits: 26 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 34240 ( 51%) + # codes of length 02 bits: 16000 ( 24%) + # codes of length 03 bits: 5994 ( 9%) + # codes of length 04 bits: 5610 ( 8%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 3610 ( 5%) + # codes of length 07 bits: 600 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 410 ( 1%) + # codes of length 10 bits: 200 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 70 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 17 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 6 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[110] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 954, 14, -14] RGB=[244,248,248] @ MCU[124, 21] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 106 + Next position in scan buffer: Offset 0x0002854D.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0002854E + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000340 + Length: 0x00002B69 (11113) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 171 + Samples per Line = 256 + Image Size = 256 x 171 + + * Embedded Thumb Marker: DHT + Length = 150 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 10759 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01180AF3DE63318828A86409EF4013DD + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS DIGITAL REBEL XSi] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop Camera Raw 9.8 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt new file mode 100644 index 0000000000..97be4853e6 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badeof.jpg.txt @@ -0,0 +1,347 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\badeof.jpg] + Filesize: [5770] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + + Compression stats: + Compression Ratio: 19.73:1 + Bits per pixel: 1.22:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 88 ( 15%) + # codes of length 03 bits: 409 ( 68%) + # codes of length 04 bits: 66 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 134 ( 45%) + # codes of length 03 bits: 68 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2706 ( 48%) + # codes of length 03 bits: 636 ( 11%) + # codes of length 04 bits: 1331 ( 23%) + # codes of length 05 bits: 473 ( 8%) + # codes of length 06 bits: 196 ( 3%) + # codes of length 07 bits: 169 ( 3%) + # codes of length 08 bits: 66 ( 1%) + # codes of length 09 bits: 60 ( 1%) + # codes of length 10 bits: 28 ( 0%) + # codes of length 11 bits: 14 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 5 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 697 ( 46%) + # codes of length 03 bits: 243 ( 16%) + # codes of length 04 bits: 294 ( 19%) + # codes of length 05 bits: 164 ( 11%) + # codes of length 06 bits: 68 ( 4%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 35 ( 2%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 2 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001687.2 + + +*** Skipped 1 marker pad bytes *** +*** Marker: ??? (Unknown) (xFF00) *** + OFFSET: 0x00001689 + WARNING: Unknown marker [0xFF00] + Stopping decode + Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00000000-0x0000168A (5770 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt new file mode 100644 index 0000000000..cb74eb88f5 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/badrst.jpg.txt @@ -0,0 +1,434 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\badrst.jpg] + Filesize: [74497] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 8628 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0003 + [Orientation ] = 1 = Row 0: top, Col 0: left + [ExifOffset ] = @ 0x083E + Offset to Next IFD = 0x000010B6 + + EXIF IFD1 @ Absolute 0x000010D4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x1114 = @ 0x1132 + [JpegIFByteCount ] = 0x[00001097] / 4247 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000085C + Dir Length = 0x0005 + [DateTimeOriginal ] = "2016:02:28 11:17:08" + [DateTimeDigitized ] = "2016:02:28 11:17:08" + [SubSecTimeOriginal ] = "06" + [SubSecTimeDigitized ] = "06" + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000021CA + Length = 2464 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + |2016-02-28T11:17:08.057 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002B6C + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002BB1 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00002BF6 + Frame header length = 17 + Precision = 8 + Number of Lines = 480 + Samples per Line = 640 + Image Size = 640 x 480 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002C09 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002C2A + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CE1 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002D02 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00002DB9 + Length = 4 + interval = 600 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002DBF + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00002DCD + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Expect Restart interval elapsed @ 0x00008802.4 + ERROR: Restart marker not detected +*** ERROR: Can't find huffman bitstring @ 0x00008802.5, table 0, value [0xffffffe0] +*** ERROR: Bad huffman code @ 0x00008802.4 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,0) @ Offset 0x00008802.5 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008802.6, table 0, value [0xffffffc0] +*** ERROR: Bad huffman code @ 0x00008802.5 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,0) @ Offset 0x00008802.6 + MCU located at pixel=(8,240) +*** ERROR: Can't find huffman bitstring @ 0x00008802.7, table 0, value [0xffffff80] +*** ERROR: Bad huffman code @ 0x00008802.6 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(0,1) @ Offset 0x00008802.7 + MCU located at pixel=(0,248) +*** ERROR: Can't find huffman bitstring @ 0x00008803.0, table 0, value [0xffffffff] +*** ERROR: Bad huffman code @ 0x00008802.7 +*** ERROR: Bad scan data in MCU(0,15): Lum CSS(1,1) @ Offset 0x00008803.0 + MCU located at pixel=(8,248) +*** ERROR: Can't find huffman bitstring @ 0x00008803.1, table 1, value [0xfffffffe] +*** ERROR: Bad huffman code @ 0x00008803.0 +*** ERROR: Bad scan data in MCU(0,15): Chr(Cb) CSS(0,0) @ Offset 0x00008803.1 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008803.2, table 1, value [0xfffffffc] +*** ERROR: Bad huffman code @ 0x00008803.1 +*** ERROR: Bad scan data in MCU(0,15): Chr(Cr) CSS(0,0) @ Offset 0x00008803.2 + MCU located at pixel=(0,240) +*** ERROR: Can't find huffman bitstring @ 0x00008803.3, table 0, value [0xfffffff8] +*** ERROR: Bad huffman code @ 0x00008803.2 + Only reported first 20 instances of this message... + + Compression stats: + Compression Ratio: 14.80:1 + Bits per pixel: 1.62:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 40 ( 1%) + # codes of length 02 bits: 202 ( 4%) + # codes of length 03 bits: 3515 ( 73%) + # codes of length 04 bits: 423 ( 9%) + # codes of length 05 bits: 338 ( 7%) + # codes of length 06 bits: 228 ( 5%) + # codes of length 07 bits: 54 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 20 ( 1%) + # codes of length 02 bits: 1657 ( 69%) + # codes of length 03 bits: 311 ( 13%) + # codes of length 04 bits: 232 ( 10%) + # codes of length 05 bits: 123 ( 5%) + # codes of length 06 bits: 49 ( 2%) + # codes of length 07 bits: 8 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 32135 ( 43%) + # codes of length 03 bits: 8668 ( 12%) + # codes of length 04 bits: 15771 ( 21%) + # codes of length 05 bits: 7559 ( 10%) + # codes of length 06 bits: 2518 ( 3%) + # codes of length 07 bits: 3834 ( 5%) + # codes of length 08 bits: 1387 ( 2%) + # codes of length 09 bits: 1122 ( 2%) + # codes of length 10 bits: 562 ( 1%) + # codes of length 11 bits: 234 ( 0%) + # codes of length 12 bits: 131 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 57 ( 0%) + # codes of length 16 bits: 286 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4525 ( 57%) + # codes of length 03 bits: 1153 ( 14%) + # codes of length 04 bits: 1341 ( 17%) + # codes of length 05 bits: 543 ( 7%) + # codes of length 06 bits: 281 ( 4%) + # codes of length 07 bits: 14 ( 0%) + # codes of length 08 bits: 93 ( 1%) + # codes of length 09 bits: 23 ( 0%) + # codes of length 10 bits: 3 ( 0%) + # codes of length 11 bits: 3 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[103] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1014, -3, -27] RGB=[248,255,252] @ MCU[ 0, 13] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 1 + Next position in scan buffer: Offset 0x0001210E.0 + + +*** Skipped 10 marker pad bytes *** +*** Marker: RST# *** + OFFSET: 0x0000880D + WARNING: Restart marker [0xFFD0] detected outside scan + Stopping decode + Use [Img Search Fwd/Rev] to locate other valid embedded JPEGs + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00000000-0x00012301 (74497 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt new file mode 100644 index 0000000000..68777cc049 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/cmyk.jpg.txt @@ -0,0 +1,435 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\cmyk.jpg] + Filesize: [2531270] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00000014 + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 0 [Unknown (RGB or CMYK)] + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000024 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 29 + Profile Size : 1829080 bytes + Preferred CMM Type : 'HDM ' (0x48444D20) + Profile Version : 0.2.4.0 (0x02400000) + Profile Device/Class : Output Device profile ('prtr' (0x70727472)) + Data Colour Space : cmykData ('CMYK' (0x434D594B)) + Profile connection space (PCS) : 'Lab ' (0x4C616220) + Profile creation date : 2007-02-28 08:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : ? (0x00000000) ('....' (0x00000000)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Media-Relative Colorimetric + Profile creator : 'HDM ' (0x48444D20) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000FE1E + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 2 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0001FC18 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 3 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0002FA12 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 4 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0003F80C + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 5 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0004F606 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 6 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0005F400 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 7 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0006F1FA + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 8 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0007EFF4 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 9 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0008EDEE + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 10 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0009EBE8 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 11 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000AE9E2 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 12 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000BE7DC + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 13 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000CE5D6 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 14 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000DE3D0 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 15 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000EE1CA + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 16 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000FDFC4 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 17 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0010DDBE + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 18 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0011DBB8 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 19 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0012D9B2 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 20 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0013D7AC + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 21 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0014D5A6 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 22 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0015D3A0 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 23 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0016D19A + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 24 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0017CF94 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 25 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0018CD8E + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 26 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0019CB88 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 27 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x001AC982 + Length = 65016 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 28 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x001BC77C + Length = 9096 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 29 of 29 + Only support decode of 1st ICC Marker + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x001BEB06 + Length = 188 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x009F] DefinedName="IPTC-NAA record" + IPTC [002:025] Keywords = "jpeg, productbeelden, productie, ptc, ptc369x1, pulsar" + IPTC [002:210] ? = ??? + IPTC [002:211] ? = ??? + IPTC [002:212] ? = ??? + IPTC [002:213] ? = ??? + IPTC [002:214] ? = ??? + IPTC [002:215] ? = ??? + IPTC [002:216] ? = ??? + IPTC [002:217] ? = ??? + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x001BEBC4 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x001BEC09 + Frame header length = 20 + Precision = 8 + Number of Lines = 900 + Samples per Line = 414 + Image Size = 414 x 900 + Raw Image Orientation = Portrait + Number of Img components = 4 + Component[1]: ID=0x43, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x4D, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Cb) + Component[3]: ID=0x59, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Cr) + Component[4]: ID=0x4B, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001BEC1F + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001BEC40 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001BECF7 + Scan header length = 14 + Number of img components = 4 + Component[1]: selector=0x43, table=0(DC),0(AC) + Component[2]: selector=0x4D, table=0(DC),0(AC) + Component[3]: selector=0x59, table=0(DC),0(AC) + Component[4]: selector=0x4B, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00269FC4 + + +*** Searching Compression Signatures *** + + Signature: 01BC2BB6764A7F9709F829E766D93AAE + Signature (Rotated): 01BC2BB6764A7F9709F829E766D93AAE + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [100 Gray ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 Gray ] + SW :[IrfanView ] [100 Gray ] + SW :[idImager ] [100 Gray ] + SW :[FastStone Image Viewer ] [100 Gray ] + SW :[NeatImage ] [100 Gray ] + SW :[Paint.NET ] [100 Gray ] + SW :[Photomatix ] [100 Gray ] + SW :[XnView ] [100 Gray ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt new file mode 100644 index 0000000000..df54994c5e --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/exif.jpg.txt @@ -0,0 +1,454 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\exif.jpg] + Filesize: [32764] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 7678 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0009 + [Make ] = "Canon" + [Model ] = "Canon PowerShot S40" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 180/1 + [YResolution ] = 180/1 + [ResolutionUnit ] = Inch + [DateTime ] = "2003:12:14 12:01:44" + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x00C4 + Offset to Next IFD = 0x000005BE + + EXIF IFD1 @ Absolute 0x000005DC + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 180/1 + [YResolution ] = 180/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x07F4 = @ 0x0812 + [JpegIFByteCount ] = 0x[00001548] / 5448 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000E2 + Dir Length = 0x001F + [ExposureTime ] = 1/500 s + [FNumber ] = F4.9 + [ExifVersion ] = 02.20 + [DateTimeOriginal ] = "2003:12:14 12:01:44" + [DateTimeDigitized ] = "2003:12:14 12:01:44" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 5/1 + [ShutterSpeedValue ] = 287/32 + [ApertureValue ] = 149/32 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 194698/65536 + [MeteringMode ] = CenterWeightedAverage + [Flash ] = Flash did not fire + [FocalLength ] = 21 mm + [MakerNote ] = @ 0x03AE + [UserComment ] = "" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 2272 + [ExifImageHeight ] = 1704 + [ExifInteroperabilityOffset ] = @ 0x0588 + [FocalPlaneXResolution ] = 2272000/280 + [FocalPlaneYResolution ] = 1704000/210 + [FocalPlaneResolutionUnit ] = Inch + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [DigitalZoomRatio ] = 2272/2272 + [SceneCaptureType ] = Standard + + EXIF MakerIFD @ Absolute 0x000003CC + Makernote decode option not enabled. + + EXIF InteropIFD @ Absolute 0x000005A6 + Dir Length = 0x0004 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + [RelatedImageWidth ] = 2272 + [RelatedImageLength ] = 1704 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001E14 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001E59 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00001E9E + Frame header length = 17 + Precision = 8 + Number of Lines = 360 + Samples per Line = 480 + Image Size = 480 x 360 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001EB1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 01 02 04 05 06 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001ECF + Huffman table length = 65 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (002 total): 12 21 + Codes of length 06 bits (004 total): 05 31 41 51 + Codes of length 07 bits (004 total): 13 22 61 71 + Codes of length 08 bits (004 total): 06 32 81 91 + Codes of length 09 bits (004 total): 14 42 A1 B1 + Codes of length 10 bits (004 total): 23 52 C1 D1 + Codes of length 11 bits (005 total): 07 15 33 62 E1 + Codes of length 12 bits (003 total): 43 72 F0 + Codes of length 13 bits (003 total): 24 92 F1 + Codes of length 14 bits (004 total): 16 34 53 82 + Codes of length 15 bits (003 total): 25 83 C2 + Codes of length 16 bits (000 total): + Total number of codes: 046 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001F12 + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001F2E + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (004 total): 04 12 21 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (004 total): 13 22 51 61 + Codes of length 08 bits (002 total): 32 71 + Codes of length 09 bits (002 total): 05 14 + Codes of length 10 bits (002 total): 23 91 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (005 total): 33 42 81 A1 B1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001F5D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00001F6B + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00007FFA.0 + + Compression stats: + Compression Ratio: 20.97:1 + Bits per pixel: 1.14:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 509 ( 18%) + # codes of length 03 bits: 1910 ( 69%) + # codes of length 04 bits: 249 ( 9%) + # codes of length 05 bits: 87 ( 3%) + # codes of length 06 bits: 5 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 905 ( 66%) + # codes of length 03 bits: 213 ( 15%) + # codes of length 04 bits: 169 ( 12%) + # codes of length 05 bits: 84 ( 6%) + # codes of length 06 bits: 9 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 14518 ( 48%) + # codes of length 03 bits: 2881 ( 10%) + # codes of length 04 bits: 6591 ( 22%) + # codes of length 05 bits: 2038 ( 7%) + # codes of length 06 bits: 2356 ( 8%) + # codes of length 07 bits: 926 ( 3%) + # codes of length 08 bits: 484 ( 2%) + # codes of length 09 bits: 220 ( 1%) + # codes of length 10 bits: 149 ( 0%) + # codes of length 11 bits: 76 ( 0%) + # codes of length 12 bits: 27 ( 0%) + # codes of length 13 bits: 14 ( 0%) + # codes of length 14 bits: 8 ( 0%) + # codes of length 15 bits: 3 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2784 ( 53%) + # codes of length 03 bits: 1230 ( 24%) + # codes of length 04 bits: 370 ( 7%) + # codes of length 05 bits: 582 ( 11%) + # codes of length 06 bits: 94 ( 2%) + # codes of length 07 bits: 121 ( 2%) + # codes of length 08 bits: 26 ( 0%) + # codes of length 09 bits: 14 ( 0%) + # codes of length 10 bits: 6 ( 0%) + # codes of length 11 bits: 2 ( 0%) + # codes of length 12 bits: 5 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[122] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, 9, 27] RGB=[255,251,255] @ MCU[ 15, 13] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00007FF9.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00007FFA + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000812 + Length: 0x00001548 (5448) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 9 6 5 9 13 22 29 35 + DQT, Row #1: 6 6 8 11 15 33 34 30 + DQT, Row #2: 8 7 9 13 22 33 39 31 + DQT, Row #3: 8 9 12 16 28 49 45 34 + DQT, Row #4: 10 12 21 32 39 61 58 42 + DQT, Row #5: 13 19 31 36 45 58 63 51 + DQT, Row #6: 28 36 44 49 58 68 66 55 + DQT, Row #7: 41 52 54 55 62 56 57 54 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 9 9 12 20 15 26 79 79 + DQT, Row #1: 9 10 12 10 26 26 79 79 + DQT, Row #2: 12 12 10 10 26 79 79 79 + DQT, Row #3: 20 10 10 26 79 79 79 79 + DQT, Row #4: 15 26 26 79 79 79 79 79 + DQT, Row #5: 26 26 79 79 79 79 79 79 + DQT, Row #6: 79 79 79 79 79 79 79 79 + DQT, Row #7: 79 79 79 79 79 79 79 79 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 120 + Samples per Line = 160 + Image Size = 160 x 120 + + * Embedded Thumb Marker: DHT + Length = 418 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 4869 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01D91E583DD0037108266E42ED3A262C + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Canon] [Canon PowerShot S40] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt new file mode 100644 index 0000000000..a5adb0247c --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/gamma_dalai_lama_gray.jpg.txt @@ -0,0 +1,339 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\gamma_dalai_lama_gray.jpg] + Filesize: [84887] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 46 + Comment= Scaled 1:2 this image wrongly becomes gray. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000044 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000089 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000000CE + Frame header length = 17 + Precision = 8 + Number of Lines = 222 + Samples per Line = 258 + Image Size = 258 x 222 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000E1 + Huffman table length = 25 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 01 02 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000FC + Huffman table length = 111 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (002 total): 05 21 + Codes of length 06 bits (007 total): 00 06 12 13 14 31 41 + Codes of length 07 bits (003 total): 22 51 61 + Codes of length 08 bits (007 total): 07 15 16 32 42 71 81 + Codes of length 09 bits (005 total): 08 23 52 62 91 + Codes of length 10 bits (008 total): 33 43 44 72 A1 A2 B1 E3 + Codes of length 11 bits (010 total): 17 24 53 54 55 66 82 92 95 C1 + Codes of length 12 bits (009 total): 18 25 28 34 45 56 63 64 65 + Codes of length 13 bits (014 total): 26 27 46 73 76 85 93 96 A3 A5 A6 C3 C7 D7 + Codes of length 14 bits (010 total): 83 86 B2 B3 B8 C6 D3 D6 E8 F0 + Codes of length 15 bits (011 total): 36 37 48 74 75 84 94 A8 B4 B6 D1 + Codes of length 16 bits (001 total): D2 + Total number of codes: 092 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000016D + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (001 total): 07 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000018A + Huffman table length = 121 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (002 total): 05 11 + Codes of length 05 bits (002 total): 06 21 + Codes of length 06 bits (005 total): 07 08 12 13 31 + Codes of length 07 bits (009 total): 00 09 14 16 17 22 32 41 51 + Codes of length 08 bits (005 total): 0A 15 23 42 61 + Codes of length 09 bits (005 total): 18 24 33 52 71 + Codes of length 10 bits (002 total): 62 81 + Codes of length 11 bits (007 total): 19 34 43 53 72 82 91 + Codes of length 12 bits (007 total): 25 44 54 56 63 A1 A2 + Codes of length 13 bits (014 total): 1A 26 27 28 46 47 55 57 64 73 97 B1 E3 E6 + Codes of length 14 bits (007 total): 35 45 48 58 92 A4 C1 + Codes of length 15 bits (002 total): D8 29 + Codes of length 16 bits (031 total): 67 74 83 85 93 94 B2 36 68 87 88 98 D6 F0 37 39 + 65 66 75 78 84 96 A3 A6 A8 C3 C9 D1 D3 D9 DA + Total number of codes: 102 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000205 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000213 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00014B95.0 + + Compression stats: + Compression Ratio: 2.04:1 + Bits per pixel: 11.78:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 893 ( 97%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 23 ( 2%) + # codes of length 04 bits: 4 ( 0%) + # codes of length 05 bits: 4 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 1728 ( 94%) + # codes of length 02 bits: 46 ( 2%) + # codes of length 03 bits: 30 ( 2%) + # codes of length 04 bits: 18 ( 1%) + # codes of length 05 bits: 14 ( 1%) + # codes of length 06 bits: 6 ( 0%) + # codes of length 07 bits: 4 ( 0%) + # codes of length 08 bits: 2 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 14381 ( 45%) + # codes of length 03 bits: 3819 ( 12%) + # codes of length 04 bits: 4489 ( 14%) + # codes of length 05 bits: 2199 ( 7%) + # codes of length 06 bits: 3836 ( 12%) + # codes of length 07 bits: 911 ( 3%) + # codes of length 08 bits: 1089 ( 3%) + # codes of length 09 bits: 398 ( 1%) + # codes of length 10 bits: 294 ( 1%) + # codes of length 11 bits: 190 ( 1%) + # codes of length 12 bits: 84 ( 0%) + # codes of length 13 bits: 75 ( 0%) + # codes of length 14 bits: 21 ( 0%) + # codes of length 15 bits: 11 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 17100 ( 23%) + # codes of length 03 bits: 31709 ( 42%) + # codes of length 04 bits: 7638 ( 10%) + # codes of length 05 bits: 4203 ( 6%) + # codes of length 06 bits: 6465 ( 9%) + # codes of length 07 bits: 5462 ( 7%) + # codes of length 08 bits: 1472 ( 2%) + # codes of length 09 bits: 804 ( 1%) + # codes of length 10 bits: 206 ( 0%) + # codes of length 11 bits: 296 ( 0%) + # codes of length 12 bits: 156 ( 0%) + # codes of length 13 bits: 164 ( 0%) + # codes of length 14 bits: 47 ( 0%) + # codes of length 15 bits: 7 ( 0%) + # codes of length 16 bits: 55 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[125] (range: 0..255) + + Brightest Pixel Search: + YCC=[ -8, 0, 0] RGB=[127,127,127] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00014B94.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00014B95 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] No + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] No + CAM:[SIGMA ] [SIGMA SD9 ] [ ] No + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt new file mode 100644 index 0000000000..b686b3ce39 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg400jfif.jpg.txt @@ -0,0 +1,211 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg400jfif.jpg] + Filesize: [45066] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000059 + Frame header length = 11 + Precision = 8 + Number of Lines = 800 + Samples per Line = 600 + Image Size = 600 x 800 + Raw Image Orientation = Portrait + Number of Img components = 1 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00000066 + Length = 4 + interval = 75 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000006C + Huffman table length = 210 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000140 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000014A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000B008.0 + + Compression stats: + Compression Ratio: 10.73:1 + Bits per pixel: 0.75:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 7215 ( 96%) + # codes of length 04 bits: 146 ( 2%) + # codes of length 05 bits: 139 ( 2%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 26194 ( 42%) + # codes of length 03 bits: 2772 ( 4%) + # codes of length 04 bits: 16626 ( 27%) + # codes of length 05 bits: 5914 ( 9%) + # codes of length 06 bits: 4996 ( 8%) + # codes of length 07 bits: 2599 ( 4%) + # codes of length 08 bits: 988 ( 2%) + # codes of length 09 bits: 1360 ( 2%) + # codes of length 10 bits: 617 ( 1%) + # codes of length 11 bits: 60 ( 0%) + # codes of length 12 bits: 152 ( 0%) + # codes of length 13 bits: 60 ( 0%) + # codes of length 14 bits: 30 ( 0%) + # codes of length 15 bits: 5 ( 0%) + # codes of length 16 bits: 28 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 58] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 894, 0, 0] RGB=[239,239,239] @ MCU[ 35, 23] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 99 + Next position in scan buffer: Offset 0x0000B007.2 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B008 + + +*** Searching Compression Signatures *** + + Signature: 01BE82BEB1019CB30EB122273E78E87C + Signature (Rotated): 01BE82BEB1019CB30EB122273E78E87C + File Offset: 0 bytes + Chroma subsampling: Gray + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt new file mode 100644 index 0000000000..babe797d6a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420exif.jpg.txt @@ -0,0 +1,412 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg420exif.jpg] + Filesize: [768608] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 8817 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0008 + [Make ] = "Hewlett-Packard Company" + [Model ] = "HP PhotoSmart 715" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x006E + Offset to Next IFD = 0x0000018E + + EXIF IFD1 @ Absolute 0x0000019A + Dir Length = 0x0007 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0C07 = @ 0x0C13 + [JpegIFByteCount ] = 0x[00001658] / 5720 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000007A + Dir Length = 0x0015 + [ExposureTime ] = 48/10000 s + [FNumber ] = F8.2 + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.10 + [DateTimeOriginal ] = "2001:10:02 14:57:31" + [DateTimeDigitized ] = "2001:10:02 14:57:31" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 20/10 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 20/10 + [SubjectDistance ] = 5043/1000 + [MeteringMode ] = CenterWeightedAverage + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 7 mm + [MakerNote ] = @ 0x0282 + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 2048 + [ExifImageHeight ] = 1536 + [ExifInteroperabilityOffset ] = @ 0x0170 + + EXIF MakerIFD @ Absolute 0x0000028E + Makernote decode option not enabled. + + EXIF InteropIFD @ Absolute 0x0000017C + Dir Length = 0x0002 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002275 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 9 11 14 + DQT, Row #1: 3 3 3 4 5 12 13 12 + DQT, Row #2: 3 3 3 5 9 12 15 12 + DQT, Row #3: 3 3 5 6 11 19 18 13 + DQT, Row #4: 3 5 7 12 15 24 23 17 + DQT, Row #5: 5 7 12 14 18 23 25 21 + DQT, Row #6: 11 14 17 19 23 27 27 22 + DQT, Row #7: 16 21 21 22 25 22 23 22 + Approx quality factor = 89.24 (scaling=21.52 variance=2.21) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 5 10 22 22 22 22 + DQT, Row #1: 3 5 5 14 22 22 22 22 + DQT, Row #2: 5 5 11 22 22 22 22 22 + DQT, Row #3: 10 14 22 22 22 22 22 22 + DQT, Row #4: 22 22 22 22 22 22 22 22 + DQT, Row #5: 22 22 22 22 22 22 22 22 + DQT, Row #6: 22 22 22 22 22 22 22 22 + DQT, Row #7: 22 22 22 22 22 22 22 22 + Approx quality factor = 89.12 (scaling=21.76 variance=1.62) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000022FB + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000249F + Frame header length = 17 + Precision = 8 + Number of Lines = 1536 + Samples per Line = 2048 + Image Size = 2048 x 1536 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000024B2 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000024C0 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x000BBA5E.0 + + Compression stats: + Compression Ratio: 12.43:1 + Bits per pixel: 1.93:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4275 ( 9%) + # codes of length 03 bits: 32688 ( 67%) + # codes of length 04 bits: 5786 ( 12%) + # codes of length 05 bits: 3984 ( 8%) + # codes of length 06 bits: 2042 ( 4%) + # codes of length 07 bits: 377 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 16194 ( 66%) + # codes of length 03 bits: 3495 ( 14%) + # codes of length 04 bits: 2416 ( 10%) + # codes of length 05 bits: 1460 ( 6%) + # codes of length 06 bits: 736 ( 3%) + # codes of length 07 bits: 261 ( 1%) + # codes of length 08 bits: 14 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 363342 ( 41%) + # codes of length 03 bits: 113855 ( 13%) + # codes of length 04 bits: 200569 ( 23%) + # codes of length 05 bits: 102577 ( 12%) + # codes of length 06 bits: 32874 ( 4%) + # codes of length 07 bits: 43593 ( 5%) + # codes of length 08 bits: 14054 ( 2%) + # codes of length 09 bits: 8847 ( 1%) + # codes of length 10 bits: 4365 ( 0%) + # codes of length 11 bits: 2009 ( 0%) + # codes of length 12 bits: 770 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 17 ( 0%) + # codes of length 16 bits: 780 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 60258 ( 49%) + # codes of length 03 bits: 17570 ( 14%) + # codes of length 04 bits: 20881 ( 17%) + # codes of length 05 bits: 14001 ( 11%) + # codes of length 06 bits: 6443 ( 5%) + # codes of length 07 bits: 842 ( 1%) + # codes of length 08 bits: 1737 ( 1%) + # codes of length 09 bits: 387 ( 0%) + # codes of length 10 bits: 169 ( 0%) + # codes of length 11 bits: 93 ( 0%) + # codes of length 12 bits: 31 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 5 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[108] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 996, 0, -33] RGB=[244,255,252] @ MCU[ 32, 59] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x000BBA5D.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000BBA5E + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000C13 + Length: 0x00001658 (5720) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 10 6 6 10 14 26 32 40 + DQT, Row #1: 8 8 8 12 16 36 38 36 + DQT, Row #2: 8 8 10 14 26 36 44 36 + DQT, Row #3: 8 10 14 18 32 56 52 40 + DQT, Row #4: 10 14 22 36 44 70 66 50 + DQT, Row #5: 14 22 36 42 52 68 74 60 + DQT, Row #6: 32 42 50 56 66 78 78 64 + DQT, Row #7: 46 60 62 64 74 64 66 64 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 10 10 14 30 64 64 64 64 + DQT, Row #1: 10 14 16 42 64 64 64 64 + DQT, Row #2: 14 16 36 64 64 64 64 64 + DQT, Row #3: 30 42 64 64 64 64 64 64 + DQT, Row #4: 64 64 64 64 64 64 64 64 + DQT, Row #5: 64 64 64 64 64 64 64 64 + DQT, Row #6: 64 64 64 64 64 64 64 64 + DQT, Row #7: 64 64 64 64 64 64 64 64 + + * Embedded Thumb Marker: DHT + Length = 418 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 120 + Samples per Line = 160 + Image Size = 160 x 120 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 5141 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 0158E595F22440126FB766B33F56B158 + +*** Searching Compression Signatures *** + + Signature: 010A5B03EB73D6AF719B39FCC8C3AE25 + Signature (Rotated): 011326BE69D2A27FCF4DBCC33DEB07A2 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Hewlett-Packard Company] [HP PhotoSmart 715] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt new file mode 100644 index 0000000000..c001d7297a --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg420small.jpg.txt @@ -0,0 +1,330 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg420small.jpg] + Filesize: [5276] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 96 x 96 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 100 + Samples per Line = 200 + Image Size = 200 x 100 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 02 03 05 07 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 66 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 11 21 + Codes of length 05 bits (002 total): 04 12 + Codes of length 06 bits (004 total): 05 06 31 41 + Codes of length 07 bits (004 total): 07 13 22 51 + Codes of length 08 bits (002 total): 32 61 + Codes of length 09 bits (005 total): 71 72 B1 D1 D2 + Codes of length 10 bits (007 total): 14 23 33 62 81 91 A1 + Codes of length 11 bits (010 total): 15 16 24 25 34 42 44 82 92 A2 + Codes of length 12 bits (007 total): 26 52 53 54 64 94 C2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 047 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000113 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 06 07 + Codes of length 03 bits (002 total): 04 05 + Codes of length 04 bits (003 total): 00 03 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 02 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000131 + Huffman table length = 63 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 02 + Codes of length 04 bits (002 total): 03 04 + Codes of length 05 bits (004 total): 05 06 11 21 + Codes of length 06 bits (007 total): 07 12 34 51 61 72 B1 + Codes of length 07 bits (014 total): 13 15 16 17 31 32 33 35 41 53 71 91 92 D1 + Codes of length 08 bits (004 total): 22 62 C1 E1 + Codes of length 09 bits (006 total): 14 52 54 81 82 B2 + Codes of length 10 bits (003 total): 36 42 C2 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 044 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000172 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000180 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000149A.0 + + Compression stats: + Compression Ratio: 12.27:1 + Bits per pixel: 1.96:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 69 ( 19%) + # codes of length 03 bits: 232 ( 64%) + # codes of length 04 bits: 34 ( 9%) + # codes of length 05 bits: 19 ( 5%) + # codes of length 06 bits: 10 ( 3%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 76 ( 42%) + # codes of length 03 bits: 60 ( 33%) + # codes of length 04 bits: 36 ( 20%) + # codes of length 05 bits: 5 ( 3%) + # codes of length 06 bits: 5 ( 3%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2698 ( 51%) + # codes of length 03 bits: 506 ( 10%) + # codes of length 04 bits: 1064 ( 20%) + # codes of length 05 bits: 373 ( 7%) + # codes of length 06 bits: 334 ( 6%) + # codes of length 07 bits: 133 ( 3%) + # codes of length 08 bits: 37 ( 1%) + # codes of length 09 bits: 43 ( 1%) + # codes of length 10 bits: 33 ( 1%) + # codes of length 11 bits: 26 ( 0%) + # codes of length 12 bits: 7 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 276 ( 20%) + # codes of length 03 bits: 340 ( 25%) + # codes of length 04 bits: 214 ( 15%) + # codes of length 05 bits: 190 ( 14%) + # codes of length 06 bits: 141 ( 10%) + # codes of length 07 bits: 170 ( 12%) + # codes of length 08 bits: 29 ( 2%) + # codes of length 09 bits: 17 ( 1%) + # codes of length 10 bits: 6 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 86] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 250, -405, 230] RGB=[198,156, 68] @ MCU[ 0, 6] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001499.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000149A + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt new file mode 100644 index 0000000000..06a1ee4263 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/jpeg444.jpg.txt @@ -0,0 +1,405 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\jpeg444.jpg] + Filesize: [5667] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.0] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] +Identifier [This is an unknown APP marker. Compliant decoders must ignore it.] not supported. Skipping remainder. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000005A + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not supported. Skipping remainder. + +*** Marker: APP3 (xFFE3) *** + OFFSET: 0x000000A0 + Length = 68 + +*** Marker: APP4 (xFFE4) *** + OFFSET: 0x000000E6 + Length = 68 + +*** Marker: APP5 (xFFE5) *** + OFFSET: 0x0000012C + Length = 68 + +*** Marker: APP6 (xFFE6) *** + OFFSET: 0x00000172 + Length = 68 + +*** Marker: APP7 (xFFE7) *** + OFFSET: 0x000001B8 + Length = 68 + +*** Marker: APP8 (xFFE8) *** + OFFSET: 0x000001FE + Length = 68 + +*** Marker: APP9 (xFFE9) *** + OFFSET: 0x00000244 + Length = 68 + +*** Marker: APP10 (xFFEA) *** + OFFSET: 0x0000028A + Length = 68 + +*** Marker: APP11 (xFFEB) *** + OFFSET: 0x000002D0 + Length = 68 + +*** Marker: APP12 (xFFEC) *** + OFFSET: 0x00000316 + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not Photoshop DUCKY. Skipping remainder. + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000035C + Length = 68 + Identifier = [This is an unknown APP marker. Compliant decoders must ignore it.] + Not Photoshop. Skipping remainder. + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x000003A2 + Length = 68 + DCTEncodeVersion = 26995 + APP14Flags0 = 8289 + APP14Flags1 = 28192 + ColorTransform = 117 [???] + +*** Marker: APP15 (xFFEF) *** + OFFSET: 0x000003E8 + Length = 68 + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000042E + Frame header length = 17 + Precision = 8 + Number of Lines = 256 + Samples per Line = 256 + Image Size = 256 x 256 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x02 (Chrom: Cr) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000441 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000486 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000004CB + Table length = 67 + ---- + Precision=8 bits + Destination ID=2 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000510 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000006B4 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000006C2 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001620.0 + + Compression stats: + Compression Ratio: 49.99:1 + Bits per pixel: 0.48:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 992 ( 97%) + # codes of length 03 bits: 31 ( 3%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1023 ( 50%) + # codes of length 03 bits: 864 ( 42%) + # codes of length 04 bits: 128 ( 6%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 2 ( 0%) + # codes of length 08 bits: 31 ( 2%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 0 ( 0%) + # codes of length 04 bits: 1024 ( 50%) + # codes of length 05 bits: 1024 ( 50%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2048 ( 67%) + # codes of length 03 bits: 1024 ( 33%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[126] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 984,-1026, -999] RGB=[ 75,255, 24] @ MCU[ 0, 31] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000161F.6 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001620 + + +*** Searching Compression Signatures *** + + Signature: 019DC7724B5425C464D28F2CF78F707E + Signature (Rotated): 016C4383FFABE35F063D8FCB331942C0 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E4800 ] [NORMAL ] No + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + + +*** Additional Info *** +NOTE: Data exists after EOF, range: 0x00001622-0x00001623 (1 bytes) diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt new file mode 100644 index 0000000000..b2ae24c469 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ratio-1x1.jpg.txt @@ -0,0 +1,338 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ratio-1x1.jpg] + Filesize: [34674] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 4 6 8 10 + DQT, Row #1: 2 2 2 3 4 9 10 9 + DQT, Row #2: 2 2 3 4 6 9 11 9 + DQT, Row #3: 2 3 4 5 8 14 13 10 + DQT, Row #4: 3 4 6 9 11 17 16 12 + DQT, Row #5: 4 6 9 10 13 17 18 15 + DQT, Row #6: 8 10 12 14 16 19 19 16 + DQT, Row #7: 12 15 15 16 18 16 16 16 + Approx quality factor = 91.86 (scaling=16.28 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 4 8 16 16 16 16 + DQT, Row #1: 3 3 4 11 16 16 16 16 + DQT, Row #2: 4 4 9 16 16 16 16 16 + DQT, Row #3: 8 11 16 16 16 16 16 16 + DQT, Row #4: 16 16 16 16 16 16 16 16 + DQT, Row #5: 16 16 16 16 16 16 16 16 + DQT, Row #6: 16 16 16 16 16 16 16 16 + DQT, Row #7: 16 16 16 16 16 16 16 16 + Approx quality factor = 91.90 (scaling=16.20 variance=0.15) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 769 + Samples per Line = 1900 + Image Size = 1900 x 769 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 07 08 + Codes of length 04 bits (002 total): 06 09 + Codes of length 05 bits (002 total): 04 05 + Codes of length 06 bits (003 total): 01 02 03 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D0 + Huffman table length = 78 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (003 total): 02 03 04 + Codes of length 05 bits (003 total): 05 06 11 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (005 total): 08 12 21 31 41 + Codes of length 08 bits (005 total): 13 14 22 51 61 + Codes of length 09 bits (003 total): 15 32 71 + Codes of length 10 bits (009 total): 09 16 23 52 62 81 91 92 A1 + Codes of length 11 bits (005 total): 17 33 42 72 82 + Codes of length 12 bits (005 total): 24 43 54 93 B3 + Codes of length 13 bits (006 total): 63 73 83 A2 B2 C2 + Codes of length 14 bits (003 total): 25 44 A3 + Codes of length 15 bits (009 total): 34 35 36 37 64 76 B1 B4 C1 + Codes of length 16 bits (000 total): + Total number of codes: 059 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000120 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 05 06 07 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 02 03 08 + Codes of length 07 bits (001 total): 01 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000013E + Huffman table length = 64 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (002 total): 02 03 + Codes of length 05 bits (003 total): 04 05 11 + Codes of length 06 bits (005 total): 06 21 31 71 81 + Codes of length 07 bits (003 total): 41 51 91 + Codes of length 08 bits (010 total): 12 13 14 22 32 61 A1 B1 C1 D1 + Codes of length 09 bits (005 total): 15 33 42 E1 F0 + Codes of length 10 bits (003 total): 07 23 52 + Codes of length 11 bits (004 total): 43 62 72 82 + Codes of length 12 bits (002 total): 92 F1 + Codes of length 13 bits (001 total): B2 + Codes of length 14 bits (005 total): 16 A2 C2 D2 E2 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 045 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000180 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000018E + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00008770.0 + + Compression stats: + Compression Ratio: 127.89:1 + Bits per pixel: 0.19:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 22539 ( 97%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 379 ( 2%) + # codes of length 04 bits: 246 ( 1%) + # codes of length 05 bits: 91 ( 0%) + # codes of length 06 bits: 69 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 11012 ( 94%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 445 ( 4%) + # codes of length 04 bits: 105 ( 1%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 81 ( 1%) + # codes of length 07 bits: 19 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 23301 ( 56%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 4265 ( 10%) + # codes of length 04 bits: 7407 ( 18%) + # codes of length 05 bits: 3364 ( 8%) + # codes of length 06 bits: 767 ( 2%) + # codes of length 07 bits: 1399 ( 3%) + # codes of length 08 bits: 642 ( 2%) + # codes of length 09 bits: 201 ( 0%) + # codes of length 10 bits: 285 ( 1%) + # codes of length 11 bits: 99 ( 0%) + # codes of length 12 bits: 42 ( 0%) + # codes of length 13 bits: 30 ( 0%) + # codes of length 14 bits: 6 ( 0%) + # codes of length 15 bits: 9 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 11662 ( 60%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 1971 ( 10%) + # codes of length 04 bits: 1938 ( 10%) + # codes of length 05 bits: 1525 ( 8%) + # codes of length 06 bits: 1005 ( 5%) + # codes of length 07 bits: 339 ( 2%) + # codes of length 08 bits: 727 ( 4%) + # codes of length 09 bits: 148 ( 1%) + # codes of length 10 bits: 41 ( 0%) + # codes of length 11 bits: 23 ( 0%) + # codes of length 12 bits: 8 ( 0%) + # codes of length 13 bits: 2 ( 0%) + # codes of length 14 bits: 5 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[250] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 0, 0] RGB=[255,255,255] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000876F.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00008770 + + +*** Searching Compression Signatures *** + + Signature: 01557A9AE226A38386271DFE13D64298 + Signature (Rotated): 0167FCEDBA3A8E8CF822163DB3564762 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Konica Minolta Camera, In] [DiMAGE Z2 ] [ ] No + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[IJG Library ] [092 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [092 ] + SW :[IrfanView ] [092 ] + SW :[idImager ] [092 ] + SW :[FastStone Image Viewer ] [092 ] + SW :[NeatImage ] [092 ] + SW :[Paint.NET ] [092 ] + SW :[Photomatix ] [092 ] + SW :[XnView ] [092 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt new file mode 100644 index 0000000000..ac2b2f9adb --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testimgint.jpg.txt @@ -0,0 +1,342 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\testimgint.jpg] + Filesize: [5756] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000167A.0 + + Compression stats: + Compression Ratio: 19.78:1 + Bits per pixel: 1.21:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 86 ( 14%) + # codes of length 03 bits: 412 ( 69%) + # codes of length 04 bits: 65 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 132 ( 44%) + # codes of length 03 bits: 70 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2692 ( 48%) + # codes of length 03 bits: 628 ( 11%) + # codes of length 04 bits: 1327 ( 23%) + # codes of length 05 bits: 471 ( 8%) + # codes of length 06 bits: 199 ( 4%) + # codes of length 07 bits: 170 ( 3%) + # codes of length 08 bits: 65 ( 1%) + # codes of length 09 bits: 58 ( 1%) + # codes of length 10 bits: 31 ( 1%) + # codes of length 11 bits: 15 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 6 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 689 ( 46%) + # codes of length 03 bits: 244 ( 16%) + # codes of length 04 bits: 289 ( 19%) + # codes of length 05 bits: 158 ( 11%) + # codes of length 06 bits: 70 ( 5%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 36 ( 2%) + # codes of length 09 bits: 5 ( 0%) + # codes of length 10 bits: 1 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001679.6 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000167A + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt new file mode 100644 index 0000000000..8e339260ba --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/testorig.jpg.txt @@ -0,0 +1,342 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\testorig.jpg] + Filesize: [5770] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 149 + Samples per Line = 227 + Image Size = 227 x 149 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D2 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000189 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000001AA + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000261 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000026F + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001688.0 + + Compression stats: + Compression Ratio: 19.73:1 + Bits per pixel: 1.22:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 88 ( 15%) + # codes of length 03 bits: 409 ( 68%) + # codes of length 04 bits: 66 ( 11%) + # codes of length 05 bits: 33 ( 6%) + # codes of length 06 bits: 4 ( 1%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 134 ( 45%) + # codes of length 03 bits: 68 ( 23%) + # codes of length 04 bits: 60 ( 20%) + # codes of length 05 bits: 26 ( 9%) + # codes of length 06 bits: 12 ( 4%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2706 ( 48%) + # codes of length 03 bits: 636 ( 11%) + # codes of length 04 bits: 1331 ( 23%) + # codes of length 05 bits: 473 ( 8%) + # codes of length 06 bits: 196 ( 3%) + # codes of length 07 bits: 169 ( 3%) + # codes of length 08 bits: 66 ( 1%) + # codes of length 09 bits: 60 ( 1%) + # codes of length 10 bits: 28 ( 0%) + # codes of length 11 bits: 14 ( 0%) + # codes of length 12 bits: 4 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 5 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 697 ( 46%) + # codes of length 03 bits: 243 ( 16%) + # codes of length 04 bits: 294 ( 19%) + # codes of length 05 bits: 164 ( 11%) + # codes of length 06 bits: 68 ( 4%) + # codes of length 07 bits: 5 ( 0%) + # codes of length 08 bits: 35 ( 2%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 2 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[107] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1008, -9, 0] RGB=[254,254,250] @ MCU[ 4, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001687.2 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001688 + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt new file mode 100644 index 0000000000..a8231b19e6 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/turtle.jpg.txt @@ -0,0 +1,367 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\turtle.jpg] + Filesize: [55126] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 28 x 28 DPcm (dots per cm) + thumbnail = 0 x 0 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000014 + Length = 3256 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3240 bytes + Preferred CMM Type : 'appl' (0x6170706C) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-05-11 16:46:50 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'appl' (0x6170706C) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000CCE + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 4 6 8 10 + DQT, Row #1: 2 2 2 3 4 9 10 9 + DQT, Row #2: 2 2 3 4 6 9 11 9 + DQT, Row #3: 2 3 4 5 8 14 13 10 + DQT, Row #4: 3 4 6 9 11 17 16 12 + DQT, Row #5: 4 6 9 10 13 17 18 15 + DQT, Row #6: 8 10 12 14 16 19 19 16 + DQT, Row #7: 12 15 15 16 18 16 16 16 + Approx quality factor = 91.86 (scaling=16.28 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000D13 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 3 4 8 16 16 16 16 + DQT, Row #1: 3 3 4 11 16 16 16 16 + DQT, Row #2: 4 4 9 16 16 16 16 16 + DQT, Row #3: 8 11 16 16 16 16 16 16 + DQT, Row #4: 16 16 16 16 16 16 16 16 + DQT, Row #5: 16 16 16 16 16 16 16 16 + DQT, Row #6: 16 16 16 16 16 16 16 16 + DQT, Row #7: 16 16 16 16 16 16 16 16 + Approx quality factor = 91.90 (scaling=16.20 variance=0.15) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000D58 + Frame header length = 17 + Precision = 8 + Number of Lines = 281 + Samples per Line = 450 + Image Size = 450 x 281 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D6B + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 06 + Codes of length 03 bits (004 total): 00 04 05 07 + Codes of length 04 bits (003 total): 01 03 08 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D8A + Huffman table length = 82 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (003 total): 05 06 11 + Codes of length 05 bits (002 total): 00 12 + Codes of length 06 bits (004 total): 07 13 21 31 + Codes of length 07 bits (003 total): 22 41 51 + Codes of length 08 bits (004 total): 08 14 61 71 + Codes of length 09 bits (006 total): 15 23 32 81 91 A1 + Codes of length 10 bits (007 total): 16 42 52 55 94 B1 D2 + Codes of length 11 bits (004 total): 33 62 72 C1 + Codes of length 12 bits (007 total): 24 34 82 92 A2 D1 F0 + Codes of length 13 bits (005 total): 17 43 53 54 E1 + Codes of length 14 bits (006 total): 09 25 35 83 93 B2 + Codes of length 15 bits (007 total): 18 26 44 64 73 A3 C2 + Codes of length 16 bits (001 total): A4 + Total number of codes: 063 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000DDE + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 04 05 06 07 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000DFC + Huffman table length = 76 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (004 total): 00 03 04 21 + Codes of length 05 bits (003 total): 05 12 31 + Codes of length 06 bits (004 total): 06 41 51 61 + Codes of length 07 bits (006 total): 13 22 71 81 91 A1 + Codes of length 08 bits (006 total): 07 14 32 52 B1 D1 + Codes of length 09 bits (007 total): 15 42 53 62 72 92 C1 + Codes of length 10 bits (005 total): 23 33 A2 E1 F0 + Codes of length 11 bits (005 total): 16 17 34 82 B2 + Codes of length 12 bits (007 total): 24 35 54 63 73 D2 F1 + Codes of length 13 bits (004 total): 08 25 93 C2 + Codes of length 14 bits (003 total): 43 C3 D3 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 057 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E4A + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000E58 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0000D754.0 + + Compression stats: + Compression Ratio: 7.37:1 + Bits per pixel: 3.26:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 344 ( 16%) + # codes of length 03 bits: 1157 ( 55%) + # codes of length 04 bits: 453 ( 22%) + # codes of length 05 bits: 102 ( 5%) + # codes of length 06 bits: 32 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 216 ( 21%) + # codes of length 03 bits: 672 ( 64%) + # codes of length 04 bits: 77 ( 7%) + # codes of length 05 bits: 59 ( 6%) + # codes of length 06 bits: 20 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 11146 ( 23%) + # codes of length 03 bits: 21025 ( 43%) + # codes of length 04 bits: 8376 ( 17%) + # codes of length 05 bits: 3259 ( 7%) + # codes of length 06 bits: 2911 ( 6%) + # codes of length 07 bits: 840 ( 2%) + # codes of length 08 bits: 696 ( 1%) + # codes of length 09 bits: 499 ( 1%) + # codes of length 10 bits: 295 ( 1%) + # codes of length 11 bits: 93 ( 0%) + # codes of length 12 bits: 85 ( 0%) + # codes of length 13 bits: 26 ( 0%) + # codes of length 14 bits: 15 ( 0%) + # codes of length 15 bits: 8 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 5260 ( 31%) + # codes of length 03 bits: 4077 ( 24%) + # codes of length 04 bits: 4031 ( 24%) + # codes of length 05 bits: 1544 ( 9%) + # codes of length 06 bits: 912 ( 5%) + # codes of length 07 bits: 626 ( 4%) + # codes of length 08 bits: 335 ( 2%) + # codes of length 09 bits: 163 ( 1%) + # codes of length 10 bits: 58 ( 0%) + # codes of length 11 bits: 27 ( 0%) + # codes of length 12 bits: 18 ( 0%) + # codes of length 13 bits: 6 ( 0%) + # codes of length 14 bits: 3 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[167] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1017, 3, -3] RGB=[253,255,255] @ MCU[ 26, 8] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0000D753.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000D754 + + +*** Searching Compression Signatures *** + + Signature: 01557A9AE226A38386271DFE13D64298 + Signature (Rotated): 0167FCEDBA3A8E8CF822163DB3564762 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Konica Minolta Camera, In] [DiMAGE Z2 ] [ ] No + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[IJG Library ] [092 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [092 ] + SW :[IrfanView ] [092 ] + SW :[idImager ] [092 ] + SW :[FastStone Image Viewer ] [092 ] + SW :[NeatImage ] [092 ] + SW :[Paint.NET ] [092 ] + SW :[Photomatix ] [092 ] + SW :[XnView ] [092 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt new file mode 100644 index 0000000000..717f35f3c9 --- /dev/null +++ b/tests/Images/Input/Jpg/baseline/JpegSnoopReports/ycck.jpg.txt @@ -0,0 +1,640 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ycck.jpg] + Filesize: [611572] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 4452 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 720000/10000 + [YResolution ] = 720000/10000 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CC 2015.5 (Windows)" + [DateTime ] = "2016:08:23 18:21:25" + [ExifOffset ] = @ 0x00AC + Offset to Next IFD = 0x000000D8 + + EXIF IFD1 @ Absolute 0x000000E4 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x0136 = @ 0x0142 + [JpegIFByteCount ] = 0x[00001026] / 4134 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000B8 + Dir Length = 0x0003 + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 0x[00000200] / 512 + [ExifImageHeight ] = 0x[00000200] / 512 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00001168 + Length = 6522 + Identifier = [Photoshop 3.0] + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ + 8BIM: [0x043A] Name="" Len=[0x00E5] DefinedName="Print Information" + Print Information = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 0B 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 00 00 00 05 00 00 00 | intOutput....... + | 0x00 50 73 74 53 62 6F 6F 6C 01 00 00 00 00 49 6E | .PstSbool.....In + | 0x74 65 65 6E 75 6D 00 00 00 00 49 6E 74 65 00 00 | teenum....Inte.. + | 0x00 00 43 6C 72 6D 00 00 00 0F 70 72 69 6E 74 53 | ..Clrm....printS + | 0x69 78 74 65 65 6E 42 69 74 62 6F 6F 6C 00 00 00 | ixteenBitbool... + | 0x00 0B 70 72 69 6E 74 65 72 4E 61 6D 65 54 45 58 | ..printerNameTEX + | 0x54 00 00 00 01 00 00 00 00 00 0F 70 72 69 6E 74 | T..........print + | ... + 8BIM: [0x043B] Name="" Len=[0x022D] DefinedName="Print Style" + Print Style = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 12 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 4F 70 74 69 6F 6E 73 | intOutputOptions + | 0x00 00 00 17 00 00 00 00 43 70 74 6E 62 6F 6F 6C | ........Cptnbool + | 0x00 00 00 00 00 43 6C 62 72 62 6F 6F 6C 00 00 00 | .....Clbrbool... + | 0x00 00 52 67 73 4D 62 6F 6F 6C 00 00 00 00 00 43 | ..RgsMbool.....C + | 0x72 6E 43 62 6F 6F 6C 00 00 00 00 00 43 6E 74 43 | rnCbool.....CntC + | 0x62 6F 6F 6C 00 00 00 00 00 4C 62 6C 73 62 6F 6F | bool.....Lblsboo + | 0x6C 00 00 00 00 00 4E 67 74 76 62 6F 6F 6C 00 00 | l.....Ngtvbool.. + | ... + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 72 pixels per inch + Width unit = cm + Vertical resolution = 72 pixels per inch + Height unit = cm + 8BIM: [0x0426] Name="" Len=[0x000E] DefinedName="Print scale" + Style = centered + X location = 0.00000 + Y location = 0.00000 + Scale = 1.00000 + 8BIM: [0x040D] Name="" Len=[0x0004] DefinedName="Global Angle" + Global Angle = 30 degrees + 8BIM: [0x0419] Name="" Len=[0x0004] DefinedName="Global Altitude" + Global Altitude = 30 + 8BIM: [0x03F3] Name="" Len=[0x0009] DefinedName="Print flags" + Labels = false + Crop marks = false + Color bars = false + Registration marks = false + Negative = false + Flip = false + Interpolate = false + Caption = false + Print flags = true + 8BIM: [0x2710] Name="" Len=[0x000A] DefinedName="Print flags information" + Version = 1 + Center crop marks = 0 + Reserved = 0 + Bleed width value = 0 + Bleed width scale = 2 + 8BIM: [0x03F5] Name="" Len=[0x0048] DefinedName="Color halftoning information" + Color halftoning information = + | 0x00 2F 66 66 00 01 00 6C 66 66 00 06 00 00 00 00 | ./ff...lff...... + | 0x00 01 00 2F 66 66 00 01 00 A1 99 9A 00 06 00 00 | .../ff.......... + | 0x00 00 00 01 00 32 00 00 00 01 00 5A 00 00 00 06 | .....2.....Z.... + | 0x00 00 00 00 00 01 00 35 00 00 00 01 00 2D 00 00 | .......5.....-.. + | 0x00 06 00 00 00 00 00 01 | ........ + 8BIM: [0x03F8] Name="" Len=[0x0070] DefinedName="Color transfer functions" + Color transfer functions = + | 0x00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF 03 E8 00 00 00 00 FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF 03 E8 00 00 00 00 FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0x03 E8 00 00 00 00 FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF 03 E8 00 00 | ................ + 8BIM: [0x0400] Name="" Len=[0x0002] DefinedName="Layer state information" + Target layer = 0 + 8BIM: [0x0402] Name="" Len=[0x0002] DefinedName="Layers group information" + Layer #0: + Layer Group = 0 + 8BIM: [0x0430] Name="" Len=[0x0001] DefinedName="Layer Groups Enabled ID" + Layer #0: + Layer Group Enabled ID = 1 + 8BIM: [0x042D] Name="" Len=[0x0006] DefinedName="Layer Selection IDs" + Num selected = 1 + Layer ID = 3 + 8BIM: [0x0408] Name="" Len=[0x0010] DefinedName="Grid and guides information" + Version = 1 + Grid Horizontal = 576 + Grid Vertical = 576 + Number of Guide Resources = 0 + 8BIM: [0x041E] Name="" Len=[0x0004] DefinedName="URL List" + URL List = | 0x00 00 00 00 | .... + 8BIM: [0x041A] Name="" Len=[0x0363] DefinedName="Slices" + Slice Header: + Version = 6 + Bound Rect (top) = 0 + Bound Rect (left) = 0 + Bound Rect (bottom) = 512 + Bound Rect (right) = 512 + Name of group of slices = "imageprocessor-logo-512" + Number of slices = 1 + ----- + Slice #0: + Slice Resource: + ID = 0 + Group ID = 0 + Origin = 0 + Name = "" + Type = 1 + Position (top) = 0 + Position (left) = 0 + Position (bottom) = 512 + Position (right) = 512 + URL = "" + Target = "" + Message = "" + Alt Tag = "" + Cell text is HTML = true + Cell text = "" + Horizontal alignment = 0 + Vertical alignment = 0 + Alpha color = 0 + Red = 0 + Green = 0 + Blue = 0 + Descriptor version = 16 + Descriptor: + Name from classID = "" + classID = "null" + Num items in descriptor = 2 + ----- + Descriptor item #0: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 512 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 512 + ----- + Descriptor item #1: + Key = "slices" + OSType key = "VlLs" + Num items in list = 1 + ----- + Item #0: + OSType key = "" + Descriptor: + Name from classID = "" + classID = "slice" + Num items in descriptor = 18 + ----- + Descriptor item #0: + Key = "sliceID" + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "groupID" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "origin" + OSType key = "enum" + Type = "ESliceOrigin" + Enum = "autoGenerated" + Descriptor item #3: + Key = "Type" + OSType key = "enum" + Type = "ESliceType" + Enum = "Img " + Descriptor item #4: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 512 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 512 + ----- + Descriptor item #5: + Key = "url" + OSType key = "TEXT" + String = "" + Descriptor item #6: + Key = "null" + OSType key = "TEXT" + String = "" + Descriptor item #7: + Key = "Msge" + OSType key = "TEXT" + String = "" + Descriptor item #8: + Key = "altTag" + OSType key = "TEXT" + String = "" + Descriptor item #9: + Key = "cellTextIsHTML" + OSType key = "bool" + Value = true + Descriptor item #10: + Key = "cellText" + OSType key = "TEXT" + String = "" + Descriptor item #11: + Key = "horzAlign" + OSType key = "enum" + Type = "ESliceHorzAlign" + Enum = "default" + Descriptor item #12: + Key = "vertAlign" + OSType key = "enum" + Type = "ESliceVertAlign" + Enum = "default" + Descriptor item #13: + Key = "bgColorType" + OSType key = "enum" + Type = "ESliceBGColorType" + Enum = "None" + Descriptor item #14: + Key = "topOutset" + OSType key = "long" + Value = 0 + Descriptor item #15: + Key = "leftOutset" + OSType key = "long" + Value = 0 + Descriptor item #16: + Key = "bottomOutset" + OSType key = "long" + Value = 0 + Descriptor item #17: + Key = "rightOutset" + OSType key = "long" + Value = 0 + ----- + ----- + ----- + ----- + 8BIM: [0x0428] Name="" Len=[0x000C] DefinedName="Pixel Aspect Ratio" + Version = 2 + X/Y Ratio = 1.00000 + 8BIM: [0x0414] Name="" Len=[0x0004] DefinedName="Document-specific IDs seed number" + Base value = 3 + 8BIM: [0x040C] Name="" Len=[0x1042] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 160 pixels + Height of thumbnail = 160 pixels + Widthbytes = 480 bytes + Total size = 76800 bytes + Size after compression = 4134 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x00001A3C + 8BIM: [0x0421] Name="" Len=[0x0061] DefinedName="Version Info" + Version = 1 + hasRealMergedData = 1 + Writer name = "Adobe Photoshop" + Reader name = "Adobe Photoshop CC 2015.5" + File version = 1 + 8BIM: [0x0406] Name="" Len=[0x0007] DefinedName="JPEG quality" + Photoshop Save As Quality = 8 + Photoshop Save Format = "Standard" + Photoshop Save Progressive Scans = "3 Scans" + ??? = 1 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00002AE4 + Length = 3685 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000394B + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 9 + Profile Size : 557168 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Output Device profile ('prtr' (0x70727472)) + Data Colour Space : cmykData ('CMYK' (0x434D594B)) + Profile connection space (PCS) : 'Lab ' (0x4C616220) + Profile creation date : 2000-07-26 05:41:53 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'ADBE' (0x41444245) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Media-Relative Colorimetric + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0001392F + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 2 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00023913 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 3 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000338F7 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 4 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000438DB + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 5 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000538BF + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 6 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x000638A3 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 7 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00073887 + Length = 65506 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 8 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0008386B + Length = 33264 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 9 of 9 + Only support decode of 1st ICC Marker + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0008BA5D + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 2 [YCCK] + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0008BA6D + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0008BAF3 + Frame header length = 20 + Precision = 8 + Number of Lines = 512 + Samples per Line = 512 + Image Size = 512 x 512 + Raw Image Orientation = Landscape + Number of Img components = 4 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Cr) + Component[4]: ID=0x04, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (K) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x0008BB09 + Length = 4 + interval = 64 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0008BB0F + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 04 05 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (002 total): 04 21 + Codes of length 06 bits (003 total): 12 31 41 + Codes of length 07 bits (005 total): 05 51 13 61 22 + Codes of length 08 bits (005 total): 06 71 81 91 32 + Codes of length 09 bits (004 total): A1 B1 F0 14 + Codes of length 10 bits (005 total): C1 D1 E1 23 42 + Codes of length 11 bits (006 total): 15 52 62 72 F1 33 + Codes of length 12 bits (004 total): 24 34 43 82 + Codes of length 13 bits (008 total): 16 92 53 25 A2 63 B2 C2 + Codes of length 14 bits (003 total): 07 73 D2 + Codes of length 15 bits (003 total): 35 E2 44 + Codes of length 16 bits (109 total): 83 17 54 93 08 09 0A 18 19 26 36 45 1A 27 64 74 + 55 37 F2 A3 B3 C3 28 29 D3 E3 F3 84 94 A4 B4 C4 + D4 E4 F4 65 75 85 95 A5 B5 C5 D5 E5 F5 46 56 66 + 76 86 96 A6 B6 C6 D6 E6 F6 47 57 67 77 87 97 A7 + B7 C7 D7 E7 F7 38 48 58 68 78 88 98 A8 B8 C8 D8 + E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A + 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0008BCB3 + Scan header length = 14 + Number of img components = 4 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Component[4]: selector=0x04, table=0(DC),0(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support CMYK files yet. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000954F2 + + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: ?x? + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CC 2015.5 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + NOTE: Photoshop IRB detected + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt new file mode 100644 index 0000000000..ea1f5e0f79 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Bedroom.jpg.txt @@ -0,0 +1,461 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue159-MissingFF00-Progressive-Bedroom.jpg] + Filesize: [338422] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 14 18 22 + DQT, Row #1: 4 4 5 7 9 21 22 20 + DQT, Row #2: 5 5 6 9 14 21 25 20 + DQT, Row #3: 5 6 8 10 18 31 29 22 + DQT, Row #4: 6 8 13 20 24 39 37 28 + DQT, Row #5: 9 13 20 23 29 37 41 33 + DQT, Row #6: 18 23 28 31 37 44 43 36 + DQT, Row #7: 26 33 34 35 40 36 37 36 + Approx quality factor = 81.99 (scaling=36.03 variance=1.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 6 6 9 17 36 36 36 36 + DQT, Row #1: 6 8 9 24 36 36 36 36 + DQT, Row #2: 9 9 20 36 36 36 36 36 + DQT, Row #3: 17 24 36 36 36 36 36 36 + DQT, Row #4: 36 36 36 36 36 36 36 36 + DQT, Row #5: 36 36 36 36 36 36 36 36 + DQT, Row #6: 36 36 36 36 36 36 36 36 + DQT, Row #7: 36 36 36 36 36 36 36 36 + Approx quality factor = 81.88 (scaling=36.24 variance=0.48) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 2300 + Samples per Line = 2300 + Image Size = 2300 x 2300 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (003 total): 03 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CE + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000CBBB + Huffman table length = 56 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (004 total): 00 01 02 03 + Codes of length 04 bits (005 total): 04 10 11 12 41 + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (005 total): 05 13 20 22 32 + Codes of length 07 bits (003 total): 15 30 42 + Codes of length 08 bits (005 total): 14 23 33 34 50 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 24 40 + Codes of length 11 bits (002 total): 06 16 + Codes of length 12 bits (002 total): 43 60 + Codes of length 13 bits (002 total): 70 A0 + Codes of length 14 bits (003 total): 44 80 90 + Codes of length 15 bits (001 total): B0 + Codes of length 16 bits (001 total): 35 + Total number of codes: 037 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000CBF5 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001A2A8 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (005 total): 02 03 10 20 30 + Codes of length 05 bits (003 total): 12 13 31 + Codes of length 06 bits (004 total): 04 21 32 40 + Codes of length 07 bits (002 total): 14 51 + Codes of length 08 bits (002 total): 05 41 + Codes of length 09 bits (002 total): 33 50 + Codes of length 10 bits (001 total): 22 + Codes of length 11 bits (004 total): 15 52 61 70 + Codes of length 12 bits (003 total): 23 42 60 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 71 A0 B0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001A2DD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001BB1E + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (005 total): 02 03 10 20 30 + Codes of length 05 bits (003 total): 12 13 31 + Codes of length 06 bits (004 total): 04 21 32 40 + Codes of length 07 bits (002 total): 14 51 + Codes of length 08 bits (003 total): 05 41 50 + Codes of length 09 bits (001 total): 22 + Codes of length 10 bits (000 total): + Codes of length 11 bits (001 total): 61 + Codes of length 12 bits (004 total): 23 33 60 70 + Codes of length 13 bits (002 total): 15 43 + Codes of length 14 bits (003 total): 52 A0 B0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001BB52 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001D49C + Huffman table length = 67 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (004 total): 10 11 21 31 + Codes of length 05 bits (005 total): 02 41 51 71 81 + Codes of length 06 bits (001 total): 20 + Codes of length 07 bits (006 total): 12 22 30 61 91 A1 + Codes of length 08 bits (004 total): 03 32 33 C1 + Codes of length 09 bits (002 total): 40 50 + Codes of length 10 bits (010 total): 13 23 42 52 72 82 B1 D1 E1 F0 + Codes of length 11 bits (002 total): 34 62 + Codes of length 12 bits (003 total): 60 92 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (002 total): 24 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (007 total): 04 70 43 A2 14 C0 D0 + Total number of codes: 048 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001D4E1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000291D6 + Huffman table length = 44 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 31 41 + Codes of length 05 bits (001 total): 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (003 total): 81 91 A1 + Codes of length 08 bits (003 total): 20 B1 F0 + Codes of length 09 bits (004 total): 30 C1 D1 E1 + Codes of length 10 bits (003 total): 40 50 F1 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (001 total): 70 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 025 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00029204 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00044080 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00047DC7 + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 10 30 31 61 + Codes of length 05 bits (006 total): 20 21 40 41 51 71 + Codes of length 06 bits (002 total): 50 60 + Codes of length 07 bits (003 total): 81 91 A1 + Codes of length 08 bits (001 total): B1 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 70 F0 + Codes of length 11 bits (002 total): C1 D1 + Codes of length 12 bits (003 total): A0 B0 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00047DF6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00048BD6 + Huffman table length = 45 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 20 30 31 61 + Codes of length 05 bits (006 total): 10 21 40 41 51 71 + Codes of length 06 bits (002 total): 50 81 + Codes of length 07 bits (003 total): 60 91 B1 + Codes of length 08 bits (001 total): A1 + Codes of length 09 bits (000 total): + Codes of length 10 bits (002 total): 70 C1 + Codes of length 11 bits (002 total): 80 F0 + Codes of length 12 bits (003 total): A0 B0 D1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00048C05 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00049AE7 + Huffman table length = 48 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 70 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (007 total): 01 11 31 41 51 80 91 + Codes of length 05 bits (003 total): 10 21 81 + Codes of length 06 bits (002 total): 50 60 + Codes of length 07 bits (005 total): 20 40 61 71 D1 + Codes of length 08 bits (004 total): 30 B1 E1 F1 + Codes of length 09 bits (002 total): A1 F0 + Codes of length 10 bits (003 total): A0 C0 C1 + Codes of length 11 bits (001 total): D0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 029 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00049B19 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000529F4 + + +*** Searching Compression Signatures *** + + Signature: 0138A8D4ECE59F41D2EB9AF5168B6675 + Signature (Rotated): 01CA9A809F737BA668C16DDE52E74092 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + SW :[IJG Library ] [082 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [082 ] + SW :[IrfanView ] [082 ] + SW :[idImager ] [082 ] + SW :[FastStone Image Viewer ] [082 ] + SW :[NeatImage ] [082 ] + SW :[Paint.NET ] [082 ] + SW :[Photomatix ] [082 ] + SW :[XnView ] [082 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt new file mode 100644 index 0000000000..4858b4ea18 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue159-MissingFF00-Progressive-Girl.jpg.txt @@ -0,0 +1,520 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue159-MissingFF00-Progressive-Girl.jpg] + Filesize: [60927] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000014 + Length = 132 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x0067] DefinedName="IPTC-NAA record" + IPTC [002:040] Special Instructions = "FBMD01000a820d0000192d00007a4400006e460000a9470000a44e00000b7b0000cc830000e0880000a08c0000ffed0000" + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000009A + Length = 3064 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3048 bytes + Preferred CMM Type : '....' (0x00000000) + Profile Version : 0.2.0.0 (0x02000000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2009-03-27 21:36:31 + Profile file signature : 'acsp' (0x61637370) + Primary platform : ? (0x00000000) ('....' (0x00000000)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000001_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : '....' (0x00000000) + Profile ID : 0x29F83DDE_AFF255AE_7842FAE4_CA83390D + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000C94 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 9 6 6 9 14 23 30 35 + DQT, Row #1: 7 7 8 11 15 34 35 32 + DQT, Row #2: 8 8 9 14 23 33 40 32 + DQT, Row #3: 8 10 13 17 30 50 46 36 + DQT, Row #4: 10 13 21 32 39 63 60 45 + DQT, Row #5: 14 20 32 37 47 60 66 53 + DQT, Row #6: 28 37 45 50 60 70 70 59 + DQT, Row #7: 42 53 55 57 65 58 60 57 + Approx quality factor = 71.07 (scaling=57.86 variance=0.92) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000CD9 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 10 10 14 27 57 57 57 57 + DQT, Row #1: 10 12 15 38 57 57 57 57 + DQT, Row #2: 14 15 32 57 57 57 57 57 + DQT, Row #3: 27 38 57 57 57 57 57 57 + DQT, Row #4: 57 57 57 57 57 57 57 57 + DQT, Row #5: 57 57 57 57 57 57 57 57 + DQT, Row #6: 57 57 57 57 57 57 57 57 + DQT, Row #7: 57 57 57 57 57 57 57 57 + Approx quality factor = 71.23 (scaling=57.54 variance=0.18) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x00000D1E + Frame header length = 17 + Precision = 8 + Number of Lines = 990 + Samples per Line = 750 + Image Size = 750 x 990 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D31 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D4E + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000D68 + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000D82 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CED + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (003 total): 03 10 11 + Codes of length 05 bits (003 total): 04 12 20 + Codes of length 06 bits (004 total): 21 30 31 40 + Codes of length 07 bits (002 total): 32 41 + Codes of length 08 bits (002 total): 13 22 + Codes of length 09 bits (003 total): 05 14 50 + Codes of length 10 bits (001 total): 33 + Codes of length 11 bits (001 total): 42 + Codes of length 12 bits (001 total): 23 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D19 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004455 + Huffman table length = 35 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (005 total): 02 10 11 20 30 + Codes of length 05 bits (001 total): 40 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 12 50 + Codes of length 08 bits (003 total): 03 31 41 + Codes of length 09 bits (001 total): 21 + Codes of length 10 bits (001 total): 51 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 016 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000447A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000464C + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (000 total): + Codes of length 04 bits (007 total): 00 10 11 20 30 40 50 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 21 31 70 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000466E + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004775 + Huffman table length = 50 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 02 21 40 + Codes of length 05 bits (007 total): 10 12 30 31 32 50 91 + Codes of length 06 bits (003 total): 20 41 51 + Codes of length 07 bits (003 total): 60 61 71 + Codes of length 08 bits (004 total): 03 22 42 81 + Codes of length 09 bits (002 total): 13 62 + Codes of length 10 bits (001 total): 43 + Codes of length 11 bits (005 total): 23 52 70 80 A1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000047A9 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00004E79 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (004 total): 41 61 71 81 + Codes of length 06 bits (002 total): 20 51 + Codes of length 07 bits (002 total): 30 91 + Codes of length 08 bits (003 total): A1 D1 F0 + Codes of length 09 bits (001 total): 40 + Codes of length 10 bits (001 total): B1 + Codes of length 11 bits (001 total): C1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00004EA4 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B0B + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000083AB + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 11 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 21 30 31 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (001 total): 51 + Codes of length 09 bits (001 total): 40 + Codes of length 10 bits (001 total): 61 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000083CC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000088BF + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 00 10 11 + Codes of length 04 bits (001 total): 20 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 21 31 41 + Codes of length 08 bits (001 total): 40 + Codes of length 09 bits (001 total): 51 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000088E0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008C75 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (003 total): 10 71 81 + Codes of length 08 bits (003 total): 91 A1 B1 + Codes of length 09 bits (005 total): 20 30 C1 D1 F1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F0 + Codes of length 12 bits (001 total): 40 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008CA0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000EDFD + + +*** Searching Compression Signatures *** + + Signature: 01B8FDD60747E53114DC15797CC09B4E + Signature (Rotated): 011975EE86201F10E48E4F365C73A839 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [071 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [071 ] + SW :[IrfanView ] [071 ] + SW :[idImager ] [071 ] + SW :[FastStone Image Viewer ] [071 ] + SW :[NeatImage ] [071 ] + SW :[Paint.NET ] [071 ] + SW :[Photomatix ] [071 ] + SW :[XnView ] [071 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt new file mode 100644 index 0000000000..af39df365c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue178-BadCoeffsProgressive-Lemon.jpg.txt @@ -0,0 +1,471 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue178-BadCoeffsProgressive-Lemon.jpg] + Filesize: [279270] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 2 2 1 + DQT, Row #4: 1 1 1 1 1 2 2 2 + DQT, Row #5: 1 1 1 1 2 2 2 2 + DQT, Row #6: 1 1 2 2 2 2 2 2 + DQT, Row #7: 1 2 2 2 2 2 2 2 + Approx quality factor = 98.32 (scaling=3.35 variance=5.00) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 2 2 2 2 + DQT, Row #1: 1 1 1 1 2 2 2 2 + DQT, Row #2: 1 1 1 2 2 2 2 2 + DQT, Row #3: 1 1 2 2 2 2 2 2 + DQT, Row #4: 2 2 2 2 2 2 2 2 + DQT, Row #5: 2 2 2 2 2 2 2 2 + DQT, Row #6: 2 2 2 2 2 2 2 2 + DQT, Row #7: 2 2 2 2 2 2 2 2 + Approx quality factor = 98.83 (scaling=2.34 variance=0.89) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 710 + Samples per Line = 710 + Image Size = 710 x 710 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 05 + Codes of length 03 bits (004 total): 03 04 06 07 + Codes of length 04 bits (003 total): 00 02 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000D1 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 00 01 02 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000F0 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002D06 + Huffman table length = 49 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 02 + Codes of length 03 bits (004 total): 00 01 03 04 + Codes of length 04 bits (002 total): 05 11 + Codes of length 05 bits (002 total): 06 12 + Codes of length 06 bits (002 total): 13 21 + Codes of length 07 bits (002 total): 07 14 + Codes of length 08 bits (001 total): 22 + Codes of length 09 bits (003 total): 10 15 31 + Codes of length 10 bits (004 total): 16 23 32 41 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (004 total): 08 30 33 50 + Codes of length 13 bits (003 total): 24 40 42 + Codes of length 14 bits (001 total): 34 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 030 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D39 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007ADB + Huffman table length = 72 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (005 total): 05 22 41 51 61 + Codes of length 07 bits (005 total): 06 13 71 81 A1 + Codes of length 08 bits (005 total): 14 32 91 B1 F0 + Codes of length 09 bits (006 total): 23 42 52 C1 D1 E1 + Codes of length 10 bits (004 total): 10 15 33 62 + Codes of length 11 bits (003 total): 07 82 F1 + Codes of length 12 bits (006 total): 20 24 30 43 72 A2 + Codes of length 13 bits (006 total): 16 34 53 92 B2 E2 + Codes of length 14 bits (003 total): 25 44 93 + Codes of length 15 bits (001 total): D2 + Codes of length 16 bits (000 total): + Total number of codes: 053 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B25 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000A7E3 + Huffman table length = 74 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (005 total): 05 12 21 31 41 + Codes of length 06 bits (005 total): 06 13 22 51 61 + Codes of length 07 bits (004 total): 32 71 81 91 + Codes of length 08 bits (006 total): 14 42 52 A1 B1 F0 + Codes of length 09 bits (008 total): 07 10 15 23 62 C1 D1 E1 + Codes of length 10 bits (004 total): 33 43 72 92 + Codes of length 11 bits (004 total): 24 82 A2 F1 + Codes of length 12 bits (004 total): 16 34 63 D2 + Codes of length 13 bits (006 total): 20 40 53 B2 C2 E2 + Codes of length 14 bits (003 total): 17 25 30 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 055 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A82F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000E96D + Huffman table length = 84 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (003 total): 00 03 21 + Codes of length 05 bits (005 total): 04 12 31 41 51 + Codes of length 06 bits (004 total): 05 22 61 71 + Codes of length 07 bits (006 total): 13 32 81 91 A1 F0 + Codes of length 08 bits (008 total): 10 14 23 42 52 B1 C1 D1 + Codes of length 09 bits (003 total): 33 62 E1 + Codes of length 10 bits (005 total): 06 72 82 92 F1 + Codes of length 11 bits (006 total): 15 20 24 43 53 A2 + Codes of length 12 bits (004 total): 30 34 63 73 + Codes of length 13 bits (004 total): 44 83 B2 C2 + Codes of length 14 bits (005 total): 40 50 93 A3 D2 + Codes of length 15 bits (002 total): 16 25 + Codes of length 16 bits (007 total): 26 35 54 60 64 B3 E2 + Total number of codes: 065 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000E9C3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001AD55 + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): C1 D1 F0 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 10 E1 F1 + Codes of length 12 bits (001 total): 20 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001AD7F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000287B1 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00028DB3 + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (003 total): 81 91 F0 + Codes of length 08 bits (005 total): A1 B1 C1 D1 E1 + Codes of length 09 bits (001 total): F1 + Codes of length 10 bits (001 total): 10 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00028DDC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0002CD0C + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (002 total): 00 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (004 total): 71 81 91 F0 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): C1 D1 E1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 30 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002CD37 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00031187 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (001 total): 21 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 00 31 41 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 51 61 + Codes of length 08 bits (002 total): 71 81 + Codes of length 09 bits (002 total): 91 A1 + Codes of length 10 bits (002 total): B1 C1 + Codes of length 11 bits (003 total): D1 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 10 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000311AF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000442E4 + + +*** Searching Compression Signatures *** + + Signature: 01C7F83908166C226C06A44017421732 + Signature (Rotated): 01D3EFDD3855C42AE3E0E6289F1A6726 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Canon ] [Canon EOS-1Ds Mark II ] [fine ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[NIKON ] [NIKON D2X ] [FINE ] No + CAM:[NIKON ] [NIKON D3 ] [FINE ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Digital Photo Professiona] [09 ] + SW :[IJG Library ] [099 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [099 ] + SW :[IrfanView ] [099 ] + SW :[idImager ] [099 ] + SW :[FastStone Image Viewer ] [099 ] + SW :[NeatImage ] [099 ] + SW :[Paint.NET ] [099 ] + SW :[Photomatix ] [099 ] + SW :[XnView ] [099 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt new file mode 100644 index 0000000000..f5b6d277d7 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue214-CriticalEOF .jpg.txt @@ -0,0 +1,94 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue214-CriticalEOF .jpg] + Filesize: [35601] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 39251 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0015 + [Make ] = "NIKON CORPORATION" + [Model ] = "NIKON D40" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "Ver.1.10 " + [DateTime ] = "2009:02:17 08:30:16" + [YCbCrPositioning ] = Co-sited + [ExifOffset ] = @ 0x015C + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + Offset to Next IFD = 0x00007652 + + EXIF IFD1 @ Absolute 0x00007670 + Dir Length = 0x0007 + [Compression ] = JPEG + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x76BC = @ 0x76DA + [JpegIFByteCount ] = 0x[0000228F] / 8847 + [YCbCrPositioning ] = Co-sited + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x0000017A + Dir Length = 0x001C + [ExposureTime ] = 10/1250 s + [FNumber ] = F5.6 + [ExposureProgram ] = Not defined + [ISOSpeedRatings ] = 220 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2009:02:17 08:30:16" + [DateTimeDigitized ] = "2009:02:17 08:30:15" + [ComponentsConfiguration ] = [Y Cb Cr .] + [CompressedBitsPerPixel ] = 1/1 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 41/10 + [MeteringMode ] = Pattern + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 30 mm + [MakerNote ] = @ 0x030A + [UserComment ] = " " + [SubSecTime ] = "60" + [SubSecTimeOriginal ] = "60" + [SubSecTimeDigitized ] = "60" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 3008 + [ExifImageHeight ] = 2000 + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [SceneType ] = A directly photographed image + [CFAPattern ] = + = [ Blu Grn ] + = [ Grn Red ] + + EXIF MakerIFD @ Absolute 0x00000328 + Makernote decode option not enabled. + +ERROR: Early EOF - file may be missing EOI diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt new file mode 100644 index 0000000000..1f98e67dc1 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue385-BadZigZag-Progressive.jpg.txt @@ -0,0 +1,468 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue385-BadZigZag-Progressive.jpg] + Filesize: [388517] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 1440 + Samples per Line = 1920 + Image Size = 1920 x 1440 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 25 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007E0B + Huffman table length = 55 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 04 12 21 + Codes of length 06 bits (002 total): 05 10 + Codes of length 07 bits (004 total): 13 20 22 31 + Codes of length 08 bits (004 total): 06 14 30 41 + Codes of length 09 bits (005 total): 15 32 33 34 40 + Codes of length 10 bits (005 total): 23 24 35 42 50 + Codes of length 11 bits (000 total): + Codes of length 12 bits (002 total): 25 70 + Codes of length 13 bits (003 total): 16 44 60 + Codes of length 14 bits (001 total): 36 + Codes of length 15 bits (001 total): 45 + Codes of length 16 bits (001 total): 43 + Total number of codes: 036 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007E44 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00012C0C + Huffman table length = 46 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 12 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (004 total): 03 21 30 31 + Codes of length 07 bits (006 total): 13 32 40 41 50 51 + Codes of length 08 bits (002 total): 22 61 + Codes of length 09 bits (002 total): 04 60 + Codes of length 10 bits (003 total): 23 33 71 + Codes of length 11 bits (001 total): 42 + Codes of length 12 bits (001 total): 05 + Codes of length 13 bits (001 total): 43 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 027 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00012C3C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00013C45 + Huffman table length = 43 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 12 20 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (004 total): 03 21 31 40 + Codes of length 07 bits (002 total): 41 50 + Codes of length 08 bits (002 total): 13 51 + Codes of length 09 bits (002 total): 22 60 + Codes of length 10 bits (003 total): 32 42 61 + Codes of length 11 bits (001 total): 04 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 71 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00013C72 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000148F2 + Huffman table length = 75 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (004 total): 02 11 21 31 + Codes of length 05 bits (002 total): 03 10 + Codes of length 06 bits (006 total): 12 20 22 32 41 51 + Codes of length 07 bits (007 total): 04 30 33 61 71 81 91 + Codes of length 08 bits (005 total): 13 40 50 52 72 + Codes of length 09 bits (007 total): 23 34 42 62 82 92 A1 + Codes of length 10 bits (001 total): B1 + Codes of length 11 bits (006 total): 14 60 70 73 C1 E1 + Codes of length 12 bits (005 total): 05 63 83 A2 D1 + Codes of length 13 bits (004 total): 24 43 53 93 + Codes of length 14 bits (002 total): 74 F0 + Codes of length 15 bits (002 total): 15 B2 + Codes of length 16 bits (003 total): 35 E2 F1 + Total number of codes: 056 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001493F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0001BD13 + Huffman table length = 44 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 10 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 20 81 91 A1 + Codes of length 09 bits (002 total): 30 B1 + Codes of length 10 bits (002 total): C1 F0 + Codes of length 11 bits (003 total): 40 D1 F1 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (001 total): 50 + Codes of length 14 bits (001 total): 60 + Codes of length 15 bits (001 total): 70 + Codes of length 16 bits (000 total): + Total number of codes: 025 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0001BD41 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002C20D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0002E1DF + Huffman table length = 37 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 10 41 + Codes of length 07 bits (003 total): 20 51 61 + Codes of length 08 bits (001 total): 71 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 91 + Codes of length 13 bits (001 total): A1 + Codes of length 14 bits (001 total): B1 + Codes of length 15 bits (001 total): C1 + Codes of length 16 bits (000 total): + Total number of codes: 018 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0002E206 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000313D7 + Huffman table length = 36 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 20 41 51 + Codes of length 07 bits (001 total): 61 + Codes of length 08 bits (001 total): 71 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 91 + Codes of length 13 bits (001 total): B1 + Codes of length 14 bits (001 total): A1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000313FD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00033E31 + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): A1 B1 + Codes of length 09 bits (003 total): 10 C1 D1 + Codes of length 10 bits (001 total): F0 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 30 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00033E5B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0005EDA3 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt new file mode 100644 index 0000000000..22e9a99dd2 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue394-MultiHuffmanBaseline-Speakers.jpg.txt @@ -0,0 +1,438 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue394-MultiHuffmanBaseline-Speakers.jpg] + Filesize: [257401] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000002 + Length = 576 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 560 bytes + Preferred CMM Type : 'ADBE' (0x41444245) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1999-06-03 00:00:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'none' (0x6E6F6E65) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'ADBE' (0x41444245) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000244 + Length = 90 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x003D] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 3 + IPTC [002:055] Date Created = "20161215" + IPTC [002:060] Time Created = "043026-0600" + IPTC [002:221] ? = ??? + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002A0 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 9 11 12 16 + DQT, Row #1: 4 5 5 6 8 10 12 12 + DQT, Row #2: 4 5 5 6 10 12 12 12 + DQT, Row #3: 6 6 6 11 12 12 12 12 + DQT, Row #4: 9 8 10 12 12 12 12 12 + DQT, Row #5: 11 10 12 12 12 12 12 12 + DQT, Row #6: 12 12 12 12 12 12 12 12 + DQT, Row #7: 16 12 12 12 12 12 12 12 + Approx quality factor = 88.28 (scaling=23.43 variance=111.68) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 13 24 20 20 17 17 + DQT, Row #1: 7 12 16 14 14 12 12 12 + DQT, Row #2: 13 16 14 14 12 12 12 12 + DQT, Row #3: 24 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 90.19 (scaling=19.62 variance=201.04) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00000326 + Length = 4 + interval = 115 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000032C + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF1 (Extended Sequential DCT, Huffman) (xFFC1) *** + OFFSET: 0x0000033C + Frame header length = 17 + Precision = 8 + Number of Lines = 496 + Samples per Line = 920 + Image Size = 920 x 496 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000034F + Huffman table length = 626 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 05 + Codes of length 03 bits (005 total): 02 03 04 06 07 + Codes of length 04 bits (001 total): 01 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 00 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 09 0A 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 07 08 + Codes of length 08 bits (003 total): 09 0A 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 2 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (003 total): 00 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (000 total): + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (005 total): 07 08 09 0A 0B + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 03 11 + Codes of length 04 bits (002 total): 04 12 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (003 total): 00 05 13 + Codes of length 07 bits (002 total): 22 31 + Codes of length 08 bits (004 total): 06 14 32 41 + Codes of length 09 bits (002 total): 23 51 + Codes of length 10 bits (003 total): 15 42 61 + Codes of length 11 bits (005 total): 07 16 33 52 71 + Codes of length 12 bits (006 total): 24 43 62 81 91 F0 + Codes of length 13 bits (006 total): 25 34 72 A1 B1 C1 + Codes of length 14 bits (012 total): 08 18 26 46 53 63 82 92 93 D1 D2 F1 + Codes of length 15 bits (111 total): 09 0A 17 19 1A 27 28 29 2A 35 36 37 38 39 3A 44 + 45 47 48 49 4A 54 55 56 57 58 59 5A 64 65 66 67 + 68 69 6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 + 88 89 8A 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 + A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 + C6 C7 C8 C9 CA D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 + E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 + Codes of length 16 bits (001 total): FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 02 21 31 + Codes of length 05 bits (004 total): 41 51 61 F0 + Codes of length 06 bits (006 total): 03 12 13 71 81 91 + Codes of length 07 bits (006 total): 14 A1 B1 C1 D1 E1 + Codes of length 08 bits (002 total): 04 F1 + Codes of length 09 bits (002 total): 22 32 + Codes of length 10 bits (002 total): 52 62 + Codes of length 11 bits (004 total): 05 42 72 A2 + Codes of length 12 bits (125 total): 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 27 + 28 29 2A 33 34 35 36 37 38 39 3A 43 44 45 46 47 + 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 + 68 69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 + 87 88 89 8A 92 93 94 95 96 97 98 99 9A A3 A4 A5 + A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 + C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA + E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 + Codes of length 13 bits (005 total): F6 F7 F8 F9 FA + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 162 + + ---- + Destination ID = 2 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 02 + Codes of length 05 bits (005 total): 12 21 31 41 51 + Codes of length 06 bits (004 total): 03 61 71 F0 + Codes of length 07 bits (004 total): 13 81 91 A1 + Codes of length 08 bits (006 total): 04 14 C1 D1 E1 F1 + Codes of length 09 bits (002 total): 22 B1 + Codes of length 10 bits (001 total): 42 + Codes of length 11 bits (004 total): 32 52 92 D2 + Codes of length 12 bits (131 total): 05 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 + 27 28 29 2A 33 34 35 36 37 38 39 3A 43 44 45 46 + 47 48 49 4A 53 54 55 56 57 58 59 5A 62 63 64 65 + 66 67 68 69 6A 72 73 74 75 76 77 78 79 7A 82 83 + 84 85 86 87 88 89 8A 93 94 95 96 97 98 99 9A A2 + A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 + BA C2 C3 C4 C5 C6 C7 C8 C9 CA D3 D4 D5 D6 D7 D8 + D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 + F7 F8 F9 + Codes of length 13 bits (001 total): FA + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000005C3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=2(DC),2(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000005D1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0003ED77.0 + + Compression stats: + Compression Ratio: 5.35:1 + Bits per pixel: 4.49:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1109 ( 16%) + # codes of length 03 bits: 4934 ( 69%) + # codes of length 04 bits: 705 ( 10%) + # codes of length 05 bits: 22 ( 0%) + # codes of length 06 bits: 360 ( 5%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 2599 ( 36%) + # codes of length 03 bits: 2938 ( 41%) + # codes of length 04 bits: 1592 ( 22%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 2, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3838 ( 54%) + # codes of length 03 bits: 3132 ( 44%) + # codes of length 04 bits: 156 ( 2%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 4 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 170962 ( 54%) + # codes of length 03 bits: 67518 ( 21%) + # codes of length 04 bits: 33616 ( 11%) + # codes of length 05 bits: 9306 ( 3%) + # codes of length 06 bits: 15458 ( 5%) + # codes of length 07 bits: 7462 ( 2%) + # codes of length 08 bits: 6393 ( 2%) + # codes of length 09 bits: 1640 ( 1%) + # codes of length 10 bits: 1220 ( 0%) + # codes of length 11 bits: 975 ( 0%) + # codes of length 12 bits: 581 ( 0%) + # codes of length 13 bits: 213 ( 0%) + # codes of length 14 bits: 134 ( 0%) + # codes of length 15 bits: 75 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 11236 ( 26%) + # codes of length 03 bits: 12123 ( 28%) + # codes of length 04 bits: 7424 ( 17%) + # codes of length 05 bits: 5864 ( 13%) + # codes of length 06 bits: 4420 ( 10%) + # codes of length 07 bits: 1997 ( 5%) + # codes of length 08 bits: 545 ( 1%) + # codes of length 09 bits: 244 ( 1%) + # codes of length 10 bits: 61 ( 0%) + # codes of length 11 bits: 41 ( 0%) + # codes of length 12 bits: 31 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 2, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 15434 ( 46%) + # codes of length 03 bits: 3540 ( 11%) + # codes of length 04 bits: 2524 ( 8%) + # codes of length 05 bits: 5638 ( 17%) + # codes of length 06 bits: 3224 ( 10%) + # codes of length 07 bits: 1556 ( 5%) + # codes of length 08 bits: 1170 ( 3%) + # codes of length 09 bits: 277 ( 1%) + # codes of length 10 bits: 14 ( 0%) + # codes of length 11 bits: 111 ( 0%) + # codes of length 12 bits: 34 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 97] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 762, 70, -70] RGB=[210,226,237] @ MCU[ 56, 4] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 61 + Next position in scan buffer: Offset 0x0003ED76.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0003ED77 + + +*** Searching Compression Signatures *** + + Signature: 01180AF3DE63318828A86409EF4013DD + Signature (Rotated): 01180AF3DE63318828A86409EF4013DD + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt new file mode 100644 index 0000000000..47e77a4f41 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue517-No-EOI-Progressive.jpg.txt @@ -0,0 +1,406 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue517-No-EOI-Progressive.jpg] + Filesize: [2192567] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 500 x 500 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 248 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 500/1 + [YResolution ] = 500/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS6 (Macintosh)" + [DateTime ] = "2018:01:06 12:59:23" + [ExifOffset ] = @ 0x00A6 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000C4 + Dir Length = 0x0004 + [DateTimeDigitized ] = "2018:01:06 04:40:19" + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[000008CA] / 2250 + [ExifImageHeight ] = 0x[000008CA] / 2250 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x0000010E + Length = 4875 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x0000141B + Length = 100 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x002C] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 2 + IPTC [002:062] Digital Creation Date = "20180106" + IPTC [002:063] Digital Creation Time = "044019-0500" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x5D 51 F3 F0 D0 DE FC 5F 94 67 16 6F B1 02 A3 89 | ]Q....._.g.o.... + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x00001481 + Frame header length = 17 + Precision = 8 + Number of Lines = 2250 + Samples per Line = 2250 + Image Size = 2250 x 2250 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001494 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (005 total): 02 04 01 05 00 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000014B5 + Huffman table length = 195 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 00 03 + Codes of length 04 bits (003 total): 11 04 12 + Codes of length 05 bits (002 total): 21 05 + Codes of length 06 bits (004 total): 31 13 22 10 + Codes of length 07 bits (003 total): 06 41 51 + Codes of length 08 bits (004 total): 32 14 61 71 + Codes of length 09 bits (006 total): 23 07 81 20 91 42 + Codes of length 10 bits (004 total): 15 A1 52 33 + Codes of length 11 bits (007 total): B1 24 62 30 16 C1 72 + Codes of length 12 bits (006 total): D1 43 92 34 82 08 + Codes of length 13 bits (004 total): E1 53 40 25 + Codes of length 14 bits (008 total): 63 17 35 F0 93 73 A2 50 + Codes of length 15 bits (006 total): 44 B2 83 F1 26 54 + Codes of length 16 bits (115 total): 36 64 94 74 C2 60 D2 84 A3 18 70 E2 27 45 37 65 + B3 55 75 A4 95 C3 85 F2 D3 46 76 80 E3 47 56 66 + B4 09 0A 19 1A 28 29 2A 38 39 3A 48 49 4A 57 58 + 59 5A 67 68 69 6A 77 78 79 7A 86 87 88 89 8A 90 + 96 97 98 99 9A A0 A5 A6 A7 A8 A9 AA B0 B5 B6 B7 + B8 B9 BA C0 C4 C5 C6 C7 C8 C9 CA D0 D4 D5 D6 D7 + D8 D9 DA E0 E4 E5 E6 E7 E8 E9 EA F3 F4 F5 F6 F7 + F8 F9 FA + Total number of codes: 176 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000157A + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 01 02 00 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000159B + Huffman table length = 195 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 10 12 21 + Codes of length 06 bits (003 total): 04 20 31 + Codes of length 07 bits (003 total): 41 13 05 + Codes of length 08 bits (002 total): 30 22 + Codes of length 09 bits (003 total): 32 51 14 + Codes of length 10 bits (005 total): 40 06 33 23 61 + Codes of length 11 bits (002 total): 42 15 + Codes of length 12 bits (005 total): 71 52 34 81 50 + Codes of length 13 bits (002 total): 24 91 + Codes of length 14 bits (004 total): A1 43 B1 16 + Codes of length 15 bits (004 total): 07 62 35 53 + Codes of length 16 bits (135 total): F0 D1 25 60 C1 44 E1 72 F1 17 82 63 36 70 26 45 + 54 92 27 A2 D2 08 09 0A 18 19 1A 28 29 2A 37 38 + 39 3A 46 47 48 49 4A 55 56 57 58 59 5A 64 65 66 + 67 68 69 6A 73 74 75 76 77 78 79 7A 80 83 84 85 + 86 87 88 89 8A 90 93 94 95 96 97 98 99 9A A0 A3 + A4 A5 A6 A7 A8 A9 AA B0 B2 B3 B4 B5 B6 B7 B8 B9 + BA C0 C2 C3 C4 C5 C6 C7 C8 C9 CA D0 D3 D4 D5 D6 + D7 D8 D9 DA E0 E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 176 + + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00001660 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 2 + DQT, Row #1: 1 1 1 1 1 1 1 2 + DQT, Row #2: 1 1 1 1 1 1 2 2 + DQT, Row #3: 1 1 1 1 1 2 2 3 + DQT, Row #4: 1 1 1 1 2 2 3 3 + DQT, Row #5: 1 1 1 2 2 3 3 3 + DQT, Row #6: 1 1 2 2 3 3 3 3 + DQT, Row #7: 2 2 2 3 3 3 3 3 + Approx quality factor = 98.11 (scaling=3.79 variance=4.10) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000016A5 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 2 3 3 3 3 + DQT, Row #1: 1 1 1 2 3 3 3 3 + DQT, Row #2: 1 1 2 3 3 3 3 3 + DQT, Row #3: 2 2 3 3 3 3 3 3 + DQT, Row #4: 3 3 3 3 3 3 3 3 + DQT, Row #5: 3 3 3 3 3 3 3 3 + DQT, Row #6: 3 3 3 3 3 3 3 3 + DQT, Row #7: 3 3 3 3 3 3 3 3 + Approx quality factor = 98.36 (scaling=3.29 variance=0.42) + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000016EA + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00023AAF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0003E82C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0006B107 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0008AA32 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000BA727 + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 11 00 21 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): B1 C1 + Codes of length 10 bits (003 total): F0 D1 10 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (002 total): 20 30 + Codes of length 16 bits (011 total): 40 50 60 70 80 90 A0 B0 C0 D0 E0 + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000BA75C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000FE1E7 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001056B6 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 21 31 10 + Codes of length 06 bits (000 total): + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (002 total): 51 61 + Codes of length 09 bits (005 total): 20 71 F0 91 81 + Codes of length 10 bits (005 total): A1 B1 D1 C1 E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): 50 + Codes of length 16 bits (009 total): 60 70 80 90 A0 B0 C0 D0 E0 + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001056EB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0014E060 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001879C8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x002174B5 + + +*** Searching Compression Signatures *** + + Signature: 01DADDC4908E9BA57CC067EEAD54E67D + Signature (Rotated): 01DADDC4908E9BA57CC067EEAD54E67D + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS6 (Macintosh)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 12 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt new file mode 100644 index 0000000000..1b1027f273 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue518-Bad-RST-Progressive.jpg.txt @@ -0,0 +1,759 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue518-Bad-RST-Progressive.jpg] + Filesize: [3764739] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 14215 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0009 + [Make ] = "OLYMPUS CORPORATION" + [Model ] = "E-1" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 300/1 + [YResolution ] = 300/1 + [ResolutionUnit ] = Inch + [Software ] = "GIMP 2.8.10" + [DateTime ] = "2017:04:18 16:37:56" + [ExifOffset ] = @ 0x00BE + Offset to Next IFD = 0x000001DC + + EXIF IFD1 @ Absolute 0x000001FA + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x023A = @ 0x0258 + [JpegIFByteCount ] = 0x[00003545] / 13637 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000DC + Dir Length = 0x0011 + [ExposureTime ] = 1/4 s + [FNumber ] = F18.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2005:07:20 20:08:42" + [ShutterSpeedValue ] = 2/1 + [ApertureValue ] = 833985/100000 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 2972656/1000000 + [MeteringMode ] = CenterWeightedAverage + [Flash ] = Flash did not fire + [FocalLength ] = 14 mm + [FlashPixVersion ] = 01.00 + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 0x[00000BB8] / 3000 + [ExifImageHeight ] = 0x[00000BB8] / 3000 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x0000379D + Comment length = 3 + Comment= + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x000037A2 + Length = 5091 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + | + | + | + | + | 3.1 + | _7201666.ORF + | Custom + | 7450 + | -7 + | -0.75 + | True + | 4 + | True + | 100 + | True + | 0 + | 0 + | 25 + | 0 + | 25 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | Medium Contrast + | ACR 2.4 + | True + | False + | True + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | 3.1 + | _7201666.ORF + | Custom + | 7450 + | -7 + | -0.75 + | True + | 4 + | True + | 100 + | True + | 0 + | 0 + | 25 + | 0 + | 25 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | 0 + | Medium Contrast + | ACR 2.4 + | True + | False + | True + | + | + | 0, 0 + | 32, 22 + | 64, 56 + | 128, 128 + | 192, 196 + | 255, 255 + | + | + | + | + | 0 + | Adobe Photoshop CS6 (Macintosh) + | 0 + | 2014-06-09T12:43:59-04:00 + | 2005-07-21T18:39:06-06:00 + | 2014-06-09T12:43:59-04:00 + | + | + | xmp.iid:0A801174072068118083C9374AAA53C2 + | uuid:021303F2FBA711D98B5DCD54C315AFD0 + | + | xmp.iid:0A801174072068118083C9374AAA53C2 + | uuid:021303F2FBA711D98B5DCD54C315AFD0 + | + | + | + | + | + | + | + | + | image/jpeg + | + | + | 2005-07-20T20:08:42 + | A8D68AA81537D1C7170A5C69A46C6C94 + | 3 + | Adobe RGB (1998) + | + | + | 100 + | + | + | + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00004B87 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000057E1 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00005826 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000586B + Frame header length = 17 + Precision = 8 + Number of Lines = 3000 + Samples per Line = 3000 + Image Size = 3000 x 3000 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000587E + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 04 05 + Codes of length 03 bits (002 total): 03 06 + Codes of length 04 bits (003 total): 00 01 02 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000589C + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 01 02 03 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x000058B9 + Length = 4 + interval = 375 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000058BF + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0004A3DA + Huffman table length = 55 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 01 04 05 + Codes of length 04 bits (000 total): + Codes of length 05 bits (001 total): 00 + Codes of length 06 bits (004 total): 06 11 12 13 + Codes of length 07 bits (001 total): 14 + Codes of length 08 bits (003 total): 15 21 22 + Codes of length 09 bits (003 total): 10 23 31 + Codes of length 10 bits (004 total): 07 20 24 41 + Codes of length 11 bits (002 total): 16 32 + Codes of length 12 bits (002 total): 30 33 + Codes of length 13 bits (002 total): 25 40 + Codes of length 14 bits (002 total): 17 42 + Codes of length 15 bits (000 total): + Codes of length 16 bits (007 total): 34 50 60 43 26 35 44 + Total number of codes: 036 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0004A413 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000B0746 + Huffman table length = 62 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (004 total): 03 10 12 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (004 total): 13 20 22 51 + Codes of length 08 bits (002 total): 04 32 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (003 total): 14 30 71 + Codes of length 11 bits (003 total): 23 40 42 + Codes of length 12 bits (003 total): 33 50 52 + Codes of length 13 bits (003 total): 05 81 91 + Codes of length 14 bits (003 total): 60 A1 B1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (011 total): 15 24 62 43 53 C1 D1 72 F0 F1 E1 + Total number of codes: 043 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000B0786 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000E3DFE + Huffman table length = 69 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (002 total): 03 21 + Codes of length 05 bits (002 total): 12 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (006 total): 04 10 13 22 41 51 + Codes of length 08 bits (001 total): 32 + Codes of length 09 bits (002 total): 20 61 + Codes of length 10 bits (005 total): 05 14 23 42 71 + Codes of length 11 bits (002 total): 30 52 + Codes of length 12 bits (004 total): 33 40 81 91 + Codes of length 13 bits (005 total): 15 50 60 A1 B1 + Codes of length 14 bits (002 total): 62 F0 + Codes of length 15 bits (000 total): + Codes of length 16 bits (015 total): 24 43 70 C1 D1 06 53 72 E1 F1 25 34 44 63 A2 + Total number of codes: 050 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000E3E45 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0012926F + Huffman table length = 79 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 11 12 + Codes of length 05 bits (005 total): 04 13 21 31 41 + Codes of length 06 bits (003 total): 22 32 51 + Codes of length 07 bits (003 total): 23 42 61 + Codes of length 08 bits (002 total): 05 14 + Codes of length 09 bits (003 total): 33 52 71 + Codes of length 10 bits (007 total): 10 24 43 62 81 91 A1 + Codes of length 11 bits (001 total): B1 + Codes of length 12 bits (006 total): 15 20 30 53 72 C1 + Codes of length 13 bits (004 total): 34 40 50 82 + Codes of length 14 bits (003 total): 60 63 92 + Codes of length 15 bits (002 total): A2 D1 + Codes of length 16 bits (015 total): 25 44 70 E1 F0 73 83 B2 F1 06 54 16 35 C2 74 + Total number of codes: 060 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001292C0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x001CCECE + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 41 51 61 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): 10 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 20 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): 50 + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x001CCEFA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0024E532 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0025B81A + Huffman table length = 42 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (002 total): 10 51 + Codes of length 09 bits (002 total): 61 71 + Codes of length 10 bits (001 total): 81 + Codes of length 11 bits (003 total): 20 91 A1 + Codes of length 12 bits (005 total): 30 B1 C1 D1 F0 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (001 total): F1 + Codes of length 16 bits (001 total): 50 + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0025B846 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0029943F + Huffman table length = 43 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (002 total): 41 51 + Codes of length 08 bits (002 total): 10 61 + Codes of length 09 bits (001 total): 71 + Codes of length 10 bits (003 total): 81 91 A1 + Codes of length 11 bits (005 total): 20 B1 C1 D1 F0 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): F1 + Codes of length 15 bits (000 total): + Codes of length 16 bits (003 total): 40 50 60 + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0029946C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x002E23F1 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 41 51 61 + Codes of length 06 bits (001 total): 71 + Codes of length 07 bits (000 total): + Codes of length 08 bits (002 total): 81 91 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 10 E1 F0 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (001 total): 30 + Codes of length 15 bits (001 total): 40 + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x002E241C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00397201 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000258 + Length: 0x00003545 (13637) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: APP0 + Length = 16 + + * Embedded Thumb Marker: DQT + Length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + + * Embedded Thumb Marker: DQT + Length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 196 + Samples per Line = 196 + Image Size = 196 x 196 + + * Embedded Thumb Marker: DHT + Length = 31 + + * Embedded Thumb Marker: DHT + Length = 181 + + * Embedded Thumb Marker: DHT + Length = 31 + + * Embedded Thumb Marker: DHT + Length = 181 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 13024 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [OLYMPUS CORPORATION] [E-1] + EXIF Makernotes: NONE + EXIF Software: OK [GIMP 2.8.10] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] No + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt new file mode 100644 index 0000000000..aadf150e6d --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue520-InvalidCast.jpg.txt @@ -0,0 +1,364 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue520-InvalidCast.jpg] + Filesize: [7751] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 499 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0011 + [DateTime ] = "2017:09:06 15:13:32" + [Model ] = "SAMSUNG-SM-J320AZ" + [Orientation ] = 1 = Row 0: top, Col 0: left + [WhiteBalance ] = Auto white balance + [DateTime ] = "2017:09:06 15:13:04" + [Make ] = "samsung" + [GPSOffset ] = @ 0x0124 + [ExifOffset ] = @ 0x01CD + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000001EB + Dir Length = 0x0002 + + EXIF GPSIFD @ Absolute 0x00000142 + Dir Length = 0x0008 + [GPSTimeStamp ] = 115:8:12.00 + [GPSLatitudeRef ] = "N" + [GPSLongitude ] = 115 deg 8' 12.000" + [GPSLongitudeRef ] = "W" + [GPSDateStamp ] = "2017:08:08" + [GPSLatitude ] = 36 deg 11' 18.000" + [GPSAltitudeRef ] = Below Sea Level + [GPSAltitude ] = 0.000 m + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000209 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 2 2 1 + DQT, Row #4: 1 1 1 1 1 2 2 2 + DQT, Row #5: 1 1 1 1 2 2 2 2 + DQT, Row #6: 1 1 2 2 2 2 2 2 + DQT, Row #7: 1 2 2 2 2 2 2 2 + Approx quality factor = 98.32 (scaling=3.35 variance=5.00) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000024E + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 2 2 2 2 + DQT, Row #1: 1 1 1 1 2 2 2 2 + DQT, Row #2: 1 1 1 2 2 2 2 2 + DQT, Row #3: 1 1 2 2 2 2 2 2 + DQT, Row #4: 2 2 2 2 2 2 2 2 + DQT, Row #5: 2 2 2 2 2 2 2 2 + DQT, Row #6: 2 2 2 2 2 2 2 2 + DQT, Row #7: 2 2 2 2 2 2 2 2 + Approx quality factor = 98.83 (scaling=2.34 variance=0.89) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000293 + Frame header length = 17 + Precision = 8 + Number of Lines = 100 + Samples per Line = 100 + Image Size = 100 x 100 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002A6 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 0A + Codes of length 03 bits (001 total): 09 + Codes of length 04 bits (004 total): 06 07 08 0B + Codes of length 05 bits (003 total): 03 04 05 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (001 total): 02 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002C7 + Huffman table length = 60 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 00 07 11 + Codes of length 06 bits (003 total): 08 12 13 + Codes of length 07 bits (002 total): 14 21 + Codes of length 08 bits (003 total): 09 22 31 + Codes of length 09 bits (005 total): 0A 15 41 51 61 + Codes of length 10 bits (006 total): 16 23 24 32 33 71 + Codes of length 11 bits (003 total): 17 52 62 + Codes of length 12 bits (009 total): 18 42 54 73 91 93 A3 B1 B2 + Codes of length 13 bits (001 total): D2 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 041 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000305 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 03 04 05 06 07 + Codes of length 04 bits (001 total): 08 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000323 + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 04 05 11 + Codes of length 05 bits (003 total): 00 12 21 + Codes of length 06 bits (003 total): 06 22 31 + Codes of length 07 bits (003 total): 13 41 51 + Codes of length 08 bits (002 total): 61 71 + Codes of length 09 bits (004 total): 07 14 32 91 + Codes of length 10 bits (005 total): 15 23 42 81 D1 + Codes of length 11 bits (005 total): 16 62 92 A1 B1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000357 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000365 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00001E45.0 + + Compression stats: + Compression Ratio: 4.36:1 + Bits per pixel: 5.50:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 97 ( 49%) + # codes of length 03 bits: 25 ( 13%) + # codes of length 04 bits: 51 ( 26%) + # codes of length 05 bits: 18 ( 9%) + # codes of length 06 bits: 3 ( 2%) + # codes of length 07 bits: 2 ( 1%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 26 ( 27%) + # codes of length 03 bits: 62 ( 63%) + # codes of length 04 bits: 5 ( 5%) + # codes of length 05 bits: 3 ( 3%) + # codes of length 06 bits: 2 ( 2%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 971 ( 16%) + # codes of length 03 bits: 3435 ( 57%) + # codes of length 04 bits: 456 ( 8%) + # codes of length 05 bits: 579 ( 10%) + # codes of length 06 bits: 285 ( 5%) + # codes of length 07 bits: 96 ( 2%) + # codes of length 08 bits: 74 ( 1%) + # codes of length 09 bits: 59 ( 1%) + # codes of length 10 bits: 30 ( 0%) + # codes of length 11 bits: 7 ( 0%) + # codes of length 12 bits: 9 ( 0%) + # codes of length 13 bits: 1 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1143 ( 50%) + # codes of length 03 bits: 254 ( 11%) + # codes of length 04 bits: 445 ( 19%) + # codes of length 05 bits: 228 ( 10%) + # codes of length 06 bits: 111 ( 5%) + # codes of length 07 bits: 48 ( 2%) + # codes of length 08 bits: 20 ( 1%) + # codes of length 09 bits: 22 ( 1%) + # codes of length 10 bits: 13 ( 1%) + # codes of length 11 bits: 5 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[193] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1001, -7, 97] RGB=[255,244,251] @ MCU[ 5, 3] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00001E44.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00001E45 + + +*** Searching Compression Signatures *** + + Signature: 01C7F83908166C226C06A44017421732 + Signature (Rotated): 01D3EFDD3855C42AE3E0E6289F1A6726 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [samsung] [SAMSUNG-SM-J320AZ] + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Canon ] [Canon EOS-1Ds Mark II ] [fine ] No + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[NIKON ] [NIKON D2X ] [FINE ] No + CAM:[NIKON ] [NIKON D3 ] [FINE ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD10 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SIGMA ] [SIGMA SD14 ] [Qual:12 ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Digital Photo Professiona] [09 ] + SW :[IJG Library ] [099 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [099 ] + SW :[IrfanView ] [099 ] + SW :[idImager ] [099 ] + SW :[FastStone Image Viewer ] [099 ] + SW :[NeatImage ] [099 ] + SW :[Paint.NET ] [099 ] + SW :[Photomatix ] [099 ] + SW :[XnView ] [099 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt new file mode 100644 index 0000000000..0ee1736d3c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue624-DhtHasWrongLength-Progressive-N.jpg.txt @@ -0,0 +1,284 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue624-DhtHasWrongLength-Progressive-N.jpg] + Filesize: [30441] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 6 6 7 10 15 22 34 + DQT, Row #1: 6 7 8 11 14 16 21 30 + DQT, Row #2: 6 8 10 12 17 25 36 54 + DQT, Row #3: 7 11 12 16 21 30 42 62 + DQT, Row #4: 10 14 17 21 28 38 52 76 + DQT, Row #5: 15 16 25 30 38 50 68 95 + DQT, Row #6: 22 21 36 42 52 68 90 124 + DQT, Row #7: 34 30 54 62 76 95 124 167 + Approx quality factor = 71.19 (scaling=57.62 variance=593.35) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 6 6 6 7 10 15 22 34 + DQT, Row #1: 6 7 8 11 14 16 21 30 + DQT, Row #2: 6 8 10 12 17 25 36 54 + DQT, Row #3: 7 11 12 16 21 30 42 62 + DQT, Row #4: 10 14 17 21 28 38 52 76 + DQT, Row #5: 15 16 25 30 38 50 68 95 + DQT, Row #6: 22 21 36 42 52 68 90 124 + DQT, Row #7: 34 30 54 62 76 95 124 167 + Approx quality factor = 80.24 (scaling=39.51 variance=961.47) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009A + Frame header length = 17 + Precision = 8 + Number of Lines = 1080 + Samples per Line = 1080 + Image Size = 1080 x 1080 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000AD + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 05 06 + Codes of length 04 bits (003 total): 01 03 04 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 02 04 06 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000E2 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000151B + Huffman table length = 2 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000151F + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000022BA + Huffman table length = 2 + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000022BE + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000309F + Huffman table length = 53 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 20 + Codes of length 05 bits (007 total): 11 31 33 34 50 71 72 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (005 total): 12 21 52 60 61 + Codes of length 08 bits (007 total): 10 13 22 32 41 51 A1 + Codes of length 09 bits (003 total): 23 53 62 + Codes of length 10 bits (005 total): 70 80 81 A0 F1 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 034 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000030D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003353 + Huffman table length = 54 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 04 + Codes of length 04 bits (002 total): 03 05 + Codes of length 05 bits (008 total): 00 06 20 32 50 63 71 B1 + Codes of length 06 bits (005 total): 11 25 31 35 73 + Codes of length 07 bits (002 total): 12 21 + Codes of length 08 bits (004 total): 10 22 51 60 + Codes of length 09 bits (005 total): 13 23 41 42 52 + Codes of length 10 bits (005 total): 14 33 70 80 A1 + Codes of length 11 bits (001 total): A0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000338B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000378D + Huffman table length = 83 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (003 total): 06 07 11 + Codes of length 06 bits (005 total): 00 21 30 31 B2 + Codes of length 07 bits (009 total): 12 13 32 40 41 50 51 72 74 + Codes of length 08 bits (011 total): 14 16 22 33 35 42 52 61 71 B1 B3 + Codes of length 09 bits (009 total): 15 20 23 24 60 62 81 91 C2 + Codes of length 10 bits (006 total): 10 25 36 43 75 92 + Codes of length 11 bits (004 total): 82 93 A1 A2 + Codes of length 12 bits (006 total): 34 63 64 73 C3 D2 + Codes of length 13 bits (001 total): A3 + Codes of length 14 bits (005 total): 26 45 53 65 83 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 064 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000037E2 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000076E7 + + +*** Searching Compression Signatures *** + + Signature: 014D6128740A2927C9914C433E852F5A + Signature (Rotated): 014D6128740A2927C9914C433E852F5A + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt new file mode 100644 index 0000000000..9feef52cce --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue694-Decode-Exif-OutOfRange.jpg.txt @@ -0,0 +1,368 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue694-Decode-Exif-OutOfRange.jpg] + Filesize: [226421] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 194 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [Software ] = "PhotoFiltre 7" + [DateTime ] = "2017:08:30 22:45:26" + [ExifOffset ] = @ 0x0094 + Offset to Next IFD = 0xFC5019BC + + EXIF IFD1 @ Absolute 0xFC5019C8 + Dir Length = 0x0000 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000A0 + Dir Length = 0x0003 + [ExifVersion ] = 02.10 + [ExifImageWidth ] = 1400 + [ExifImageHeight ] = 1400 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000C6 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000010B + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000150 + Frame header length = 17 + Precision = 8 + Number of Lines = 1400 + Samples per Line = 1400 + Image Size = 1400 x 1400 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000163 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000184 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000023B + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000025C + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000313 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00000321 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00037473.0 + + Compression stats: + Compression Ratio: 26.06:1 + Bits per pixel: 0.92:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 25384 ( 82%) + # codes of length 03 bits: 1101 ( 4%) + # codes of length 04 bits: 566 ( 2%) + # codes of length 05 bits: 758 ( 2%) + # codes of length 06 bits: 429 ( 1%) + # codes of length 07 bits: 616 ( 2%) + # codes of length 08 bits: 933 ( 3%) + # codes of length 09 bits: 1189 ( 4%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 13762 ( 89%) + # codes of length 03 bits: 146 ( 1%) + # codes of length 04 bits: 264 ( 2%) + # codes of length 05 bits: 354 ( 2%) + # codes of length 06 bits: 509 ( 3%) + # codes of length 07 bits: 335 ( 2%) + # codes of length 08 bits: 116 ( 1%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 48125 ( 26%) + # codes of length 03 bits: 20074 ( 11%) + # codes of length 04 bits: 54692 ( 30%) + # codes of length 05 bits: 21145 ( 12%) + # codes of length 06 bits: 3017 ( 2%) + # codes of length 07 bits: 14358 ( 8%) + # codes of length 08 bits: 8803 ( 5%) + # codes of length 09 bits: 2231 ( 1%) + # codes of length 10 bits: 5065 ( 3%) + # codes of length 11 bits: 1096 ( 1%) + # codes of length 12 bits: 224 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 6 ( 0%) + # codes of length 16 bits: 4924 ( 3%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 25772 ( 49%) + # codes of length 03 bits: 5924 ( 11%) + # codes of length 04 bits: 7056 ( 13%) + # codes of length 05 bits: 6378 ( 12%) + # codes of length 06 bits: 2891 ( 5%) + # codes of length 07 bits: 1200 ( 2%) + # codes of length 08 bits: 1082 ( 2%) + # codes of length 09 bits: 1030 ( 2%) + # codes of length 10 bits: 559 ( 1%) + # codes of length 11 bits: 299 ( 1%) + # codes of length 12 bits: 38 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 73 ( 0%) + # codes of length 15 bits: 67 ( 0%) + # codes of length 16 bits: 260 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[ 57] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1016, 0, 0] RGB=[255,255,255] @ MCU[ 40, 2] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x00037472.4 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00037473 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [PhotoFiltre 7] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] Yes + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] Yes + CAM:[SIGMA ] [SIGMA SD9 ] [ ] Yes + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt new file mode 100644 index 0000000000..8911896afa --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue695-Invalid-EOI.jpg.txt @@ -0,0 +1,39 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue695-Invalid-EOI.jpg] + Filesize: [4805575] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 64 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0001 + [ExifOffset ] = @ 0x001A + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000038 + Dir Length = 0x0002 + [ExifImageWidth ] = 0x[000003E8] / 1000 + [ExifImageHeight ] = 0x[000003E8] / 1000 + +ERROR: Expected marker 0xFF, got 0x49 @ offset 0x00000056. Consider using [Tools->Img Search Fwd/Rev]. diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt new file mode 100644 index 0000000000..566291b47e --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue696-Resize-Exif-OutOfRange.jpg.txt @@ -0,0 +1,377 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue696-Resize-Exif-OutOfRange.jpg] + Filesize: [3196058] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 201 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x0007 + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 96/1 + [YResolution ] = 96/1 + [ResolutionUnit ] = Inch + [Software ] = "PhotoFiltre Studio X" + [DateTime ] = "2017:09:12 23:47:30" + [ExifOffset ] = @ 0x009B + Offset to Next IFD = 0xFFFFFFFF + + EXIF IFD1 @ Absolute 0x0000001D + Dir Length = 0x4900 + Excessive # components (117440512). Limiting to first 4000. + Offset to Next IFD = 0x03011200 + + EXIF SubIFD @ Absolute 0x000000B9 + Dir Length = 0x0003 + [ExifVersion ] = 02.10 + [ExifImageWidth ] = 3000 + [ExifImageHeight ] = 3000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000000DF + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=2.99 variance=6.13) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000124 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 1 1 1 1 1 + DQT, Row #1: 1 1 1 1 1 1 1 1 + DQT, Row #2: 1 1 1 1 1 1 1 1 + DQT, Row #3: 1 1 1 1 1 1 1 1 + DQT, Row #4: 1 1 1 1 1 1 1 1 + DQT, Row #5: 1 1 1 1 1 1 1 1 + DQT, Row #6: 1 1 1 1 1 1 1 1 + DQT, Row #7: 1 1 1 1 1 1 1 1 + Approx quality factor = 100.00 (scaling=1.54 variance=1.58) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00000169 + Frame header length = 17 + Precision = 8 + Number of Lines = 3000 + Samples per Line = 3000 + Image Size = 3000 x 3000 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000017C + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000019D + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000254 + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000275 + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000032C + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x0000033A + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0030C498.0 + + Compression stats: + Compression Ratio: 8.45:1 + Bits per pixel: 2.84:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 35306 ( 25%) + # codes of length 03 bits: 79378 ( 56%) + # codes of length 04 bits: 10642 ( 8%) + # codes of length 05 bits: 5371 ( 4%) + # codes of length 06 bits: 3913 ( 3%) + # codes of length 07 bits: 2829 ( 2%) + # codes of length 08 bits: 2486 ( 2%) + # codes of length 09 bits: 1451 ( 1%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 45165 ( 64%) + # codes of length 03 bits: 10069 ( 14%) + # codes of length 04 bits: 6960 ( 10%) + # codes of length 05 bits: 3541 ( 5%) + # codes of length 06 bits: 2100 ( 3%) + # codes of length 07 bits: 1345 ( 2%) + # codes of length 08 bits: 1100 ( 2%) + # codes of length 09 bits: 324 ( 0%) + # codes of length 10 bits: 84 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 1981662 ( 53%) + # codes of length 03 bits: 213036 ( 6%) + # codes of length 04 bits: 749857 ( 20%) + # codes of length 05 bits: 410362 ( 11%) + # codes of length 06 bits: 173055 ( 5%) + # codes of length 07 bits: 94282 ( 3%) + # codes of length 08 bits: 61648 ( 2%) + # codes of length 09 bits: 36705 ( 1%) + # codes of length 10 bits: 19723 ( 1%) + # codes of length 11 bits: 10118 ( 0%) + # codes of length 12 bits: 2157 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 211 ( 0%) + # codes of length 16 bits: 9772 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 425513 ( 38%) + # codes of length 03 bits: 127308 ( 11%) + # codes of length 04 bits: 204956 ( 18%) + # codes of length 05 bits: 171523 ( 15%) + # codes of length 06 bits: 89715 ( 8%) + # codes of length 07 bits: 30159 ( 3%) + # codes of length 08 bits: 25054 ( 2%) + # codes of length 09 bits: 22104 ( 2%) + # codes of length 10 bits: 10243 ( 1%) + # codes of length 11 bits: 4250 ( 0%) + # codes of length 12 bits: 210 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 1829 ( 0%) + # codes of length 15 bits: 1498 ( 0%) + # codes of length 16 bits: 2262 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[127] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 992, -112, 17] RGB=[254,255,227] @ MCU[ 35, 79] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0030C497.3 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0030C498 + + +*** Searching Compression Signatures *** + + Signature: 01BBB1709AC9C1F89220D955A31A8F34 + Signature (Rotated): 01BBB1709AC9C1F89220D955A31A8F34 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [PhotoFiltre Studio X] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[CASIO COMPUTER CO.,LTD ] [EX-Z750 ] [ ] Yes + CAM:[CASIO COMPUTER CO.,LTD. ] [EX-Z1000 ] [ ] Yes + CAM:[PENTAX ] [PENTAX Optio S5i ] [ ] Yes + CAM:[SIGMA ] [SIGMA SD9 ] [ ] Yes + SW :[ACDSee ] [100 ] + SW :[Apple ImageIO.framework ] [100 (Best) ] + SW :[Digital Photo Professiona] [10 ] + SW :[IJG Library ] [100 ] + SW :[MS Office Pic Mgr ] [ ] + SW :[Nikon Scan ] [Excellent Qualit] + SW :[Picasa ] [100 (Maximum) ] + SW :[ZoomBrowser EX ] [highest ] + SW :[EOS Viewer Utility ] [ ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [100 ] + SW :[IrfanView ] [100 ] + SW :[idImager ] [100 ] + SW :[FastStone Image Viewer ] [100 ] + SW :[NeatImage ] [100 ] + SW :[Paint.NET ] [100 ] + SW :[Photomatix ] [100 ] + SW :[XnView ] [100 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt new file mode 100644 index 0000000000..dc283bfcfc --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue721-InvalidAPP0.jpg.txt @@ -0,0 +1,446 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue721-InvalidAPP0.jpg] + Filesize: [1225163] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 806 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0007 + [Make ] = "NIKON CORPORATION" + [Model ] = "NIKON D300S" + [Software ] = "Adobe Bridge CS6 (Windows)" + [DateTime ] = "2017:06:07 16:49:51" + [Artist ] = ""Evgeniy Ivahiv Mr.Ivas"" + [Copyright ] = "Evgeniy Ivahiv Erich Krause" + [ExifOffset ] = @ 0x00EC + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000F8 + Dir Length = 0x0022 + [ExposureTime ] = 1/160 s + [FNumber ] = F10.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 200 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2017:06:06 11:29:53" + [ShutterSpeedValue ] = 7321928/1000000 + [ApertureValue ] = 6643856/1000000 + [ExposureBiasValue ] = -3.00 eV + [MaxApertureValue ] = 50/10 + [MeteringMode ] = CenterWeightedAverage + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 48 mm + [SubSecTimeOriginal ] = "24" + [ColorSpace ] = Uncalibrated + [ExifImageWidth ] = 2304 + [ExifImageHeight ] = 2998 + [SensingMethod ] = One-chip color area sensor + [FileSource ] = DSC + [SceneType ] = A directly photographed image + [ExposureMode ] = Manual exposure + [WhiteBalance ] = Manual white balance + [DigitalZoomRatio ] = 1/1 + [FocalLengthIn35mmFilm ] = 72 + [SceneCaptureType ] = Standard + [GainControl ] = 0 + [Contrast ] = 0 + [Saturation ] = 0 + [Sharpness ] = 2 + [SubjectDistanceRange ] = 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x0000032A + Length = 4442 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00001486 + Length = 160 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x0068] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 4 + IPTC [002:055] Date Created = "20170606" + IPTC [002:060] Time Created = "112953" + IPTC [002:080] By-line = "Evgeniy Ivahiv Mr.Ivas" + IPTC [002:116] Copyright Notice = "Evgeniy Ivahiv Erich Krause" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x59 13 63 D2 BD 08 14 B4 2B E3 4F 37 D7 52 D2 6F | Y.c.....+.O7.R.o + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00001528 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00002182 + Length = 12 + Identifier = [Adobe_CM] + Not known APP0 type. Skipping remainder. + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002190 + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 7 11 14 17 22 17 + DQT, Row #1: 4 5 6 10 14 19 12 12 + DQT, Row #2: 7 6 8 14 19 12 12 12 + DQT, Row #3: 11 10 14 19 12 12 12 12 + DQT, Row #4: 14 14 19 12 12 12 12 12 + DQT, Row #5: 17 19 12 12 12 12 12 12 + DQT, Row #6: 22 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 83.88 (scaling=32.24 variance=430.71) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 9 19 34 20 20 17 17 + DQT, Row #1: 9 12 19 14 14 12 12 12 + DQT, Row #2: 19 19 14 14 12 12 12 12 + DQT, Row #3: 34 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 89.11 (scaling=21.78 variance=377.49) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00002216 + Length = 4 + interval = 288 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x0000221C + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 49152 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x0000222C + Frame header length = 17 + Precision = 8 + Number of Lines = 2998 + Samples per Line = 2304 + Image Size = 2304 x 2998 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000223F + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (004 total): 03 04 05 06 + Codes of length 04 bits (003 total): 02 07 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (001 total): 06 + Codes of length 08 bits (000 total): + Codes of length 09 bits (002 total): 07 08 + Codes of length 10 bits (003 total): 09 0A 0B + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 02 03 11 + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (004 total): 04 12 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (008 total): 05 13 22 71 81 91 A1 F0 + Codes of length 08 bits (004 total): 06 14 B1 C1 + Codes of length 09 bits (005 total): 23 32 D1 E1 F1 + Codes of length 10 bits (002 total): 07 42 + Codes of length 11 bits (003 total): 15 24 52 + Codes of length 12 bits (002 total): 33 62 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 16 + Codes of length 16 bits (125 total): 34 43 72 82 92 A2 08 17 53 B2 C2 25 D2 E2 44 83 + 84 F2 09 0A 18 19 1A 26 27 28 29 2A 35 36 37 38 + 39 3A 45 46 47 48 49 4A 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 85 + 86 87 88 89 8A 93 94 95 96 97 98 B3 C3 D3 99 9A + A3 A4 A5 A6 A7 A8 A9 AA B4 B5 B6 B7 B8 B9 BA C4 + C5 C6 C7 C8 C9 CA D4 D5 D6 D7 D8 D9 DA E3 E4 E5 + E6 E7 E8 E9 EA F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 02 11 + Codes of length 05 bits (001 total): 03 + Codes of length 06 bits (003 total): 12 21 31 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (005 total): 04 13 51 61 71 + Codes of length 09 bits (002 total): 81 F0 + Codes of length 10 bits (006 total): 22 91 A1 B1 C1 D1 + Codes of length 11 bits (003 total): 14 32 E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (127 total): 05 06 07 08 09 0A 15 16 17 18 19 1A 23 24 25 26 + 27 28 29 2A 33 34 35 36 37 38 39 3A 42 43 44 45 + 46 47 48 49 4A 52 53 54 55 56 57 58 59 5A 62 63 + 64 65 66 67 68 69 6A 72 73 74 75 76 77 78 79 7A + 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 + 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 + B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 + D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA + Codes of length 15 bits (009 total): F2 F3 F4 F5 F6 F7 F8 F9 FA + Codes of length 16 bits (000 total): + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000023E3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000023F1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + +*** ERROR: Overread scan segment (after bitstring)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.6 +*** ERROR: Bad scan data in MCU(272,16): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(272,16): Chr(Cb) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(272,16): Chr(Cr) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(2176,128) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Chr(Cb) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,17): Chr(Cr) CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,136) +*** ERROR: Overread scan segment (before nCode)! @ Offset: 0x00003EA5.1 +*** ERROR: Bad huffman code @ 0x00003EA5.1 +*** ERROR: Bad scan data in MCU(0,18): Lum CSS(0,0) @ Offset 0x00003EA5.1 + MCU located at pixel=(0,144) + Only reported first 20 instances of this message... + + Compression stats: + Compression Ratio: 3031.33:1 + Bits per pixel: 0.01:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 4841 ( 99%) + # codes of length 03 bits: 33 ( 1%) + # codes of length 04 bits: 6 ( 0%) + # codes of length 05 bits: 1 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 9732 (100%) + # codes of length 02 bits: 23 ( 0%) + # codes of length 03 bits: 5 ( 0%) + # codes of length 04 bits: 0 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 274 ( 5%) + # codes of length 03 bits: 297 ( 5%) + # codes of length 04 bits: 4903 ( 85%) + # codes of length 05 bits: 88 ( 2%) + # codes of length 06 bits: 26 ( 0%) + # codes of length 07 bits: 98 ( 2%) + # codes of length 08 bits: 25 ( 0%) + # codes of length 09 bits: 4 ( 0%) + # codes of length 10 bits: 14 ( 0%) + # codes of length 11 bits: 1 ( 0%) + # codes of length 12 bits: 2 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 17 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 9760 (100%) + # codes of length 02 bits: 5 ( 0%) + # codes of length 03 bits: 0 ( 0%) + # codes of length 04 bits: 14 ( 0%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 2 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[128] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1014, 0, 0] RGB=[254,254,254] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 17 + Next position in scan buffer: Offset 0x00003EA5.1 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0012B1C9 + + +*** Searching Compression Signatures *** + + Signature: 01A20F69263117021CD16AEF44D6E650 + Signature (Rotated): 01A20F69263117021CD16AEF44D6E650 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [NIKON] [NIKON D300S] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Bridge CS6 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[Adobe Photoshop ] [Save As 08 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 2 - Image has high probability of being processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt new file mode 100644 index 0000000000..92adfb3159 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-A.jpg.txt @@ -0,0 +1,519 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-A.jpg] + Filesize: [42798] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 1 1 2 2 4 5 6 + DQT, Row #1: 1 1 1 2 3 6 6 6 + DQT, Row #2: 1 1 2 2 4 6 7 6 + DQT, Row #3: 1 2 2 3 5 9 8 6 + DQT, Row #4: 2 2 4 6 7 11 10 8 + DQT, Row #5: 2 4 6 6 8 10 11 9 + DQT, Row #6: 5 6 8 9 10 12 12 10 + DQT, Row #7: 7 9 10 10 11 10 10 10 + Approx quality factor = 95.04 (scaling=9.93 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 5 10 10 10 10 + DQT, Row #1: 2 2 3 7 10 10 10 10 + DQT, Row #2: 2 3 6 10 10 10 10 10 + DQT, Row #3: 5 7 10 10 10 10 10 10 + DQT, Row #4: 10 10 10 10 10 10 10 10 + DQT, Row #5: 10 10 10 10 10 10 10 10 + DQT, Row #6: 10 10 10 10 10 10 10 10 + DQT, Row #7: 10 10 10 10 10 10 10 10 + Approx quality factor = 94.91 (scaling=10.18 variance=0.26) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 600 + Samples per Line = 600 + Image Size = 600 x 600 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (005 total): 04 05 06 07 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000A58 + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 01 02 + Codes of length 04 bits (003 total): 03 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000A75 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E55 + Huffman table length = 37 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (005 total): 02 04 05 11 12 + Codes of length 04 bits (004 total): 00 01 03 06 + Codes of length 05 bits (001 total): 30 + Codes of length 06 bits (005 total): 10 13 14 15 16 + Codes of length 07 bits (001 total): 40 + Codes of length 08 bits (001 total): 20 + Codes of length 09 bits (001 total): A0 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 018 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E7C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 2 + Successive approximation = 0x03 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000015BD + Huffman table length = 82 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (004 total): 00 04 05 11 + Codes of length 05 bits (002 total): 12 21 + Codes of length 06 bits (002 total): 13 31 + Codes of length 07 bits (011 total): 06 10 14 22 30 32 40 41 51 61 92 + Codes of length 08 bits (012 total): 15 23 25 52 53 54 71 73 91 A1 B1 C1 + Codes of length 09 bits (007 total): 20 24 33 42 72 81 93 + Codes of length 10 bits (006 total): 43 44 55 62 63 A2 + Codes of length 11 bits (003 total): 82 83 D1 + Codes of length 12 bits (006 total): 16 26 34 50 A0 B2 + Codes of length 13 bits (007 total): 35 45 64 84 A3 C2 E1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 063 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001611 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 3 .. 63 + Successive approximation = 0x03 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002E3F + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 11 + Codes of length 03 bits (001 total): 00 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (004 total): 10 41 51 61 + Codes of length 06 bits (005 total): 20 71 81 91 F0 + Codes of length 07 bits (005 total): 30 A1 B1 C1 D1 + Codes of length 08 bits (001 total): F1 + Codes of length 09 bits (001 total): E1 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (001 total): A0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002E6B + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x32 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003F38 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (004 total): 10 71 81 91 + Codes of length 08 bits (001 total): A1 + Codes of length 09 bits (005 total): 30 B1 C1 D1 F0 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (003 total): 20 40 A0 + Codes of length 14 bits (001 total): 50 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003F65 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00005B9B + Huffman table length = 58 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (003 total): 04 11 12 + Codes of length 05 bits (001 total): 21 + Codes of length 06 bits (005 total): 05 13 14 31 51 + Codes of length 07 bits (005 total): 10 15 20 30 41 + Codes of length 08 bits (005 total): 22 23 32 33 71 + Codes of length 09 bits (005 total): 24 34 61 81 F0 + Codes of length 10 bits (008 total): 80 91 A1 B1 C1 D1 E1 F1 + Codes of length 11 bits (003 total): 42 52 62 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 039 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00005BD7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006270 + Huffman table length = 57 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 00 02 03 11 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 30 + Codes of length 07 bits (004 total): 10 13 14 20 + Codes of length 08 bits (003 total): 32 41 51 + Codes of length 09 bits (007 total): 15 22 23 61 71 81 F0 + Codes of length 10 bits (002 total): 91 A1 + Codes of length 11 bits (004 total): 24 25 33 80 + Codes of length 12 bits (007 total): 42 62 B1 C1 D1 E1 F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 038 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000062AB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006827 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 81 91 A1 B1 + Codes of length 09 bits (003 total): 30 C1 D1 + Codes of length 10 bits (001 total): F0 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (000 total): + Codes of length 14 bits (003 total): 40 A0 F1 + Codes of length 15 bits (001 total): 20 + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006853 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000099AB + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 61 + Codes of length 06 bits (003 total): 10 51 91 + Codes of length 07 bits (004 total): 20 71 81 B1 + Codes of length 08 bits (002 total): 30 A1 + Codes of length 09 bits (002 total): C1 F0 + Codes of length 10 bits (003 total): 80 E1 F1 + Codes of length 11 bits (001 total): D1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000099D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000A0BC + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (004 total): 10 51 61 71 + Codes of length 07 bits (002 total): 30 91 + Codes of length 08 bits (002 total): 20 81 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (002 total): C1 D1 + Codes of length 11 bits (003 total): 40 80 E1 + Codes of length 12 bits (001 total): F1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000A0E7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000A72C + + +*** Searching Compression Signatures *** + + Signature: 01E764F3ECB6C14A51FF83F1FF6D546B + Signature (Rotated): 01E6610D026E8E6FE4BECEA9B3328A63 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[PENTAX ] [PENTAX K10D ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-F828 ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N1 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W55 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Apple ImageIO.framework ] [084 ] + SW :[IJG Library ] [095 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [095 ] + SW :[IrfanView ] [095 ] + SW :[idImager ] [095 ] + SW :[FastStone Image Viewer ] [095 ] + SW :[NeatImage ] [095 ] + SW :[Paint.NET ] [095 ] + SW :[Photomatix ] [095 ] + SW :[XnView ] [095 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt new file mode 100644 index 0000000000..bcbe9f7f1d --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-B.jpg.txt @@ -0,0 +1,477 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-B.jpg] + Filesize: [36937] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 600 + Samples per Line = 600 + Image Size = 600 x 600 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (000 total): + Codes of length 04 bits (007 total): 02 03 04 05 06 07 08 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000A95 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 04 05 + Codes of length 04 bits (003 total): 01 03 06 + Codes of length 05 bits (001 total): 02 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (001 total): 08 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000AB3 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E60 + Huffman table length = 54 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (006 total): 00 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 11 12 13 + Codes of length 06 bits (002 total): 21 50 + Codes of length 07 bits (004 total): 07 10 14 15 + Codes of length 08 bits (004 total): 20 22 23 31 + Codes of length 09 bits (005 total): 16 24 30 32 36 + Codes of length 10 bits (003 total): 25 40 41 + Codes of length 11 bits (004 total): 17 42 43 80 + Codes of length 12 bits (003 total): 26 33 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E98 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001E73 + Huffman table length = 75 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (002 total): 00 11 + Codes of length 05 bits (002 total): 04 12 + Codes of length 06 bits (005 total): 13 21 31 41 51 + Codes of length 07 bits (006 total): 10 22 52 61 71 81 + Codes of length 08 bits (010 total): 05 14 20 32 42 50 91 A1 B1 C1 + Codes of length 09 bits (005 total): 23 33 62 72 D1 + Codes of length 10 bits (010 total): 24 30 40 53 63 73 82 92 E1 F0 + Codes of length 11 bits (005 total): 15 34 35 43 A2 + Codes of length 12 bits (004 total): 64 74 80 B2 + Codes of length 13 bits (003 total): 60 93 F1 + Codes of length 14 bits (001 total): A3 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 056 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001EC0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003A1E + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (005 total): 10 51 61 71 81 + Codes of length 07 bits (004 total): 50 91 A1 B1 + Codes of length 08 bits (002 total): C1 F0 + Codes of length 09 bits (003 total): 20 D1 E1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 40 + Codes of length 12 bits (001 total): 80 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003A4A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00005386 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (001 total): 51 + Codes of length 07 bits (003 total): 61 71 81 + Codes of length 08 bits (004 total): 50 91 A1 B1 + Codes of length 09 bits (002 total): 10 C1 + Codes of length 10 bits (003 total): D1 E1 F0 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 20 80 F1 + Codes of length 13 bits (001 total): 30 + Codes of length 14 bits (001 total): 40 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000053B3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007B5B + Huffman table length = 50 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (003 total): 13 31 40 + Codes of length 07 bits (003 total): 06 22 41 + Codes of length 08 bits (002 total): 14 32 + Codes of length 09 bits (004 total): 10 16 23 33 + Codes of length 10 bits (005 total): 15 20 42 60 61 + Codes of length 11 bits (005 total): 24 34 50 51 52 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 031 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007B8F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000081EE + Huffman table length = 49 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (004 total): 21 31 41 51 + Codes of length 05 bits (003 total): 02 61 71 + Codes of length 06 bits (007 total): 10 40 81 91 A1 B1 C1 + Codes of length 07 bits (003 total): D1 E1 F0 + Codes of length 08 bits (003 total): 03 50 F1 + Codes of length 09 bits (004 total): 12 22 30 60 + Codes of length 10 bits (003 total): 20 32 70 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 030 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008221 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000084F2 + Huffman table length = 48 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (003 total): 00 11 12 + Codes of length 06 bits (003 total): 06 21 31 + Codes of length 07 bits (003 total): 13 22 40 + Codes of length 08 bits (002 total): 14 41 + Codes of length 09 bits (005 total): 07 10 15 32 50 + Codes of length 10 bits (003 total): 42 60 61 + Codes of length 11 bits (005 total): 20 23 33 43 51 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 029 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008524 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008C10 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (004 total): 02 31 41 51 + Codes of length 06 bits (002 total): 61 71 + Codes of length 07 bits (009 total): 03 12 40 81 91 A1 B1 C1 D1 + Codes of length 08 bits (003 total): 10 E1 F0 + Codes of length 09 bits (003 total): 22 32 F1 + Codes of length 10 bits (004 total): 04 50 52 70 + Codes of length 11 bits (003 total): 20 42 60 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008C45 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00009047 + + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt new file mode 100644 index 0000000000..c76b744313 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/Issue723-Ordered-Interleaved-Progressive-C.jpg.txt @@ -0,0 +1,484 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Issue723-Ordered-Interleaved-Progressive-C.jpg] + Filesize: [46799] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 38 x 38 DPcm (dots per cm) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 2 1 1 2 2 4 5 6 + DQT, Row #1: 1 1 1 2 3 6 6 6 + DQT, Row #2: 1 1 2 2 4 6 7 6 + DQT, Row #3: 1 2 2 3 5 9 8 6 + DQT, Row #4: 2 2 4 6 7 11 10 8 + DQT, Row #5: 2 4 6 6 8 10 11 9 + DQT, Row #6: 5 6 8 9 10 12 12 10 + DQT, Row #7: 7 9 10 10 11 10 10 10 + Approx quality factor = 95.04 (scaling=9.93 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 2 2 2 5 10 10 10 10 + DQT, Row #1: 2 2 3 7 10 10 10 10 + DQT, Row #2: 2 3 6 10 10 10 10 10 + DQT, Row #3: 5 7 10 10 10 10 10 10 + DQT, Row #4: 10 10 10 10 10 10 10 10 + DQT, Row #5: 10 10 10 10 10 10 10 10 + DQT, Row #6: 10 10 10 10 10 10 10 10 + DQT, Row #7: 10 10 10 10 10 10 10 10 + Approx quality factor = 94.91 (scaling=10.18 variance=0.26) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 517 + Samples per Line = 502 + Image Size = 502 x 517 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 30 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 06 + Codes of length 04 bits (004 total): 04 05 07 08 + Codes of length 05 bits (003 total): 02 03 09 + Codes of length 06 bits (001 total): 01 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000D1 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000858 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (001 total): 05 + Codes of length 04 bits (005 total): 02 03 04 06 07 + Codes of length 05 bits (001 total): 01 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000877 + Scan header length = 10 + Number of img components = 2 + Component[1]: selector=0x02, table=1(DC),0(AC) + Component[2]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012C2 + Huffman table length = 67 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (002 total): 00 06 + Codes of length 05 bits (001 total): 11 + Codes of length 06 bits (002 total): 07 12 + Codes of length 07 bits (004 total): 13 14 21 50 + Codes of length 08 bits (004 total): 08 15 22 31 + Codes of length 09 bits (002 total): 17 23 + Codes of length 10 bits (006 total): 10 16 20 24 32 41 + Codes of length 11 bits (008 total): 25 33 34 42 51 52 54 62 + Codes of length 12 bits (004 total): 26 30 35 40 + Codes of length 13 bits (005 total): 18 27 37 55 56 + Codes of length 14 bits (005 total): 44 53 61 70 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 048 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001307 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 12 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002FBE + Huffman table length = 80 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (005 total): 13 22 41 51 61 + Codes of length 07 bits (011 total): 05 10 14 32 50 71 81 91 A1 B1 C1 + Codes of length 08 bits (007 total): 20 23 42 52 62 82 D1 + Codes of length 09 bits (009 total): 15 30 33 53 72 92 A2 B2 E1 + Codes of length 10 bits (006 total): 24 40 43 73 C2 E2 + Codes of length 11 bits (004 total): 06 63 D2 F0 + Codes of length 12 bits (005 total): 25 54 75 A3 B3 + Codes of length 13 bits (005 total): 44 64 70 80 83 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 061 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003010 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 13 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000048A9 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (001 total): 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (003 total): 10 81 A1 + Codes of length 08 bits (004 total): 50 91 B1 C1 + Codes of length 09 bits (003 total): 20 D1 F0 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (001 total): 70 + Codes of length 14 bits (001 total): 80 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000048D6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000060D3 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (001 total): 71 + Codes of length 08 bits (004 total): 50 81 91 A1 + Codes of length 09 bits (002 total): 10 B1 + Codes of length 10 bits (002 total): C1 F0 + Codes of length 11 bits (002 total): D1 F1 + Codes of length 12 bits (003 total): 30 70 E1 + Codes of length 13 bits (001 total): 20 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000060FF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007FD1 + Huffman table length = 54 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (002 total): 06 11 + Codes of length 06 bits (006 total): 07 12 13 21 31 50 + Codes of length 07 bits (001 total): 14 + Codes of length 08 bits (002 total): 15 22 + Codes of length 09 bits (005 total): 10 23 32 33 41 + Codes of length 10 bits (003 total): 16 17 20 + Codes of length 11 bits (002 total): 24 34 + Codes of length 12 bits (007 total): 25 26 30 40 42 51 70 + Codes of length 13 bits (001 total): 80 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 035 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008009 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 8 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008F76 + Huffman table length = 59 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (004 total): 03 12 41 51 + Codes of length 06 bits (003 total): 61 71 81 + Codes of length 07 bits (005 total): 10 22 50 91 A1 + Codes of length 08 bits (007 total): 32 52 B1 C1 D1 F0 F1 + Codes of length 09 bits (002 total): 04 13 + Codes of length 10 bits (004 total): 20 23 42 72 + Codes of length 11 bits (006 total): 62 70 80 82 92 E1 + Codes of length 12 bits (003 total): 30 60 A2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 040 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008FB3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 9 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00009B28 + Huffman table length = 51 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 03 + Codes of length 03 bits (004 total): 01 02 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 00 07 11 + Codes of length 06 bits (003 total): 12 13 31 + Codes of length 07 bits (003 total): 08 21 50 + Codes of length 08 bits (003 total): 10 14 15 + Codes of length 09 bits (004 total): 20 23 32 41 + Codes of length 10 bits (001 total): 16 + Codes of length 11 bits (003 total): 22 24 40 + Codes of length 12 bits (005 total): 17 18 33 34 70 + Codes of length 13 bits (001 total): 80 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00009B5D + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 8 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000AB99 + Huffman table length = 62 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (002 total): 03 21 + Codes of length 05 bits (004 total): 12 31 41 51 + Codes of length 06 bits (003 total): 04 61 71 + Codes of length 07 bits (005 total): 10 22 32 50 81 + Codes of length 08 bits (004 total): 13 91 A1 B1 + Codes of length 09 bits (008 total): 20 23 42 52 62 72 C1 D1 + Codes of length 10 bits (005 total): 05 14 92 E1 F0 + Codes of length 11 bits (003 total): 30 33 F1 + Codes of length 12 bits (005 total): 70 80 82 90 A2 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 043 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000ABD9 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 9 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000B6CD + + +*** Searching Compression Signatures *** + + Signature: 01E764F3ECB6C14A51FF83F1FF6D546B + Signature (Rotated): 01E6610D026E8E6FE4BECEA9B3328A63 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Minolta Co., Ltd. ] [DiMAGE F100 ] [ ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E8700 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[PENTAX ] [PENTAX K10D ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-F828 ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N1 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W55 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + SW :[Apple ImageIO.framework ] [084 ] + SW :[IJG Library ] [095 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [095 ] + SW :[IrfanView ] [095 ] + SW :[idImager ] [095 ] + SW :[FastStone Image Viewer ] [095 ] + SW :[NeatImage ] [095 ] + SW :[Paint.NET ] [095 ] + SW :[Photomatix ] [095 ] + SW :[XnView ] [095 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt new file mode 100644 index 0000000000..6070e1cdab --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-load.jpg.txt @@ -0,0 +1,772 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\issue750-exif-load.jpg] + Filesize: [36885] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000002 + Length = 3656 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 08000000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000014 + Dir Length = 0x0010 + [Make ] = "Canon" + [Model ] = "Canon EOS 70D" + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 720000/10000 + [YResolution ] = 720000/10000 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS6 (Windows)" + [DateTime ] = "2018:02:28 17:51:59" + [YCbCrPositioning ] = Centered + [ExifOffset ] = @ 0x012C + [GPSOffset ] = @ 0x04C8 + Offset to Next IFD = 0x000004DC + + EXIF IFD1 @ Absolute 0x000004E8 + Dir Length = 0x0006 + [Compression ] = JPEG + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [JpegIFOffset ] = @ +0x053A = @ 0x0546 + [JpegIFByteCount ] = 0x[00000906] / 2310 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000138 + Dir Length = 0x0025 + [ExposureTime ] = 1/60 s + [FNumber ] = F11.0 + [ExposureProgram ] = Manual + [ISOSpeedRatings ] = 100 + [ExifVersion ] = 02.30 + [DateTimeOriginal ] = "2017:09:14 14:41:54" + [DateTimeDigitized ] = "2017:09:14 14:41:54" + [ComponentsConfiguration ] = [Y Cb Cr .] + [ShutterSpeedValue ] = 393216/65536 + [ApertureValue ] = 458752/65536 + [ExposureBiasValue ] = 0.00 eV + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 50 mm + [UserComment ] = "" + [SubSecTime ] = "277" + [SubSecTimeOriginal ] = "00" + [SubSecTimeDigitized ] = "00" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 0x[000001D3] / 467 + [ExifImageHeight ] = 0x[000002BC] / 700 + [ExifInteroperabilityOffset ] = @ 0x04A8 + [FocalPlaneXResolution ] = 5472000/899 + [FocalPlaneYResolution ] = 3648000/599 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Manual exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + + EXIF GPSIFD @ Absolute 0x000004D4 + Dir Length = 0x0001 + [GPSVersionID ] = 2.3.0.0 + + EXIF InteropIFD @ Absolute 0x000004B4 + Dir Length = 0x0002 + [InteroperabilityIndex ] = "R98" + [InteroperabilityVersion ] = 01.00 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000E4C + Length = 4648 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x002C] DefinedName="IPTC-NAA record" + IPTC [001:090] Coded Character Set = "%G" + IPTC [002:000] Record Version = 51658 + IPTC [002:055] Date Created = "20170914" + IPTC [002:060] Time Created = "144154+0000" + 8BIM: [0x0425] Name="" Len=[0x0010] DefinedName="Caption digest" + Caption digest = | 0x8B 58 80 D1 16 85 C7 6D 47 04 59 0B 61 59 FA 69 | .X.....mG.Y.aY.i + 8BIM: [0x043A] Name="" Len=[0x00E5] DefinedName="Print Information" + Print Information = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 0B 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 00 00 00 05 00 00 00 | intOutput....... + | 0x00 50 73 74 53 62 6F 6F 6C 01 00 00 00 00 49 6E | .PstSbool.....In + | 0x74 65 65 6E 75 6D 00 00 00 00 49 6E 74 65 00 00 | teenum....Inte.. + | 0x00 00 43 6C 72 6D 00 00 00 0F 70 72 69 6E 74 53 | ..Clrm....printS + | 0x69 78 74 65 65 6E 42 69 74 62 6F 6F 6C 00 00 00 | ixteenBitbool... + | 0x00 0B 70 72 69 6E 74 65 72 4E 61 6D 65 54 45 58 | ..printerNameTEX + | 0x54 00 00 00 01 00 00 00 00 00 0F 70 72 69 6E 74 | T..........print + | ... + 8BIM: [0x043B] Name="" Len=[0x022D] DefinedName="Print Style" + Print Style = + | 0x00 00 00 10 00 00 00 01 00 00 00 00 00 12 70 72 | ..............pr + | 0x69 6E 74 4F 75 74 70 75 74 4F 70 74 69 6F 6E 73 | intOutputOptions + | 0x00 00 00 17 00 00 00 00 43 70 74 6E 62 6F 6F 6C | ........Cptnbool + | 0x00 00 00 00 00 43 6C 62 72 62 6F 6F 6C 00 00 00 | .....Clbrbool... + | 0x00 00 52 67 73 4D 62 6F 6F 6C 00 00 00 00 00 43 | ..RgsMbool.....C + | 0x72 6E 43 62 6F 6F 6C 00 00 00 00 00 43 6E 74 43 | rnCbool.....CntC + | 0x62 6F 6F 6C 00 00 00 00 00 4C 62 6C 73 62 6F 6F | bool.....Lblsboo + | 0x6C 00 00 00 00 00 4E 67 74 76 62 6F 6F 6C 00 00 | l.....Ngtvbool.. + | ... + 8BIM: [0x03ED] Name="" Len=[0x0010] DefinedName="ResolutionInfo structure" + Horizontal resolution = 72 pixels per inch + Width unit = cm + Vertical resolution = 72 pixels per inch + Height unit = cm + 8BIM: [0x0426] Name="" Len=[0x000E] DefinedName="Print scale" + Style = centered + X location = 0.00000 + Y location = 0.00000 + Scale = 1.00000 + 8BIM: [0x040D] Name="" Len=[0x0004] DefinedName="Global Angle" + Global Angle = 30 degrees + 8BIM: [0x0419] Name="" Len=[0x0004] DefinedName="Global Altitude" + Global Altitude = 30 + 8BIM: [0x03F3] Name="" Len=[0x0009] DefinedName="Print flags" + Labels = false + Crop marks = false + Color bars = false + Registration marks = false + Negative = false + Flip = false + Interpolate = false + Caption = false + Print flags = true + 8BIM: [0x2710] Name="" Len=[0x000A] DefinedName="Print flags information" + Version = 1 + Center crop marks = 0 + Reserved = 0 + Bleed width value = 0 + Bleed width scale = 2 + 8BIM: [0x03F5] Name="" Len=[0x0048] DefinedName="Color halftoning information" + Color halftoning information = + | 0x00 2F 66 66 00 01 00 6C 66 66 00 06 00 00 00 00 | ./ff...lff...... + | 0x00 01 00 2F 66 66 00 01 00 A1 99 9A 00 06 00 00 | .../ff.......... + | 0x00 00 00 01 00 32 00 00 00 01 00 5A 00 00 00 06 | .....2.....Z.... + | 0x00 00 00 00 00 01 00 35 00 00 00 01 00 2D 00 00 | .......5.....-.. + | 0x00 06 00 00 00 00 00 01 | ........ + 8BIM: [0x03F8] Name="" Len=[0x0070] DefinedName="Color transfer functions" + Color transfer functions = + | 0x00 00 FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF 03 E8 00 00 00 00 FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF 03 E8 00 00 00 00 FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF | ................ + | 0x03 E8 00 00 00 00 FF FF FF FF FF FF FF FF FF FF | ................ + | 0xFF FF FF FF FF FF FF FF FF FF FF FF 03 E8 00 00 | ................ + 8BIM: [0x0408] Name="" Len=[0x0010] DefinedName="Grid and guides information" + Version = 1 + Grid Horizontal = 576 + Grid Vertical = 576 + Number of Guide Resources = 0 + 8BIM: [0x041E] Name="" Len=[0x0004] DefinedName="URL List" + URL List = | 0x00 00 00 00 | .... + 8BIM: [0x041A] Name="" Len=[0x0341] DefinedName="Slices" + Slice Header: + Version = 6 + Bound Rect (top) = 0 + Bound Rect (left) = 0 + Bound Rect (bottom) = 700 + Bound Rect (right) = 467 + Name of group of slices = "513566" + Number of slices = 1 + ----- + Slice #0: + Slice Resource: + ID = 0 + Group ID = 0 + Origin = 0 + Name = "" + Type = 1 + Position (top) = 0 + Position (left) = 0 + Position (bottom) = 467 + Position (right) = 700 + URL = "" + Target = "" + Message = "" + Alt Tag = "" + Cell text is HTML = true + Cell text = "" + Horizontal alignment = 0 + Vertical alignment = 0 + Alpha color = 0 + Red = 0 + Green = 0 + Blue = 0 + Descriptor version = 16 + Descriptor: + Name from classID = "" + classID = "null" + Num items in descriptor = 2 + ----- + Descriptor item #0: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 700 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 467 + ----- + Descriptor item #1: + Key = "slices" + OSType key = "VlLs" + Num items in list = 1 + ----- + Item #0: + OSType key = "" + Descriptor: + Name from classID = "" + classID = "slice" + Num items in descriptor = 18 + ----- + Descriptor item #0: + Key = "sliceID" + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "groupID" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "origin" + OSType key = "enum" + Type = "ESliceOrigin" + Enum = "autoGenerated" + Descriptor item #3: + Key = "Type" + OSType key = "enum" + Type = "ESliceType" + Enum = "Img " + Descriptor item #4: + Key = "bounds" + OSType key = "Objc" + Descriptor: + Name from classID = "" + classID = "Rct1" + Num items in descriptor = 4 + ----- + Descriptor item #0: + Key = "Top " + OSType key = "long" + Value = 0 + Descriptor item #1: + Key = "Left" + OSType key = "long" + Value = 0 + Descriptor item #2: + Key = "Btom" + OSType key = "long" + Value = 700 + Descriptor item #3: + Key = "Rght" + OSType key = "long" + Value = 467 + ----- + Descriptor item #5: + Key = "url" + OSType key = "TEXT" + String = "" + Descriptor item #6: + Key = "null" + OSType key = "TEXT" + String = "" + Descriptor item #7: + Key = "Msge" + OSType key = "TEXT" + String = "" + Descriptor item #8: + Key = "altTag" + OSType key = "TEXT" + String = "" + Descriptor item #9: + Key = "cellTextIsHTML" + OSType key = "bool" + Value = true + Descriptor item #10: + Key = "cellText" + OSType key = "TEXT" + String = "" + Descriptor item #11: + Key = "horzAlign" + OSType key = "enum" + Type = "ESliceHorzAlign" + Enum = "default" + Descriptor item #12: + Key = "vertAlign" + OSType key = "enum" + Type = "ESliceVertAlign" + Enum = "default" + Descriptor item #13: + Key = "bgColorType" + OSType key = "enum" + Type = "ESliceBGColorType" + Enum = "None" + Descriptor item #14: + Key = "topOutset" + OSType key = "long" + Value = 0 + Descriptor item #15: + Key = "leftOutset" + OSType key = "long" + Value = 0 + Descriptor item #16: + Key = "bottomOutset" + OSType key = "long" + Value = 0 + Descriptor item #17: + Key = "rightOutset" + OSType key = "long" + Value = 0 + ----- + ----- + ----- + ----- + 8BIM: [0x0428] Name="" Len=[0x000C] DefinedName="Pixel Aspect Ratio" + Version = 2 + X/Y Ratio = 1.00000 + 8BIM: [0x0414] Name="" Len=[0x0004] DefinedName="Document-specific IDs seed number" + Base value = 1 + 8BIM: [0x040C] Name="" Len=[0x0922] DefinedName="Thumbnail resources" + Format = 1 + Width of thumbnail = 107 pixels + Height of thumbnail = 160 pixels + Widthbytes = 324 bytes + Total size = 51840 bytes + Size after compression = 2310 bytes + Bits per pixel = 24 bits + Number of planes = 1 + JFIF data @ 0x000016FA + 8BIM: [0x0421] Name="" Len=[0x0055] DefinedName="Version Info" + Version = 1 + hasRealMergedData = 1 + Writer name = "Adobe Photoshop" + Reader name = "Adobe Photoshop CS6" + File version = 1 + 8BIM: [0x0406] Name="" Len=[0x0007] DefinedName="JPEG quality" + Photoshop Save As Quality = 7 + Photoshop Save Format = "Standard" + Photoshop Save Progressive Scans = "3 Scans" + ??? = 1 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00002076 + Length = 3752 + Identifier = [http://ns.adobe.com/xap/1.0/] + XMP = + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00002F20 + Length = 3160 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 3144 bytes + Preferred CMM Type : 'Lino' (0x4C696E6F) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 1998-02-09 06:49:00 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Microsoft Corporation ('MSFT' (0x4D534654)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : 'IEC ' (0x49454320) + Device Model : 'sRGB' (0x73524742) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'HP ' (0x48502020) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: APP14 (xFFEE) *** + OFFSET: 0x00003B7A + Length = 14 + DCTEncodeVersion = 100 + APP14Flags0 = 0 + APP14Flags1 = 0 + ColorTransform = 1 [YCbCr] + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00003B8A + Table length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 10 7 7 10 15 18 20 17 + DQT, Row #1: 7 8 8 10 13 16 12 12 + DQT, Row #2: 7 8 8 10 16 12 12 12 + DQT, Row #3: 10 10 10 18 12 12 12 12 + DQT, Row #4: 15 13 16 12 12 12 12 12 + DQT, Row #5: 18 16 12 12 12 12 12 12 + DQT, Row #6: 20 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 83.48 (scaling=33.04 variance=462.13) + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 11 12 21 34 20 20 17 17 + DQT, Row #1: 12 19 24 14 14 12 12 12 + DQT, Row #2: 21 24 14 14 12 12 12 12 + DQT, Row #3: 34 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + Approx quality factor = 87.98 (scaling=24.05 variance=592.80) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x00003C10 + Frame header length = 17 + Precision = 8 + Number of Lines = 700 + Samples per Line = 467 + Image Size = 467 x 700 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 1 x 1), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DRI (Restart Interval) (xFFDD) *** + OFFSET: 0x00003C23 + Length = 4 + interval = 59 + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003C29 + Huffman table length = 418 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 04 05 03 02 06 01 00 + Codes of length 04 bits (001 total): 07 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (001 total): 0A + Codes of length 08 bits (001 total): 0B + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (003 total): 04 05 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 11 04 00 + Codes of length 05 bits (003 total): 05 21 12 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 51 06 13 61 + Codes of length 08 bits (002 total): 22 71 + Codes of length 09 bits (006 total): 81 14 32 91 A1 07 + Codes of length 10 bits (007 total): 15 B1 42 23 C1 52 D1 + Codes of length 11 bits (003 total): E1 33 16 + Codes of length 12 bits (004 total): 62 F0 24 72 + Codes of length 13 bits (002 total): 82 F1 + Codes of length 14 bits (006 total): 25 43 34 53 92 A2 + Codes of length 15 bits (002 total): B2 63 + Codes of length 16 bits (115 total): 73 C2 35 44 27 93 A3 B3 36 17 54 64 74 C3 D2 E2 + 08 26 83 09 0A 18 19 84 94 45 46 A4 B4 56 D3 55 + 28 1A F2 E3 F3 C4 D4 E4 F4 65 75 85 95 A5 B5 C5 + D5 E5 F5 66 76 86 96 A6 B6 C6 D6 E6 F6 37 47 57 + 67 77 87 97 A7 B7 C7 D7 E7 F7 38 48 58 68 78 88 + 98 A8 B8 C8 D8 E8 F8 29 39 49 59 69 79 89 99 A9 + B9 C9 D9 E9 F9 2A 3A 4A 5A 6A 7A 8A 9A AA BA CA + DA EA FA + Total number of codes: 162 + + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 00 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (002 total): 04 21 + Codes of length 06 bits (003 total): 12 31 41 + Codes of length 07 bits (005 total): 05 51 13 61 22 + Codes of length 08 bits (005 total): 06 71 81 91 32 + Codes of length 09 bits (004 total): A1 B1 F0 14 + Codes of length 10 bits (005 total): C1 D1 E1 23 42 + Codes of length 11 bits (006 total): 15 52 62 72 F1 33 + Codes of length 12 bits (004 total): 24 34 43 82 + Codes of length 13 bits (008 total): 16 92 53 25 A2 63 B2 C2 + Codes of length 14 bits (003 total): 07 73 D2 + Codes of length 15 bits (003 total): 35 E2 44 + Codes of length 16 bits (109 total): 83 17 54 93 08 09 0A 18 19 26 36 45 1A 27 64 74 + 55 37 F2 A3 B3 C3 28 29 D3 E3 F3 84 94 A4 B4 C4 + D4 E4 F4 65 75 85 95 A5 B5 C5 D5 E5 F5 46 56 66 + 76 86 96 A6 B6 C6 D6 E6 F6 47 57 67 77 87 97 A7 + B7 C7 D7 E7 F7 38 48 58 68 78 88 98 A8 B8 C8 D8 + E8 F8 39 49 59 69 79 89 99 A9 B9 C9 D9 E9 F9 2A + 3A 4A 5A 6A 7A 8A 9A AA BA CA DA EA FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DCD + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x00003DDB + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x00009013.0 + + Compression stats: + Compression Ratio: 46.60:1 + Bits per pixel: 0.52:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 0 ( 0%) + # codes of length 03 bits: 4910 ( 95%) + # codes of length 04 bits: 280 ( 5%) + # codes of length 05 bits: 2 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 9997 ( 96%) + # codes of length 03 bits: 335 ( 3%) + # codes of length 04 bits: 52 ( 1%) + # codes of length 05 bits: 0 ( 0%) + # codes of length 06 bits: 0 ( 0%) + # codes of length 07 bits: 0 ( 0%) + # codes of length 08 bits: 0 ( 0%) + # codes of length 09 bits: 0 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 5649 ( 33%) + # codes of length 03 bits: 1560 ( 9%) + # codes of length 04 bits: 6758 ( 39%) + # codes of length 05 bits: 1189 ( 7%) + # codes of length 06 bits: 349 ( 2%) + # codes of length 07 bits: 488 ( 3%) + # codes of length 08 bits: 255 ( 1%) + # codes of length 09 bits: 351 ( 2%) + # codes of length 10 bits: 254 ( 1%) + # codes of length 11 bits: 70 ( 0%) + # codes of length 12 bits: 76 ( 0%) + # codes of length 13 bits: 14 ( 0%) + # codes of length 14 bits: 115 ( 1%) + # codes of length 15 bits: 41 ( 0%) + # codes of length 16 bits: 88 ( 1%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 10917 ( 93%) + # codes of length 03 bits: 435 ( 4%) + # codes of length 04 bits: 77 ( 1%) + # codes of length 05 bits: 75 ( 1%) + # codes of length 06 bits: 121 ( 1%) + # codes of length 07 bits: 47 ( 0%) + # codes of length 08 bits: 36 ( 0%) + # codes of length 09 bits: 5 ( 0%) + # codes of length 10 bits: 15 ( 0%) + # codes of length 11 bits: 39 ( 0%) + # codes of length 12 bits: 11 ( 0%) + # codes of length 13 bits: 3 ( 0%) + # codes of length 14 bits: 2 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 1 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[222] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1020, 0, 0] RGB=[255,255,255] @ MCU[ 0, 0] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 87 + Next position in scan buffer: Offset 0x00009012.5 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00009013 + + +*** Embedded JPEG Thumbnail *** + Offset: 0x00000546 + Length: 0x00000906 (2310) + + * Embedded Thumb Marker: SOI + + * Embedded Thumb Marker: APP13 + Length = 12 + + * Embedded Thumb Marker: APP14 + Length = 14 + + * Embedded Thumb Marker: DQT + Length = 132 + ---- + Precision=8 bits + Destination ID=0 (Luminance, typically) + DQT, Row #0: 12 8 8 12 17 21 24 17 + DQT, Row #1: 8 9 9 11 15 19 12 12 + DQT, Row #2: 8 9 10 12 19 12 12 12 + DQT, Row #3: 12 11 12 21 12 12 12 12 + DQT, Row #4: 17 15 19 12 12 12 12 12 + DQT, Row #5: 21 19 12 12 12 12 12 12 + DQT, Row #6: 24 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + ---- + Precision=8 bits + Destination ID=1 (Chrominance, typically) + DQT, Row #0: 13 11 13 16 20 20 17 17 + DQT, Row #1: 11 14 14 14 14 12 12 12 + DQT, Row #2: 13 14 14 14 12 12 12 12 + DQT, Row #3: 16 14 14 12 12 12 12 12 + DQT, Row #4: 20 14 12 12 12 12 12 12 + DQT, Row #5: 20 12 12 12 12 12 12 12 + DQT, Row #6: 17 12 12 12 12 12 12 12 + DQT, Row #7: 17 12 12 12 12 12 12 12 + + * Embedded Thumb Marker: SOF + Frame header length = 17 + Precision = 8 + Number of Lines = 160 + Samples per Line = 107 + Image Size = 107 x 160 + + * Embedded Thumb Marker: DRI + Length = 4 + + * Embedded Thumb Marker: DHT + Length = 319 + + * Embedded Thumb Marker: SOS + Skipping scan data + Skipped 1785 bytes + + * Embedded Thumb Marker: EOI + + * Embedded Thumb Signature: 01C2DDA29A1B5DCCD5E217CF9C558A62 + +*** Searching Compression Signatures *** + + Signature: 0165B3F1B409A4D8D5F2ADFFA970D3A5 + Signature (Rotated): 0165B3F1B409A4D8D5F2ADFFA970D3A5 + File Offset: 0 bytes + Chroma subsampling: 1x1 + EXIF Make/Model: OK [Canon] [Canon EOS 70D] + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS6 (Windows)] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E885 ] [FINE ] Yes + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + + NOTE: Photoshop IRB detected + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + diff --git a/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt new file mode 100644 index 0000000000..48760626be --- /dev/null +++ b/tests/Images/Input/Jpg/issues/JpegSnoopReports/issue750-exif-tranform.jpg.txt @@ -0,0 +1,435 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\issue750-exif-tranform.jpg] + Filesize: [5587341] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 300 x 300 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 8272 + Identifier = [Exif] + Identifier TIFF = 0x[4D4D002A 00000008] + Endian = Motorola (big) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x00000026 + Dir Length = 0x000A + [Make ] = "Canon" + [Model ] = "Canon EOS 500D" + [Orientation ] = 1 = Row 0: top, Col 0: left + [DateTime ] = "2017:12:06 15:48:51" + [Artist ] = "" + [YCbCrPositioning ] = Co-sited + [Copyright ] = "" + [ExifOffset ] = @ 0x00B0 + [GPSOffset ] = @ 0x2034 + [XPAuthor ] = "??" + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x000000CE + Dir Length = 0x0020 + [ExposureTime ] = 1/160 s + [FNumber ] = F9.0 + [ExposureProgram ] = Normal program + [ISOSpeedRatings ] = 3200 + [ExifVersion ] = 02.21 + [DateTimeOriginal ] = "2017:12:06 15:48:51" + [DateTimeDigitized ] = "2017:12:06 15:48:51" + [ComponentsConfiguration ] = [Y Cb Cr .] + [ShutterSpeedValue ] = 483328/65536 + [ApertureValue ] = 417792/65536 + [ExposureBiasValue ] = 1.00 eV + [MeteringMode ] = Pattern + [Flash ] = Flash did not fire + [FocalLength ] = 24 mm + [MakerNote ] = @ 0x028E + [UserComment ] = "" + [SubSecTime ] = "80" + [SubSecTimeOriginal ] = "80" + [SubSecTimeDigitized ] = "80" + [FlashPixVersion ] = 01.00 + [ColorSpace ] = sRGB + [ExifImageWidth ] = 4752 + [ExifImageHeight ] = 3168 + [ExifInteroperabilityOffset ] = @ 0x2010 + [FocalPlaneXResolution ] = 4752000/894 + [FocalPlaneYResolution ] = 3168000/593 + [FocalPlaneResolutionUnit ] = Inch + [CustomRendered ] = Normal process + [ExposureMode ] = Auto exposure + [WhiteBalance ] = Auto white balance + [SceneCaptureType ] = Standard + + EXIF MakerIFD @ Absolute 0x000002AC + Makernote decode option not enabled. + + EXIF GPSIFD @ Absolute 0x00002052 + Dir Length = 0x0001 + [GPSVersionID ] = 2.2.0.0 + + EXIF InteropIFD @ Absolute 0x0000202E + Dir Length = 0x0001 + [InteroperabilityVersion ] = 01.00 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00002066 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 1 1 1 1 1 2 3 4 + DQT, Row #1: 1 1 1 1 2 3 4 3 + DQT, Row #2: 1 1 1 1 2 3 4 3 + DQT, Row #3: 1 1 1 2 3 5 5 4 + DQT, Row #4: 1 1 2 3 4 7 6 5 + DQT, Row #5: 1 2 3 4 5 6 7 6 + DQT, Row #6: 3 4 5 5 6 7 7 6 + DQT, Row #7: 4 6 6 6 7 6 6 6 + Approx quality factor = 96.95 (scaling=6.11 variance=1.09) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000020AB + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 1 1 1 3 6 6 6 6 + DQT, Row #1: 1 1 2 4 6 6 6 6 + DQT, Row #2: 1 2 3 6 6 6 6 6 + DQT, Row #3: 3 4 6 6 6 6 6 6 + DQT, Row #4: 6 6 6 6 6 6 6 6 + DQT, Row #5: 6 6 6 6 6 6 6 6 + DQT, Row #6: 6 6 6 6 6 6 6 6 + DQT, Row #7: 6 6 6 6 6 6 6 6 + Approx quality factor = 96.99 (scaling=6.01 variance=0.24) + +*** Marker: SOF0 (Baseline DCT) (xFFC0) *** + OFFSET: 0x000020F0 + Frame header length = 17 + Precision = 8 + Number of Lines = 3168 + Samples per Line = 4752 + Image Size = 4752 x 3168 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002103 + Huffman table length = 31 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (005 total): 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 09 + Codes of length 08 bits (001 total): 0A + Codes of length 09 bits (001 total): 0B + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002124 + Huffman table length = 181 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (003 total): 00 04 11 + Codes of length 05 bits (003 total): 05 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 06 13 51 61 + Codes of length 08 bits (003 total): 07 22 71 + Codes of length 09 bits (005 total): 14 32 81 91 A1 + Codes of length 10 bits (005 total): 08 23 42 B1 C1 + Codes of length 11 bits (004 total): 15 52 D1 F0 + Codes of length 12 bits (004 total): 24 33 62 72 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (001 total): 82 + Codes of length 16 bits (125 total): 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 + 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 + 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 + 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 + 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 + B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA + D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 + E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000021DB + Huffman table length = 31 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 02 + Codes of length 03 bits (001 total): 03 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (001 total): 05 + Codes of length 06 bits (001 total): 06 + Codes of length 07 bits (001 total): 07 + Codes of length 08 bits (001 total): 08 + Codes of length 09 bits (001 total): 09 + Codes of length 10 bits (001 total): 0A + Codes of length 11 bits (001 total): 0B + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 012 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000021FC + Huffman table length = 181 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (002 total): 03 11 + Codes of length 05 bits (004 total): 04 05 21 31 + Codes of length 06 bits (004 total): 06 12 41 51 + Codes of length 07 bits (003 total): 07 61 71 + Codes of length 08 bits (004 total): 13 22 32 81 + Codes of length 09 bits (007 total): 08 14 42 91 A1 B1 C1 + Codes of length 10 bits (005 total): 09 23 33 52 F0 + Codes of length 11 bits (004 total): 15 62 72 D1 + Codes of length 12 bits (004 total): 0A 16 24 34 + Codes of length 13 bits (000 total): + Codes of length 14 bits (001 total): E1 + Codes of length 15 bits (002 total): 25 F1 + Codes of length 16 bits (119 total): 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 + 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 + 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 + 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 + 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 + B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 + D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 + F4 F5 F6 F7 F8 F9 FA + Total number of codes: 162 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000022B3 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),1(AC) + Component[3]: selector=0x03, table=1(DC),1(AC) + Spectral selection = 0 .. 63 + Successive approximation = 0x00 + + +*** Decoding SCAN Data *** + OFFSET: 0x000022C1 + Scan Decode Mode: No IDCT (DC only) + NOTE: Low-resolution DC component shown. Can decode full-res with [Options->Scan Segment->Full IDCT] + + Scan Data encountered marker 0xFFD9 @ 0x0055418B.0 + + Compression stats: + Compression Ratio: 8.10:1 + Bits per pixel: 2.96:1 + + Huffman code histogram stats: + Huffman Table: (Dest ID: 0, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 7852 ( 3%) + # codes of length 03 bits: 194801 ( 83%) + # codes of length 04 bits: 18114 ( 8%) + # codes of length 05 bits: 9703 ( 4%) + # codes of length 06 bits: 3623 ( 2%) + # codes of length 07 bits: 941 ( 0%) + # codes of length 08 bits: 188 ( 0%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 1, Class: DC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 53609 ( 46%) + # codes of length 03 bits: 36337 ( 31%) + # codes of length 04 bits: 20089 ( 17%) + # codes of length 05 bits: 4404 ( 4%) + # codes of length 06 bits: 2062 ( 2%) + # codes of length 07 bits: 903 ( 1%) + # codes of length 08 bits: 206 ( 0%) + # codes of length 09 bits: 2 ( 0%) + # codes of length 10 bits: 0 ( 0%) + # codes of length 11 bits: 0 ( 0%) + # codes of length 12 bits: 0 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 0 ( 0%) + # codes of length 16 bits: 0 ( 0%) + + Huffman Table: (Dest ID: 0, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 3801677 ( 49%) + # codes of length 03 bits: 1263986 ( 16%) + # codes of length 04 bits: 1288745 ( 17%) + # codes of length 05 bits: 606891 ( 8%) + # codes of length 06 bits: 282047 ( 4%) + # codes of length 07 bits: 273734 ( 4%) + # codes of length 08 bits: 85749 ( 1%) + # codes of length 09 bits: 90483 ( 1%) + # codes of length 10 bits: 39213 ( 1%) + # codes of length 11 bits: 19089 ( 0%) + # codes of length 12 bits: 6439 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 0 ( 0%) + # codes of length 15 bits: 136 ( 0%) + # codes of length 16 bits: 7545 ( 0%) + + Huffman Table: (Dest ID: 1, Class: AC) + # codes of length 01 bits: 0 ( 0%) + # codes of length 02 bits: 309037 ( 51%) + # codes of length 03 bits: 124353 ( 21%) + # codes of length 04 bits: 87742 ( 14%) + # codes of length 05 bits: 43060 ( 7%) + # codes of length 06 bits: 28928 ( 5%) + # codes of length 07 bits: 2442 ( 0%) + # codes of length 08 bits: 8544 ( 1%) + # codes of length 09 bits: 1150 ( 0%) + # codes of length 10 bits: 376 ( 0%) + # codes of length 11 bits: 126 ( 0%) + # codes of length 12 bits: 30 ( 0%) + # codes of length 13 bits: 0 ( 0%) + # codes of length 14 bits: 50 ( 0%) + # codes of length 15 bits: 24 ( 0%) + # codes of length 16 bits: 4 ( 0%) + + YCC clipping in DC: + Y component: [<0= 0] [>255= 0] + Cb component: [<0= 0] [>255= 0] + Cr component: [<0= 0] [>255= 0] + + RGB clipping in DC: + R component: [<0= 0] [>255= 0] + G component: [<0= 0] [>255= 0] + B component: [<0= 0] [>255= 0] + + Average Pixel Luminance (Y): + Y=[215] (range: 0..255) + + Brightest Pixel Search: + YCC=[ 1016, -3, 3] RGB=[255,255,253] @ MCU[ 92, 26] + + Finished Decoding SCAN Data + Number of RESTART markers decoded: 0 + Next position in scan buffer: Offset 0x0055418A.7 + + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0055418B + + +*** Searching Compression Signatures *** + + Signature: 010564D93F295ADB889B91604DC82EE1 + Signature (Rotated): 014302FE54745F4DBB58A0D51CDC66BD + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: OK [Canon] [Canon EOS 500D] + EXIF Makernotes: OK + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[Leica Camera AG ] [M8 Digital Camera ] [ ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5400 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[OLYMPUS CORPORATION ] [C8080WZ ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[Samsung Techwin ] [Digimax V50/a5 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [Pro 815 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV 7, NV 7 ] [ ] No + CAM:[SAMSUNG TECHWIN ] [VLUU NV10, NV10 ] [ ] No + CAM:[SONY ] [CYBERSHOT ] [ ] No + CAM:[SONY ] [DSC-H1 ] [ ] No + CAM:[SONY ] [DSC-H2 ] [ ] No + CAM:[SONY ] [DSC-H5 ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-L1 ] [ ] No + CAM:[SONY ] [DSC-N2 ] [ ] No + CAM:[SONY ] [DSC-P150 ] [ ] No + CAM:[SONY ] [DSC-P200 ] [ ] No + CAM:[SONY ] [DSC-R1 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-V1 ] [ ] No + CAM:[SONY ] [DSC-V3 ] [ ] No + CAM:[SONY ] [DSC-W35 ] [ ] No + CAM:[SONY ] [DSC-W7 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[IJG Library ] [097 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [097 ] + SW :[IrfanView ] [097 ] + SW :[idImager ] [097 ] + SW :[FastStone Image Viewer ] [097 ] + SW :[NeatImage ] [097 ] + SW :[Paint.NET ] [097 ] + SW :[Photomatix ] [097 ] + SW :[XnView ] [097 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 4 - Uncertain if processed or original + While the EXIF fields indicate original, no compression signatures + in the current database were found matching this make/model + + Appears to be new signature for known camera. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg b/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg new file mode 100644 index 0000000000..4753cd526e Binary files /dev/null and b/tests/Images/Input/Jpg/issues/issue750-exif-load.jpg differ diff --git a/tests/Images/Input/Jpg/issues/issue750-exif-tranform.jpg b/tests/Images/Input/Jpg/issues/issue750-exif-tranform.jpg new file mode 100644 index 0000000000..5a906c4375 Binary files /dev/null and b/tests/Images/Input/Jpg/issues/issue750-exif-tranform.jpg differ diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt new file mode 100644 index 0000000000..b6a1fe8094 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/BadEofProgressive.jpg.txt @@ -0,0 +1,452 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\BadEofProgressive.jpg] + Filesize: [67503] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: APP13 (xFFED) *** + OFFSET: 0x00000014 + Length = 124 + Identifier = [Photoshop 3.0] + 8BIM: [0x0404] Name="" Len=[0x005F] DefinedName="IPTC-NAA record" + IPTC [002:040] Special Instructions = "FBMD2300098903000068210000c735000008450000e88e0000fab00000c6cd000002f80000191a0100653f0100" + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x00000092 + Length = 540 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 524 bytes + Preferred CMM Type : 'lcms' (0x6C636D73) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-01-25 03:41:57 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'lcms' (0x6C636D73) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002B0 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 6 4 4 6 10 16 20 24 + DQT, Row #1: 5 5 6 8 10 23 24 22 + DQT, Row #2: 6 5 6 10 16 23 28 22 + DQT, Row #3: 6 7 9 12 20 35 32 25 + DQT, Row #4: 7 9 15 22 27 44 41 31 + DQT, Row #5: 10 14 22 26 32 42 45 37 + DQT, Row #6: 20 26 31 35 41 48 48 40 + DQT, Row #7: 29 37 38 39 45 40 41 40 + Approx quality factor = 79.94 (scaling=40.12 variance=1.43) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x000002F5 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 7 7 10 19 40 40 40 40 + DQT, Row #1: 7 8 10 26 40 40 40 40 + DQT, Row #2: 10 10 22 40 40 40 40 40 + DQT, Row #3: 19 26 40 40 40 40 40 40 + DQT, Row #4: 40 40 40 40 40 40 40 40 + DQT, Row #5: 40 40 40 40 40 40 40 40 + DQT, Row #6: 40 40 40 40 40 40 40 40 + DQT, Row #7: 40 40 40 40 40 40 40 40 + Approx quality factor = 79.87 (scaling=40.26 variance=0.36) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000033A + Frame header length = 17 + Precision = 8 + Number of Lines = 640 + Samples per Line = 640 + Image Size = 640 x 640 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000034D + Huffman table length = 29 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (007 total): 01 02 03 04 05 06 07 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 08 + Codes of length 06 bits (001 total): 09 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000036C + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (003 total): 00 03 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 07 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000389 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),0(AC) + Component[3]: selector=0x02, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002127 + Huffman table length = 63 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (004 total): 00 02 03 11 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (002 total): 05 41 + Codes of length 07 bits (003 total): 13 22 51 + Codes of length 08 bits (004 total): 10 32 61 A1 + Codes of length 09 bits (007 total): 14 20 71 81 91 B1 F0 + Codes of length 10 bits (007 total): 06 23 42 52 C1 D1 E1 + Codes of length 11 bits (002 total): 15 30 + Codes of length 12 bits (005 total): 16 24 33 34 62 + Codes of length 13 bits (005 total): 25 40 50 72 F1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 044 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002168 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003588 + Huffman table length = 61 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (003 total): 04 12 21 + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (004 total): 05 10 13 51 + Codes of length 08 bits (003 total): 14 20 22 + Codes of length 09 bits (005 total): 32 42 61 71 91 + Codes of length 10 bits (007 total): 15 23 33 81 A1 B1 C1 + Codes of length 11 bits (003 total): 06 30 D1 + Codes of length 12 bits (002 total): E1 F0 + Codes of length 13 bits (007 total): 16 24 34 40 43 50 52 + Codes of length 14 bits (001 total): 62 + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 042 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000035C7 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x00 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000044BF + Huffman table length = 71 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (003 total): 12 21 31 + Codes of length 06 bits (004 total): 13 22 41 51 + Codes of length 07 bits (007 total): 05 10 20 32 61 71 81 + Codes of length 08 bits (005 total): 14 23 42 52 91 + Codes of length 09 bits (005 total): 30 33 62 72 A1 + Codes of length 10 bits (007 total): 15 34 43 53 82 92 B1 + Codes of length 11 bits (003 total): 06 24 40 + Codes of length 12 bits (004 total): 44 A2 C1 D1 + Codes of length 13 bits (001 total): E1 + Codes of length 14 bits (004 total): 25 35 50 F0 + Codes of length 15 bits (003 total): 54 63 73 + Codes of length 16 bits (000 total): + Total number of codes: 052 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00004508 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00008EC5 + Huffman table length = 33 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 31 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (001 total): 51 + Codes of length 08 bits (001 total): 20 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (001 total): 30 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 40 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 014 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00008EE8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 10 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000B0CE + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (006 total): 10 41 51 61 71 91 + Codes of length 06 bits (002 total): 20 81 + Codes of length 07 bits (001 total): 30 + Codes of length 08 bits (005 total): 40 A1 B1 C1 F0 + Codes of length 09 bits (001 total): D1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (001 total): 50 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000B0FA + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 11 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000CDA4 + Huffman table length = 32 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (001 total): 10 + Codes of length 07 bits (001 total): 41 + Codes of length 08 bits (001 total): 51 + Codes of length 09 bits (001 total): 20 + Codes of length 10 bits (001 total): 61 + Codes of length 11 bits (001 total): 71 + Codes of length 12 bits (001 total): 81 + Codes of length 13 bits (001 total): 91 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000CDC6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 10 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000F7DF + Huffman table length = 33 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 10 41 + Codes of length 06 bits (003 total): 51 61 71 + Codes of length 07 bits (001 total): 20 + Codes of length 08 bits (001 total): 81 + Codes of length 09 bits (001 total): 30 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 014 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000F802 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 11 .. 19 + Successive approximation = 0x10 +ERROR: Ran out of buffer before EOI during phase 1 of Scan decode @ 0x000107B0 + + NOTE: Scan parsing doesn't support this SOF mode. + +ERROR: Early EOF - file may be missing EOI + +*** Searching Compression Signatures *** + + Signature: 01DC499064BA9264D591FDE9071DFD89 + Signature (Rotated): 0175BAF3251040E0EFB2930B73328E7F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C40Z,D40Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C700UZ ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + SW :[Apple ImageIO.framework ] [050 (Normal) ] + SW :[IJG Library ] [080 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [080 ] + SW :[IrfanView ] [080 ] + SW :[idImager ] [080 ] + SW :[FastStone Image Viewer ] [080 ] + SW :[NeatImage ] [080 ] + SW :[Paint.NET ] [080 ] + SW :[Photomatix ] [080 ] + SW :[XnView ] [080 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt new file mode 100644 index 0000000000..397343c5e5 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/ExifUndefType.jpg.txt @@ -0,0 +1,535 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\ExifUndefType.jpg] + Filesize: [6582] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 72 x 72 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: APP1 (xFFE1) *** + OFFSET: 0x00000014 + Length = 804 + Identifier = [Exif] + Identifier TIFF = 0x[49492A00 86020000] + Endian = Intel (little) + TAG Mark x002A = 0x002A + + EXIF IFD0 @ Absolute 0x000002A4 + Dir Length = 0x000C + [Orientation ] = 1 = Row 0: top, Col 0: left + [XResolution ] = 72/1 + [YResolution ] = 72/1 + [ResolutionUnit ] = Inch + [Software ] = "Adobe Photoshop CS4 Windows" + [DateTime ] = "2014:03:28 16:44:10" + [WhitePoint ] = 0/1000000, 0/1000000 + [PrimChromaticities ] = 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000 + [YCbCrCoefficients ] = 0/1000000, 0/1000000, 0/1000000 + [YCbCrPositioning ] = 0 + [ReferenceBlackWhite ] = 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000, 0/1000000 + [ExifOffset ] = @ 0x0138 + Offset to Next IFD = 0x00000000 + + EXIF SubIFD @ Absolute 0x00000156 + Dir Length = 0x001B + [ExposureTime ] = 0/1000000 s + [FNumber ] = F0.0 + [ExposureProgram ] = Not defined + [ISOSpeedRatings ] = 0, 0 + [ExifVersion ] = 12.20 + [CompressedBitsPerPixel ] = 0/1000000 + [ShutterSpeedValue ] = 0/1000000 + [ApertureValue ] = 0/1000000 + [BrightnessValue ] = 0/1000000 + [ExposureBiasValue ] = 0.00 eV + [MaxApertureValue ] = 0/1000000 + [SubjectDistance ] = 0/1000000 + [MeteringMode ] = Unknown + [LightSource ] = unknown + [Flash ] = Flash did not fire + [FocalLength ] = 0 mm + [FlashPixVersion ] = + [ColorSpace ] = sRGB + [ExifImageWidth ] = 850 + [ExifImageHeight ] = 638 + [FocalPlaneXResolution ] = 0/1000000 + [FocalPlaneYResolution ] = 0/1000000 + [FocalPlaneResolutionUnit ] = 0 + [ExposureIndex ] = 0/1000000 + [SensingMethod ] = 0 + [FileSource ] = 0 + [SceneType ] = 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000033A + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 3 2 2 3 5 8 10 12 + DQT, Row #1: 2 2 3 4 5 12 12 11 + DQT, Row #2: 3 3 3 5 8 11 14 11 + DQT, Row #3: 3 3 4 6 10 17 16 12 + DQT, Row #4: 4 4 7 11 14 22 21 15 + DQT, Row #5: 5 7 11 13 16 21 23 18 + DQT, Row #6: 10 13 16 17 21 24 24 20 + DQT, Row #7: 14 18 19 20 22 20 21 20 + Approx quality factor = 90.06 (scaling=19.88 variance=1.14) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000037F + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 3 4 5 9 20 20 20 20 + DQT, Row #1: 4 4 5 13 20 20 20 20 + DQT, Row #2: 5 5 11 20 20 20 20 20 + DQT, Row #3: 9 13 20 20 20 20 20 20 + DQT, Row #4: 20 20 20 20 20 20 20 20 + DQT, Row #5: 20 20 20 20 20 20 20 20 + DQT, Row #6: 20 20 20 20 20 20 20 20 + DQT, Row #7: 20 20 20 20 20 20 20 20 + Approx quality factor = 89.93 (scaling=20.14 variance=0.34) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x000003C4 + Frame header length = 17 + Precision = 8 + Number of Lines = 165 + Samples per Line = 220 + Image Size = 220 x 165 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000003D7 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 03 07 + Codes of length 04 bits (003 total): 02 04 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (001 total): 01 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000003F5 + Huffman table length = 22 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (000 total): + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 003 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000040D + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000581 + Huffman table length = 41 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (006 total): 00 01 02 03 04 05 + Codes of length 04 bits (001 total): 06 + Codes of length 05 bits (003 total): 11 15 16 + Codes of length 06 bits (004 total): 12 13 14 21 + Codes of length 07 bits (002 total): 07 10 + Codes of length 08 bits (002 total): 22 40 + Codes of length 09 bits (003 total): 17 30 60 + Codes of length 10 bits (001 total): 24 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000005AC + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000883 + Huffman table length = 27 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 11 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 01 10 + Codes of length 05 bits (003 total): 20 30 40 + Codes of length 06 bits (001 total): 50 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000008A0 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000008BF + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (001 total): 01 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 30 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 40 50 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000008DD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000905 + Huffman table length = 65 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (000 total): + Codes of length 03 bits (004 total): 00 01 02 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (004 total): 12 21 31 34 + Codes of length 06 bits (008 total): 13 32 33 35 91 92 93 D2 + Codes of length 07 bits (009 total): 05 10 14 22 41 51 71 A1 D1 + Codes of length 08 bits (010 total): 20 23 40 42 52 61 81 A2 A3 B1 + Codes of length 09 bits (007 total): 15 24 60 62 72 E1 E2 + Codes of length 10 bits (001 total): 30 + Codes of length 11 bits (001 total): B2 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 046 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000948 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000E49 + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (004 total): 51 61 71 D1 + Codes of length 07 bits (006 total): 81 91 A1 C1 F0 F1 + Codes of length 08 bits (002 total): 40 B1 + Codes of length 09 bits (003 total): 10 20 60 + Codes of length 10 bits (001 total): 30 + Codes of length 11 bits (001 total): E1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000E75 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001266 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012E8 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (001 total): 10 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 30 51 + Codes of length 06 bits (003 total): 21 40 50 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001306 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000133E + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 30 51 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 20 61 + Codes of length 07 bits (003 total): 21 40 50 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000135E + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000139C + Huffman table length = 42 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (003 total): 41 51 61 + Codes of length 07 bits (003 total): 71 81 B1 + Codes of length 08 bits (003 total): 91 A1 D1 + Codes of length 09 bits (004 total): 10 40 E1 F0 + Codes of length 10 bits (003 total): 20 C1 F1 + Codes of length 11 bits (001 total): 60 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 023 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000013C8 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x000019B4 + + +*** Searching Compression Signatures *** + + Signature: 013BA18D5561625796E986FDBC09F846 + Signature (Rotated): 01AC57E12793DFA7C46C704625C5AF0F + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: OK [Adobe Photoshop CS4 Windows] + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[??? ] [Treo 680 ] [ ] Yes + CAM:[Canon ] [Canon PowerShot Pro1 ] [fine ] No + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[NIKON ] [E3100 ] [FINE ] No + CAM:[NIKON ] [E4500 ] [FINE ] No + CAM:[NIKON ] [E5000 ] [FINE ] No + CAM:[NIKON ] [E5700 ] [FINE ] No + CAM:[NIKON ] [E775 ] [FINE ] No + CAM:[NIKON ] [E885 ] [FINE ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 9530 ] [Superfine ] Yes + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + CAM:[SONY ] [DSC-H7 ] [ ] No + CAM:[SONY ] [DSC-H9 ] [ ] No + CAM:[SONY ] [DSC-S90 ] [ ] No + CAM:[SONY ] [DSC-W1 ] [ ] No + CAM:[SONY ] [SONY ] [ ] No + SW :[ACDSee ] [ ] + SW :[FixFoto ] [fine ] + SW :[IJG Library ] [090 ] + SW :[ZoomBrowser EX ] [high ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [090 ] + SW :[IrfanView ] [090 ] + SW :[idImager ] [090 ] + SW :[FastStone Image Viewer ] [090 ] + SW :[NeatImage ] [090 ] + SW :[Paint.NET ] [090 ] + SW :[Photomatix ] [090 ] + SW :[XnView ] [090 ] + + NOTE: EXIF Software field recognized as from editor + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + Appears to be new signature for known software. + If the camera/software doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt new file mode 100644 index 0000000000..445e80a7e7 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/Festzug.jpg.txt @@ -0,0 +1,459 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\Festzug.jpg] + Filesize: [49977] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 229 x 229 DPI (dots per inch) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 131 + ---- + Precision=16 bits + Destination ID=0 (Luminance) + DQT, Row #0: 53 37 33 53 80 133 170 203 + DQT, Row #1: 40 40 47 63 87 193 200 183 + DQT, Row #2: 47 43 53 80 133 190 230 186 + DQT, Row #3: 47 57 73 97 170 290 266 206 + DQT, Row #4: 60 73 123 186 226 363 343 256 + DQT, Row #5: 80 117 183 213 270 346 376 306 + DQT, Row #6: 163 213 260 290 343 403 400 336 + DQT, Row #7: 240 306 316 326 373 333 343 330 + Approx quality factor = 15.01 (scaling=333.00 variance=1.25) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000099 + Table length = 131 + ---- + Precision=16 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 57 60 80 157 330 330 330 330 + DQT, Row #1: 60 70 87 220 330 330 330 330 + DQT, Row #2: 80 87 186 330 330 330 330 330 + DQT, Row #3: 157 220 330 330 330 330 330 330 + DQT, Row #4: 330 330 330 330 330 330 330 330 + DQT, Row #5: 330 330 330 330 330 330 330 330 + DQT, Row #6: 330 330 330 330 330 330 330 330 + DQT, Row #7: 330 330 330 330 330 330 330 330 + Approx quality factor = 15.00 (scaling=333.41 variance=0.14) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000011E + Frame header length = 17 + Precision = 8 + Number of Lines = 1071 + Samples per Line = 1443 + Image Size = 1443 x 1071 + Raw Image Orientation = Landscape + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000131 + Huffman table length = 25 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 03 + Codes of length 05 bits (001 total): 04 + Codes of length 06 bits (001 total): 05 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 006 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000014C + Huffman table length = 22 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (001 total): 00 + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (000 total): + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 003 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000164 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000028E0 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (004 total): 02 10 20 30 + Codes of length 05 bits (003 total): 12 31 40 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 21 41 50 + Codes of length 08 bits (001 total): 60 + Codes of length 09 bits (001 total): 03 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 22 32 42 + Codes of length 12 bits (001 total): 13 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002908 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003D97 + Huffman table length = 29 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (003 total): 00 10 11 + Codes of length 04 bits (001 total): 20 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 30 60 + Codes of length 07 bits (003 total): 80 90 C0 + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 010 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DB6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003DE1 + Huffman table length = 28 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 10 11 + Codes of length 04 bits (003 total): 00 20 60 + Codes of length 05 bits (000 total): + Codes of length 06 bits (003 total): 80 90 C0 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003DFF + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003E21 + Huffman table length = 23 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 21 + Codes of length 02 bits (001 total): D0 + Codes of length 03 bits (001 total): A0 + Codes of length 04 bits (001 total): B0 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 004 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003E3A + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003E4C + Huffman table length = 36 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 10 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (003 total): 20 30 41 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 40 50 51 + Codes of length 08 bits (001 total): 61 + Codes of length 09 bits (001 total): 60 + Codes of length 10 bits (001 total): 71 + Codes of length 11 bits (001 total): 81 + Codes of length 12 bits (001 total): B1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00003E72 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006325 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007512 + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (003 total): 10 21 60 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 41 80 + Codes of length 08 bits (001 total): C0 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00007532 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000075CE + Huffman table length = 30 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 11 + Codes of length 03 bits (001 total): 10 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 21 31 60 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 20 80 C0 + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 011 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000075EE + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00007676 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 10 41 + Codes of length 07 bits (002 total): 20 51 + Codes of length 08 bits (002 total): 30 61 + Codes of length 09 bits (003 total): 40 50 71 + Codes of length 10 bits (000 total): + Codes of length 11 bits (003 total): 60 81 91 + Codes of length 12 bits (001 total): A1 + Codes of length 13 bits (001 total): B1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (002 total): C1 D1 + Codes of length 16 bits (003 total): E1 F0 F1 + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000076A3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000C337 + + +*** Searching Compression Signatures *** + + Signature: 0105A3D95D2D36DE9351313E30D8E945 + Signature (Rotated): 013C3A43642D2E8325A76C3818B3C324 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + SW :[IJG Library ] [015 ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [015 ] + SW :[IrfanView ] [015 ] + SW :[idImager ] [015 ] + SW :[FastStone Image Viewer ] [015 ] + SW :[NeatImage ] [015 ] + SW :[Paint.NET ] [015 ] + SW :[Photomatix ] [015 ] + SW :[XnView ] [015 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt new file mode 100644 index 0000000000..6f20fc1ee8 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/fb.jpg.txt @@ -0,0 +1,525 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\fb.jpg] + Filesize: [15787] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.2] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: COM (Comment) (xFFFE) *** + OFFSET: 0x00000014 + Comment length = 4 + Comment=*. + +*** Marker: APP2 (xFFE2) *** + OFFSET: 0x0000001A + Length = 540 + Identifier = [ICC_PROFILE] + ICC Profile: + Marker Number = 1 of 1 + Profile Size : 524 bytes + Preferred CMM Type : 'lcms' (0x6C636D73) + Profile Version : 0.2.1.0 (0x02100000) + Profile Device/Class : Display Device profile ('mntr' (0x6D6E7472)) + Data Colour Space : rgbData ('RGB ' (0x52474220)) + Profile connection space (PCS) : 'XYZ ' (0x58595A20) + Profile creation date : 2012-01-25 03:41:57 + Profile file signature : 'acsp' (0x61637370) + Primary platform : Apple Computer, Inc. ('APPL' (0x4150504C)) + Profile flags : 0x00000000 + Profile flags > Profile not embedded + Profile flags > Profile can't be used independently of embedded + Device Manufacturer : '....' (0x00000000) + Device Model : '....' (0x00000000) + Device attributes : 0x00000000_00000000 + Device attributes > Reflective + Device attributes > Glossy + Device attributes > Media polarity = negative + Device attributes > Black & white media + Rendering intent : Perceptual + Profile creator : 'lcms' (0x6C636D73) + Profile ID : 0x00000000_00000000_00000000_00000000 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000238 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 8 6 5 8 12 20 26 31 + DQT, Row #1: 6 6 7 10 13 29 30 28 + DQT, Row #2: 7 7 8 12 20 29 35 28 + DQT, Row #3: 7 9 11 15 26 44 40 31 + DQT, Row #4: 9 11 19 28 34 55 52 39 + DQT, Row #5: 12 18 28 32 41 52 57 46 + DQT, Row #6: 25 32 39 44 52 61 60 51 + DQT, Row #7: 36 46 48 49 56 50 52 50 + Approx quality factor = 74.75 (scaling=50.51 variance=0.81) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x0000027D + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 9 9 12 24 50 50 50 50 + DQT, Row #1: 9 11 13 33 50 50 50 50 + DQT, Row #2: 12 13 28 50 50 50 50 50 + DQT, Row #3: 24 33 50 50 50 50 50 50 + DQT, Row #4: 50 50 50 50 50 50 50 50 + DQT, Row #5: 50 50 50 50 50 50 50 50 + DQT, Row #6: 50 50 50 50 50 50 50 50 + DQT, Row #7: 50 50 50 50 50 50 50 50 + Approx quality factor = 74.74 (scaling=50.52 variance=0.19) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x000002C2 + Frame header length = 17 + Precision = 8 + Number of Lines = 336 + Samples per Line = 276 + Image Size = 276 x 336 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x00, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x01, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002D5 + Huffman table length = 27 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 00 02 03 05 06 + Codes of length 04 bits (001 total): 01 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 008 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000002F2 + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 03 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000030C + Huffman table length = 24 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (003 total): 00 01 03 + Codes of length 03 bits (001 total): 02 + Codes of length 04 bits (001 total): 04 + Codes of length 05 bits (000 total): + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 005 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000326 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000935 + Huffman table length = 43 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (002 total): 01 04 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (002 total): 11 12 + Codes of length 06 bits (006 total): 05 10 13 20 31 32 + Codes of length 07 bits (002 total): 21 33 + Codes of length 08 bits (002 total): 14 22 + Codes of length 09 bits (002 total): 34 41 + Codes of length 10 bits (003 total): 15 23 30 + Codes of length 11 bits (001 total): 24 + Codes of length 12 bits (001 total): 42 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 024 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000962 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000012EE + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 10 + Codes of length 05 bits (004 total): 03 20 21 31 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (004 total): 13 30 41 51 + Codes of length 08 bits (001 total): 22 + Codes of length 09 bits (005 total): 32 40 42 50 61 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001317 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000142A + Huffman table length = 36 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (001 total): 10 + Codes of length 05 bits (004 total): 03 20 21 31 + Codes of length 06 bits (002 total): 12 30 + Codes of length 07 bits (002 total): 13 41 + Codes of length 08 bits (003 total): 22 40 51 + Codes of length 09 bits (001 total): 50 + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 017 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001450 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x0000155A + Huffman table length = 51 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (002 total): 00 02 + Codes of length 04 bits (003 total): 03 10 11 + Codes of length 05 bits (006 total): 12 20 21 31 41 51 + Codes of length 06 bits (005 total): 22 32 61 71 81 + Codes of length 07 bits (002 total): 13 30 + Codes of length 08 bits (005 total): 04 33 42 72 91 + Codes of length 09 bits (004 total): 14 52 62 A1 + Codes of length 10 bits (003 total): 23 82 B1 + Codes of length 11 bits (001 total): 43 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 032 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000158F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00001D3E + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 11 21 + Codes of length 04 bits (001 total): 31 + Codes of length 05 bits (003 total): 10 41 51 + Codes of length 06 bits (004 total): 20 61 71 A1 + Codes of length 07 bits (002 total): 81 91 + Codes of length 08 bits (002 total): B1 F0 + Codes of length 09 bits (003 total): 30 C1 D1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00001D68 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000028B9 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x00, table=0(DC),0(AC) + Component[2]: selector=0x01, table=1(DC),1(AC) + Component[3]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000029E4 + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (000 total): + Codes of length 05 bits (003 total): 10 21 31 + Codes of length 06 bits (000 total): + Codes of length 07 bits (003 total): 20 41 51 + Codes of length 08 bits (001 total): 30 + Codes of length 09 bits (001 total): 61 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (001 total): 50 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002A06 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002B55 + Huffman table length = 32 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (003 total): 10 21 31 + Codes of length 05 bits (001 total): 20 + Codes of length 06 bits (001 total): 41 + Codes of length 07 bits (000 total): + Codes of length 08 bits (003 total): 30 51 61 + Codes of length 09 bits (001 total): 71 + Codes of length 10 bits (001 total): 40 + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 013 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002B77 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=1(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002CEA + Huffman table length = 40 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (004 total): 81 91 A1 B1 + Codes of length 08 bits (003 total): 20 C1 F0 + Codes of length 09 bits (001 total): D1 + Codes of length 10 bits (001 total): E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 30 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 021 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00002D14 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x00, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x00003DA9 + + +*** Searching Compression Signatures *** + + Signature: 0182408A81A4ABF04D4A34A8A5E98C58 + Signature (Rotated): 012D821C6AB210E2A753BE053B8F55D0 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[SONY ] [CYBERSHOT U ] [ ] Yes + SW :[Adobe Photoshop 7.0 ] [Save As 07 ] + SW :[Apple Quicktime ] [0466-0467 ] + SW :[Digital Photo Professiona] [05 ] + SW :[IJG Library ] [075 ] + SW :[MS Paint ] [ ] + SW :[MS Visio ] [ ] + SW :[ZoomBrowser EX ] [low ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [075 ] + SW :[IrfanView ] [075 ] + SW :[idImager ] [075 ] + SW :[FastStone Image Viewer ] [075 ] + SW :[NeatImage ] [075 ] + SW :[Paint.NET ] [075 ] + SW :[Photomatix ] [075 ] + SW :[XnView ] [075 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt new file mode 100644 index 0000000000..f38a115328 --- /dev/null +++ b/tests/Images/Input/Jpg/progressive/JpegSnoopReports/progress.jpg.txt @@ -0,0 +1,468 @@ + +JPEGsnoop 1.8.0 by Calvin Hass + http://www.impulseadventure.com/photo/ + ------------------------------------- + + Filename: [.\progress.jpg] + Filesize: [44884] Bytes + +Start Offset: 0x00000000 +*** Marker: SOI (xFFD8) *** + OFFSET: 0x00000000 + +*** Marker: APP0 (xFFE0) *** + OFFSET: 0x00000002 + Length = 16 + Identifier = [JFIF] + version = [1.1] + density = 1 x 1 (aspect ratio) + thumbnail = 0 x 0 + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000014 + Table length = 67 + ---- + Precision=8 bits + Destination ID=0 (Luminance) + DQT, Row #0: 5 3 3 5 7 12 15 18 + DQT, Row #1: 4 4 4 6 8 17 18 17 + DQT, Row #2: 4 4 5 7 12 17 21 17 + DQT, Row #3: 4 5 7 9 15 26 24 19 + DQT, Row #4: 5 7 11 17 20 33 31 23 + DQT, Row #5: 7 11 17 19 24 31 34 28 + DQT, Row #6: 15 19 23 26 31 36 36 30 + DQT, Row #7: 22 28 29 29 34 30 31 30 + Approx quality factor = 84.93 (scaling=30.13 variance=1.05) + +*** Marker: DQT (xFFDB) *** + Define a Quantization Table. + OFFSET: 0x00000059 + Table length = 67 + ---- + Precision=8 bits + Destination ID=1 (Chrominance) + DQT, Row #0: 5 5 7 14 30 30 30 30 + DQT, Row #1: 5 6 8 20 30 30 30 30 + DQT, Row #2: 7 8 17 30 30 30 30 30 + DQT, Row #3: 14 20 30 30 30 30 30 30 + DQT, Row #4: 30 30 30 30 30 30 30 30 + DQT, Row #5: 30 30 30 30 30 30 30 30 + DQT, Row #6: 30 30 30 30 30 30 30 30 + DQT, Row #7: 30 30 30 30 30 30 30 30 + Approx quality factor = 84.93 (scaling=30.15 variance=0.29) + +*** Marker: SOF2 (Progressive DCT, Huffman) (xFFC2) *** + OFFSET: 0x0000009E + Frame header length = 17 + Precision = 8 + Number of Lines = 486 + Samples per Line = 341 + Image Size = 341 x 486 + Raw Image Orientation = Portrait + Number of Img components = 3 + Component[1]: ID=0x01, Samp Fac=0x22 (Subsamp 1 x 1), Quant Tbl Sel=0x00 (Lum: Y) + Component[2]: ID=0x02, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cb) + Component[3]: ID=0x03, Samp Fac=0x11 (Subsamp 2 x 2), Quant Tbl Sel=0x01 (Chrom: Cr) + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000B1 + Huffman table length = 28 + ---- + Destination ID = 0 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 04 + Codes of length 03 bits (005 total): 01 02 03 05 06 + Codes of length 04 bits (001 total): 00 + Codes of length 05 bits (001 total): 07 + Codes of length 06 bits (001 total): 08 + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 009 + + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000000CF + Huffman table length = 26 + ---- + Destination ID = 1 + Class = 0 (DC / Lossless Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 02 03 + Codes of length 03 bits (003 total): 00 01 04 + Codes of length 04 bits (001 total): 05 + Codes of length 05 bits (001 total): 06 + Codes of length 06 bits (000 total): + Codes of length 07 bits (000 total): + Codes of length 08 bits (000 total): + Codes of length 09 bits (000 total): + Codes of length 10 bits (000 total): + Codes of length 11 bits (000 total): + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 007 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000000EB + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=1(DC),0(AC) + Component[3]: selector=0x03, table=1(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00000CCC + Huffman table length = 45 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 01 02 + Codes of length 03 bits (002 total): 00 03 + Codes of length 04 bits (002 total): 04 11 + Codes of length 05 bits (001 total): 12 + Codes of length 06 bits (003 total): 05 13 21 + Codes of length 07 bits (003 total): 10 22 31 + Codes of length 08 bits (004 total): 14 20 32 41 + Codes of length 09 bits (002 total): 06 23 + Codes of length 10 bits (002 total): 30 33 + Codes of length 11 bits (003 total): 15 24 42 + Codes of length 12 bits (001 total): 34 + Codes of length 13 bits (001 total): 43 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 026 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00000CFB + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 5 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000020DC + Huffman table length = 46 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 03 + Codes of length 04 bits (001 total): 11 + Codes of length 05 bits (004 total): 04 10 21 31 + Codes of length 06 bits (001 total): 12 + Codes of length 07 bits (003 total): 13 20 41 + Codes of length 08 bits (003 total): 05 22 51 + Codes of length 09 bits (003 total): 23 32 61 + Codes of length 10 bits (005 total): 14 30 33 42 71 + Codes of length 11 bits (000 total): + Codes of length 12 bits (003 total): 15 52 91 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 027 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000210C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00002604 + Huffman table length = 41 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (002 total): 00 01 + Codes of length 03 bits (002 total): 02 11 + Codes of length 04 bits (002 total): 03 10 + Codes of length 05 bits (002 total): 21 31 + Codes of length 06 bits (002 total): 12 20 + Codes of length 07 bits (001 total): 13 + Codes of length 08 bits (004 total): 04 22 41 61 + Codes of length 09 bits (002 total): 42 51 + Codes of length 10 bits (002 total): 14 32 + Codes of length 11 bits (003 total): 33 71 F0 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 022 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000262F + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x01 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000029A7 + Huffman table length = 61 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (000 total): + Codes of length 02 bits (001 total): 01 + Codes of length 03 bits (003 total): 00 02 11 + Codes of length 04 bits (003 total): 03 12 21 + Codes of length 05 bits (001 total): 31 + Codes of length 06 bits (005 total): 10 22 41 51 61 + Codes of length 07 bits (006 total): 04 13 20 32 71 81 + Codes of length 08 bits (005 total): 23 30 42 52 91 + Codes of length 09 bits (002 total): A1 B1 + Codes of length 10 bits (004 total): 62 72 C1 F0 + Codes of length 11 bits (006 total): 14 33 40 82 D1 E1 + Codes of length 12 bits (001 total): 24 + Codes of length 13 bits (005 total): 05 43 53 73 F1 + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 042 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000029E6 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 6 .. 63 + Successive approximation = 0x02 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00003FF3 + Huffman table length = 39 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (002 total): 21 31 + Codes of length 05 bits (002 total): 41 51 + Codes of length 06 bits (001 total): 61 + Codes of length 07 bits (003 total): 71 81 91 + Codes of length 08 bits (004 total): 10 A1 B1 C1 + Codes of length 09 bits (003 total): D1 E1 F0 + Codes of length 10 bits (001 total): 20 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x0000401C + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x21 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006299 + Scan header length = 12 + Number of img components = 3 + Component[1]: selector=0x01, table=0(DC),0(AC) + Component[2]: selector=0x02, table=0(DC),0(AC) + Component[3]: selector=0x03, table=0(DC),0(AC) + Spectral selection = 0 .. 0 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x000064A9 + Huffman table length = 39 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (000 total): + Codes of length 03 bits (002 total): 00 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (003 total): 31 41 51 + Codes of length 06 bits (003 total): 10 61 71 + Codes of length 07 bits (004 total): 81 91 D1 F0 + Codes of length 08 bits (003 total): A1 B1 E1 + Codes of length 09 bits (001 total): C1 + Codes of length 10 bits (001 total): F1 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (000 total): + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 020 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x000064D2 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x03, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006ACB + Huffman table length = 38 + ---- + Destination ID = 1 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 00 + Codes of length 03 bits (001 total): 11 + Codes of length 04 bits (001 total): 21 + Codes of length 05 bits (000 total): + Codes of length 06 bits (002 total): 31 41 + Codes of length 07 bits (002 total): 10 51 + Codes of length 08 bits (001 total): 61 + Codes of length 09 bits (003 total): 91 D1 F0 + Codes of length 10 bits (005 total): 71 81 A1 B1 C1 + Codes of length 11 bits (001 total): 20 + Codes of length 12 bits (001 total): E1 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006AF3 + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x02, table=0(DC),1(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: DHT (Define Huffman Table) (xFFC4) *** + OFFSET: 0x00006F95 + Huffman table length = 38 + ---- + Destination ID = 0 + Class = 1 (AC Table) + Codes of length 01 bits (001 total): 01 + Codes of length 02 bits (001 total): 11 + Codes of length 03 bits (000 total): + Codes of length 04 bits (002 total): 00 21 + Codes of length 05 bits (002 total): 31 41 + Codes of length 06 bits (002 total): 51 61 + Codes of length 07 bits (002 total): 71 81 + Codes of length 08 bits (002 total): 91 A1 + Codes of length 09 bits (002 total): B1 F0 + Codes of length 10 bits (003 total): C1 D1 E1 + Codes of length 11 bits (001 total): F1 + Codes of length 12 bits (001 total): 10 + Codes of length 13 bits (000 total): + Codes of length 14 bits (000 total): + Codes of length 15 bits (000 total): + Codes of length 16 bits (000 total): + Total number of codes: 019 + + +*** Marker: SOS (Start of Scan) (xFFDA) *** + OFFSET: 0x00006FBD + Scan header length = 8 + Number of img components = 1 + Component[1]: selector=0x01, table=0(DC),0(AC) + Spectral selection = 1 .. 63 + Successive approximation = 0x10 + + NOTE: Scan parsing doesn't support this SOF mode. + +*** Marker: EOI (End of Image) (xFFD9) *** + OFFSET: 0x0000AF52 + + +*** Searching Compression Signatures *** + + Signature: 0155D875C95B74D0F3C5835A62516F48 + Signature (Rotated): 01D38A25358EB7649A254E19F1D46600 + File Offset: 0 bytes + Chroma subsampling: 2x2 + EXIF Make/Model: NONE + EXIF Makernotes: NONE + EXIF Software: NONE + + Searching Compression Signatures: (3347 built-in, 0 user(*) ) + + EXIF.Make / Software EXIF.Model Quality Subsamp Match? + ------------------------- ----------------------------------- ---------------- -------------- + CAM:[NIKON ] [E2500 ] [FINE ] No + CAM:[Nokia ] [N73 ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C2000Z ] [ ] No + CAM:[OLYMPUS OPTICAL CO.,LTD ] [C3040Z ] [ ] No + CAM:[PENTAX ] [PENTAX Optio 550 ] [ ] No + CAM:[Research In Motion ] [BlackBerry 8100 ] [ ] No + CAM:[SEIKO EPSON CORP. ] [PhotoPC 3000Z ] [ ] No + SW :[IJG Library ] [085 ] + SW :[Picasa ] [085 (Normal) ] + SW :[ZoomBrowser EX ] [medium ] + + The following IJG-based editors also match this signature: + SW :[GIMP ] [085 ] + SW :[IrfanView ] [085 ] + SW :[idImager ] [085 ] + SW :[FastStone Image Viewer ] [085 ] + SW :[NeatImage ] [085 ] + SW :[Paint.NET ] [085 ] + SW :[Photomatix ] [085 ] + SW :[XnView ] [085 ] + + Based on the analysis of compression characteristics and EXIF metadata: + + ASSESSMENT: Class 1 - Image is processed/edited + + This may be a new software editor for the database. + If this file is processed, and editor doesn't appear in list above, + PLEASE ADD TO DATABASE with [Tools->Add Camera to DB] + diff --git a/tests/Images/Input/Png/gray-1-trns.png b/tests/Images/Input/Png/gray-1-trns.png new file mode 100644 index 0000000000..99b288d526 Binary files /dev/null and b/tests/Images/Input/Png/gray-1-trns.png differ diff --git a/tests/Images/Input/Png/gray-2-tRNS.png b/tests/Images/Input/Png/gray-2-tRNS.png new file mode 100644 index 0000000000..8e04cb5020 Binary files /dev/null and b/tests/Images/Input/Png/gray-2-tRNS.png differ diff --git a/tests/Images/Input/Png/gray-4-tRNS.png b/tests/Images/Input/Png/gray-4-tRNS.png new file mode 100644 index 0000000000..14c4f1fb3a Binary files /dev/null and b/tests/Images/Input/Png/gray-4-tRNS.png differ diff --git a/tests/Images/Input/Png/gray-8-tRNS.png b/tests/Images/Input/Png/gray-8-tRNS.png new file mode 100644 index 0000000000..842245f1d9 Binary files /dev/null and b/tests/Images/Input/Png/gray-8-tRNS.png differ