Browse Source

Merge branch 'sw/github-actions' of https://github.com/SixLabors/ImageSharp into sw/github-actions

af/merge-core
James Jackson-South 6 years ago
parent
commit
a2fff3d35a
  1. 10
      .gitattributes
  2. 34
      Directory.Build.props
  3. 2
      shared-infrastructure
  4. 10
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  5. 16
      src/ImageSharp.Drawing/Processing/BrushApplicator.cs
  6. 68
      src/ImageSharp.Drawing/Processing/PathGradientBrush.cs
  7. 2
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs
  8. 6
      src/ImageSharp/Common/Extensions/EncoderExtensions.cs
  9. 47
      src/ImageSharp/Common/Extensions/StreamExtensions.cs
  10. 20
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  11. 4
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  12. 8
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  13. 11
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
  14. 2
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  15. 5
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  16. 4
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  17. 18
      src/ImageSharp/ImageSharp.csproj
  18. 16
      tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
  19. 5
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs
  20. 1
      tests/ImageSharp.Tests/TestImages.cs
  21. 2
      tests/Images/External
  22. 3
      tests/Images/Input/Jpg/issues/issue-1076-invalid-subsampling.jpg

10
.gitattributes

@ -64,13 +64,20 @@
# treat as binary # treat as binary
*.bmp binary *.bmp binary
*.dll binary *.dll binary
*.eot binary
*.exe binary *.exe binary
*.gif binary *.gif binary
*.jpg binary *.jpg binary
*.pdf binary
*.png binary *.png binary
*.tga binary *.ppt binary
*.pptx binary
*.ttf binary *.ttf binary
*.snk binary *.snk binary
*.woff binary
*.woff2 binary
*.xls binary
*.xlsx binary
# diff as plain text # diff as plain text
*.doc diff=astextplain *.doc diff=astextplain
*.docx diff=astextplain *.docx diff=astextplain
@ -78,6 +85,7 @@
*.pdf diff=astextplain *.pdf diff=astextplain
*.pptx diff=astextplain *.pptx diff=astextplain
*.rtf diff=astextplain *.rtf diff=astextplain
*.svg diff=astextplain
*.jpg filter=lfs diff=lfs merge=lfs -text *.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text *.jpeg filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text *.bmp filter=lfs diff=lfs merge=lfs -text

34
Directory.Build.props

@ -29,10 +29,42 @@
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage> <SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
</PropertyGroup> </PropertyGroup>
<!--
https://apisof.net/
+===================+================+===================+==============================+======================+==========================+
| Target Framework | SUPPORTS_MATHF | SUPPORTS_HASHCODE | SUPPORTS_EXTENDED_INTRINSICS | SUPPORTS_SPAN_STREAM | SUPPORTS_ENCODING_STRING |
+===================+================+===================+==============================+======================+==========================+
| netcoreapp3.1 | Y | Y | Y | Y | Y |
| netcoreapp2.1 | Y | Y | Y | Y | Y |
| netcoreapp2.0 | Y | N | N | N | N |
| netstandard2.1 | Y | N | N | Y | Y |
| netstandard2.0 | N | N | N | N | N |
| netstandard1.3 | N | N | N | N | N |
| net472 | N | N | Y | N | N |
+===================+================+===================+==============================+======================+==========================+
-->
<!-- TODO: Include additional targets to TargetFrameworks -->
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_HASHCODE;SUPPORTS_EXTENDED_INTRINSICS;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.1'">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF;SUPPORTS_SPAN_STREAM;SUPPORTS_ENCODING_STRING</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'net472'">
<DefineConstants>$(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> <PropertyGroup Condition="'$(Configuration)' == 'Release'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup> </PropertyGroup>
<!--TODO: Check what this is testing for and why does it fail?--> <!--TODO: Check what this is testing for and why does it fail?-->
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>

2
shared-infrastructure

@ -1 +1 @@
Subproject commit faf84e44ec90e8a42a7271bcd04fea76279efb08 Subproject commit c2e689abe9227209e6d5bc4bf56255d92b4a5d62

10
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -8,18 +8,10 @@
<PackageId>SixLabors.ImageSharp.Drawing</PackageId> <PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags> <PackageTags>Image Draw Shape Path Font</PackageTags>
<RootNamespace>SixLabors.ImageSharp</RootNamespace> <RootNamespace>SixLabors.ImageSharp</RootNamespace>
<TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
</PropertyGroup>
<!-- TODO: Include .NETSTANDARD2.1 when released--> <TargetFrameworks>netcoreapp2.1;netstandard2.0;netstandard1.3</TargetFrameworks>
<PropertyGroup Condition=" $(TargetFramework.StartsWith('netcoreapp2')) ">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF</DefineConstants>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" $(TargetFramework.StartsWith('netcoreapp2.1')) ">
<DefineConstants>$(DefineConstants);SUPPORTS_HASHCODE</DefineConstants>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SixLabors.Fonts" /> <PackageReference Include="SixLabors.Fonts" />
<PackageReference Include="SixLabors.Shapes" /> <PackageReference Include="SixLabors.Shapes" />

16
src/ImageSharp.Drawing/Processing/BrushApplicator.cs

@ -90,19 +90,23 @@ namespace SixLabors.ImageSharp.Processing
{ {
Span<float> amountSpan = amountBuffer.Memory.Span; Span<float> amountSpan = amountBuffer.Memory.Span;
Span<TPixel> overlaySpan = overlay.Memory.Span; Span<TPixel> overlaySpan = overlay.Memory.Span;
float blendPercentage = this.Options.BlendPercentage;
for (int i = 0; i < scanline.Length; i++) if (blendPercentage < 1)
{ {
if (this.Options.BlendPercentage < 1) for (int i = 0; i < scanline.Length; i++)
{ {
amountSpan[i] = scanline[i] * this.Options.BlendPercentage; amountSpan[i] = scanline[i] * blendPercentage;
overlaySpan[i] = this[x + i, y];
} }
else }
else
{
for (int i = 0; i < scanline.Length; i++)
{ {
amountSpan[i] = scanline[i]; amountSpan[i] = scanline[i];
overlaySpan[i] = this[x + i, y];
} }
overlaySpan[i] = this[x + i, y];
} }
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);

68
src/ImageSharp.Drawing/Processing/PathGradientBrush.cs

@ -2,11 +2,13 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
using SixLabors.Primitives; using SixLabors.Primitives;
using SixLabors.Shapes; using SixLabors.Shapes;
@ -47,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing
throw new ArgumentNullException(nameof(colors)); throw new ArgumentNullException(nameof(colors));
} }
if (!colors.Any()) if (colors.Length == 0)
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
nameof(colors), nameof(colors),
@ -99,7 +101,7 @@ namespace SixLabors.ImageSharp.Processing
throw new ArgumentNullException(nameof(colors)); throw new ArgumentNullException(nameof(colors));
} }
if (!colors.Any()) if (colors.Length == 0)
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
nameof(colors), nameof(colors),
@ -133,22 +135,19 @@ namespace SixLabors.ImageSharp.Processing
private readonly float length; private readonly float length;
private readonly PointF[] buffer;
public Edge(Path path, Color startColor, Color endColor) public Edge(Path path, Color startColor, Color endColor)
{ {
this.path = path; this.path = path;
Vector2[] points = path.LineSegments.SelectMany(s => s.Flatten()).Select(p => (Vector2)p).ToArray(); Vector2[] points = path.LineSegments.SelectMany(s => s.Flatten()).Select(p => (Vector2)p).ToArray();
this.Start = points.First(); this.Start = points[0];
this.StartColor = (Vector4)startColor; this.StartColor = (Vector4)startColor;
this.End = points.Last(); this.End = points.Last();
this.EndColor = (Vector4)endColor; this.EndColor = (Vector4)endColor;
this.length = DistanceBetween(this.End, this.Start); this.length = DistanceBetween(this.End, this.Start);
this.buffer = new PointF[this.path.MaxIntersections];
} }
public PointF Start { get; } public PointF Start { get; }
@ -159,18 +158,38 @@ namespace SixLabors.ImageSharp.Processing
public Vector4 EndColor { get; } public Vector4 EndColor { get; }
public Intersection? FindIntersection(PointF start, PointF end) public Intersection? FindIntersection(PointF start, PointF end, MemoryAllocator allocator)
{ {
int intersections = this.path.FindIntersections(start, end, this.buffer); // TODO: The number of max intersections is upper bound to the number of nodes of the path.
// Normally these numbers would be small and could potentially be stackalloc rather than pooled.
if (intersections == 0) // Investigate performance beifit of checking length and choosing approach.
using (IMemoryOwner<PointF> memory = allocator.Allocate<PointF>(this.path.MaxIntersections))
{ {
return null; Span<PointF> buffer = memory.Memory.Span;
} int intersections = this.path.FindIntersections(start, end, buffer);
if (intersections == 0)
{
return null;
}
buffer = buffer.Slice(0, intersections);
PointF minPoint = buffer[0];
var min = new Intersection(minPoint, ((Vector2)(minPoint - start)).LengthSquared());
for (int i = 1; i < buffer.Length; i++)
{
PointF point = buffer[i];
var current = new Intersection(point, ((Vector2)(point - start)).LengthSquared());
return this.buffer.Take(intersections) if (min.Distance > current.Distance)
.Select(p => new Intersection(point: p, distance: ((Vector2)(p - start)).LengthSquared())) {
.Aggregate((min, current) => min.Distance > current.Distance ? current : min); min = current;
}
}
return min;
}
} }
public Vector4 ColorAt(float distance) public Vector4 ColorAt(float distance)
@ -197,6 +216,10 @@ namespace SixLabors.ImageSharp.Processing
private readonly IList<Edge> edges; private readonly IList<Edge> edges;
private readonly TPixel centerPixel;
private readonly TPixel transparentPixel;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PathGradientBrushApplicator{TPixel}"/> class. /// Initializes a new instance of the <see cref="PathGradientBrushApplicator{TPixel}"/> class.
/// </summary> /// </summary>
@ -214,13 +237,15 @@ namespace SixLabors.ImageSharp.Processing
: base(configuration, options, source) : base(configuration, options, source)
{ {
this.edges = edges; this.edges = edges;
PointF[] points = edges.Select(s => s.Start).ToArray(); PointF[] points = edges.Select(s => s.Start).ToArray();
this.center = points.Aggregate((p1, p2) => p1 + p2) / edges.Count; this.center = points.Aggregate((p1, p2) => p1 + p2) / edges.Count;
this.centerColor = (Vector4)centerColor; this.centerColor = (Vector4)centerColor;
this.centerPixel = centerColor.ToPixel<TPixel>();
this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Max(d => d.Length());
this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Select(d => d.Length()).Max(); this.transparentPixel = Color.Transparent.ToPixel<TPixel>();
} }
/// <inheritdoc /> /// <inheritdoc />
@ -232,22 +257,20 @@ namespace SixLabors.ImageSharp.Processing
if (point == this.center) if (point == this.center)
{ {
return new Color(this.centerColor).ToPixel<TPixel>(); return this.centerPixel;
} }
var direction = Vector2.Normalize(point - this.center); var direction = Vector2.Normalize(point - this.center);
PointF end = point + (PointF)(direction * this.maxDistance); PointF end = point + (PointF)(direction * this.maxDistance);
(Edge edge, Intersection? info) = this.FindIntersection(point, end); (Edge edge, Intersection? info) = this.FindIntersection(point, end);
if (!info.HasValue) if (!info.HasValue)
{ {
return Color.Transparent.ToPixel<TPixel>(); return this.transparentPixel;
} }
PointF intersection = info.Value.Point; PointF intersection = info.Value.Point;
Vector4 edgeColor = edge.ColorAt(intersection); Vector4 edgeColor = edge.ColorAt(intersection);
float length = DistanceBetween(intersection, this.center); float length = DistanceBetween(intersection, this.center);
@ -263,9 +286,10 @@ namespace SixLabors.ImageSharp.Processing
{ {
(Edge edge, Intersection? info) closest = default; (Edge edge, Intersection? info) closest = default;
MemoryAllocator allocator = this.Target.MemoryAllocator;
foreach (Edge edge in this.edges) foreach (Edge edge in this.edges)
{ {
Intersection? intersection = edge.FindIntersection(start, end); Intersection? intersection = edge.FindIntersection(start, end, allocator);
if (!intersection.HasValue) if (!intersection.HasValue)
{ {

2
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs

@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
source, source,
sourceRectangle)) sourceRectangle))
{ {
amount.Memory.Span.Fill(1f); amount.Memory.Span.Fill(1F);
ParallelHelper.IterateRows( ParallelHelper.IterateRows(
workingRect, workingRect,

6
src/ImageSharp/Common/Extensions/EncoderExtensions.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
#if !NETCOREAPP2_1 #if !SUPPORTS_ENCODING_STRING
using System; using System;
using System.Text; using System.Text;
@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp
} }
} }
} }
#endif #endif

47
src/ImageSharp/Common/Extensions/StreamExtensions.cs

@ -4,7 +4,6 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.Memory; using SixLabors.Memory;
@ -15,7 +14,6 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
internal static class StreamExtensions internal static class StreamExtensions
{ {
#if NETCOREAPP2_1
/// <summary> /// <summary>
/// Writes data from a stream into the provided buffer. /// Writes data from a stream into the provided buffer.
/// </summary> /// </summary>
@ -24,23 +22,18 @@ namespace SixLabors.ImageSharp
/// <param name="offset">The offset within the buffer to begin writing.</param> /// <param name="offset">The offset within the buffer to begin writing.</param>
/// <param name="count">The number of bytes to write to the stream.</param> /// <param name="count">The number of bytes to write to the stream.</param>
public static void Write(this Stream stream, Span<byte> buffer, int offset, int count) public static void Write(this Stream stream, Span<byte> buffer, int offset, int count)
{ => stream.Write(buffer.Slice(offset, count));
stream.Write(buffer.Slice(offset, count));
}
/// <summary> /// <summary>
/// Reads data from a stream into the provided buffer. /// Reads data from a stream into the provided buffer.
/// </summary> /// </summary>
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
/// <param name="buffer">The buffer..</param> /// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset within the buffer where the bytes are read into.</param> /// <param name="offset">The offset within the buffer where the bytes are read into.</param>
/// <param name="count">The number of bytes, if available, to read.</param> /// <param name="count">The number of bytes, if available, to read.</param>
/// <returns>The actual number of bytes read.</returns> /// <returns>The actual number of bytes read.</returns>
public static int Read(this Stream stream, Span<byte> buffer, int offset, int count) public static int Read(this Stream stream, Span<byte> buffer, int offset, int count)
{ => stream.Read(buffer.Slice(offset, count));
return stream.Read(buffer.Slice(offset, count));
}
#endif
/// <summary> /// <summary>
/// Skips the number of bytes in the given stream. /// Skips the number of bytes in the given stream.
@ -75,17 +68,39 @@ namespace SixLabors.ImageSharp
} }
public static void Read(this Stream stream, IManagedByteBuffer buffer) public static void Read(this Stream stream, IManagedByteBuffer buffer)
{ => stream.Read(buffer.Array, 0, buffer.Length());
stream.Read(buffer.Array, 0, buffer.Length());
}
public static void Write(this Stream stream, IManagedByteBuffer buffer) public static void Write(this Stream stream, IManagedByteBuffer buffer)
=> stream.Write(buffer.Array, 0, buffer.Length());
#if !SUPPORTS_SPAN_STREAM
// This is a port of the CoreFX implementation and is MIT Licensed:
// https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L742
public static int Read(this Stream stream, Span<byte> buffer)
{ {
stream.Write(buffer.Array, 0, buffer.Length()); // This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator,
// in order to match the signature of the framework method that exists in
// .NET Core.
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
int numRead = stream.Read(sharedBuffer, 0, buffer.Length);
if ((uint)numRead > (uint)buffer.Length)
{
throw new IOException("Stream was too long.");
}
new Span<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
return numRead;
}
finally
{
ArrayPool<byte>.Shared.Return(sharedBuffer);
}
} }
#if NET472 || NETSTANDARD1_3 || NETSTANDARD2_0 // This is a port of the CoreFX implementation and is MIT Licensed:
// This is a port of the CoreFX implementation and is MIT Licensed: https://github.com/dotnet/coreclr/blob/c4dca1072d15bdda64c754ad1ea474b1580fa554/src/System.Private.CoreLib/shared/System/IO/Stream.cs#L770 // https://github.com/dotnet/corefx/blob/17300169760c61a90cab8d913636c1058a30a8c1/src/Common/src/CoreLib/System/IO/Stream.cs#L775
public static void Write(this Stream stream, ReadOnlySpan<byte> buffer) public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
{ {
// This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator, // This uses ArrayPool<byte>.Shared, rather than taking a MemoryAllocator,

20
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -445,11 +445,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param> /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle4(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels) private void UncompressRle4(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{ {
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2]; Span<byte> cmd = stackalloc byte[2];
#else
var cmd = new byte[2];
#endif
int count = 0; int count = 0;
while (count < buffer.Length) while (count < buffer.Length)
@ -556,11 +552,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param> /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle8(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels) private void UncompressRle8(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{ {
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2]; Span<byte> cmd = stackalloc byte[2];
#else
var cmd = new byte[2];
#endif
int count = 0; int count = 0;
while (count < buffer.Length) while (count < buffer.Length)
@ -639,11 +631,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param> /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle24(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels) private void UncompressRle24(int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{ {
#if NETCOREAPP2_1
Span<byte> cmd = stackalloc byte[2]; Span<byte> cmd = stackalloc byte[2];
#else
var cmd = new byte[2];
#endif
int uncompressedPixels = 0; int uncompressedPixels = 0;
while (uncompressedPixels < buffer.Length) while (uncompressedPixels < buffer.Length)
@ -1213,11 +1201,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary> /// </summary>
private void ReadInfoHeader() private void ReadInfoHeader()
{ {
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[BmpInfoHeader.MaxHeaderSize]; Span<byte> buffer = stackalloc byte[BmpInfoHeader.MaxHeaderSize];
#else
var buffer = new byte[BmpInfoHeader.MaxHeaderSize];
#endif
// Read the header size. // Read the header size.
this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize); this.stream.Read(buffer, 0, BmpInfoHeader.HeaderSizeSize);
@ -1339,11 +1323,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
/// </summary> /// </summary>
private void ReadFileHeader() private void ReadFileHeader()
{ {
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[BmpFileHeader.Size]; Span<byte> buffer = stackalloc byte[BmpFileHeader.Size];
#else
var buffer = new byte[BmpFileHeader.Size];
#endif
this.stream.Read(buffer, 0, BmpFileHeader.Size); this.stream.Read(buffer, 0, BmpFileHeader.Size);
short fileTypeMarker = BinaryPrimitives.ReadInt16LittleEndian(buffer); short fileTypeMarker = BinaryPrimitives.ReadInt16LittleEndian(buffer);

4
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -173,11 +173,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
reserved: 0, reserved: 0,
offset: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize); offset: BmpFileHeader.Size + infoHeaderSize + colorPaletteSize);
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[infoHeaderSize]; Span<byte> buffer = stackalloc byte[infoHeaderSize];
#else
var buffer = new byte[infoHeaderSize];
#endif
fileHeader.WriteTo(buffer); fileHeader.WriteTo(buffer);
stream.Write(buffer, 0, BmpFileHeader.Size); stream.Write(buffer, 0, BmpFileHeader.Size);

8
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -113,11 +113,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
Unsafe.Add(ref suffixRef, code) = (byte)code; Unsafe.Add(ref suffixRef, code) = (byte)code;
} }
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[255]; Span<byte> buffer = stackalloc byte[255];
#else
var buffer = new byte[255];
#endif
while (xyz < length) while (xyz < length)
{ {
@ -227,11 +223,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The <see cref="int"/>. /// The <see cref="int"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
#if NETCOREAPP2_1
private int ReadBlock(Span<byte> buffer) private int ReadBlock(Span<byte> buffer)
#else
private int ReadBlock(byte[] buffer)
#endif
{ {
int bufferSize = this.stream.ReadByte(); int bufferSize = this.stream.ReadByte();

11
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -22,11 +22,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.Frame = frame; this.Frame = frame;
this.Id = id; this.Id = id;
// Valid sampling factors are 1..2 // Validate sampling factors.
if (horizontalFactor == 0 if (horizontalFactor == 0 || verticalFactor == 0)
|| verticalFactor == 0
|| horizontalFactor > 2
|| verticalFactor > 2)
{ {
JpegThrowHelper.ThrowBadSampling(); JpegThrowHelper.ThrowBadSampling();
} }
@ -138,4 +135,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.SpectralBlocks = this.memoryAllocator.Allocate2D<Block8x8>(width, height, AllocationOptions.Clean); this.SpectralBlocks = this.memoryAllocator.Allocate2D<Block8x8>(width, height, AllocationOptions.Clean);
} }
} }
} }

2
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -764,7 +764,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
for (int i = 0; i < this.ComponentCount; i++) for (int i = 0; i < this.ComponentCount; i++)
{ {
byte hv = this.temp[index + 1]; byte hv = this.temp[index + 1];
int h = hv >> 4; int h = (hv >> 4) & 15;
int v = hv & 15; int v = hv & 15;
if (maxH < h) if (maxH < h)

5
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -565,11 +565,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
{ {
this.currentStream = stream; this.currentStream = stream;
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[TgaFileHeader.Size]; Span<byte> buffer = stackalloc byte[TgaFileHeader.Size];
#else
var buffer = new byte[TgaFileHeader.Size];
#endif
this.currentStream.Read(buffer, 0, TgaFileHeader.Size); this.currentStream.Read(buffer, 0, TgaFileHeader.Size);
this.fileHeader = TgaFileHeader.Parse(buffer); this.fileHeader = TgaFileHeader.Parse(buffer);
this.metadata = new ImageMetadata(); this.metadata = new ImageMetadata();

4
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -97,11 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
pixelDepth: (byte)this.bitsPerPixel.Value, pixelDepth: (byte)this.bitsPerPixel.Value,
imageDescriptor: imageDescriptor); imageDescriptor: imageDescriptor);
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[TgaFileHeader.Size]; Span<byte> buffer = stackalloc byte[TgaFileHeader.Size];
#else
byte[] buffer = new byte[TgaFileHeader.Size];
#endif
fileHeader.WriteTo(buffer); fileHeader.WriteTo(buffer);
stream.Write(buffer, 0, TgaFileHeader.Size); stream.Write(buffer, 0, TgaFileHeader.Size);

18
src/ImageSharp/ImageSharp.csproj

@ -12,6 +12,7 @@
<TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;netstandard1.3;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="$(skipFullFramework) != 'true'">$(TargetFrameworks);net472</TargetFrameworks> <TargetFrameworks Condition="$(skipFullFramework) != 'true'">$(TargetFrameworks);net472</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;netstandard2.0;netstandard1.3;net472</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
@ -20,23 +21,6 @@
<RootNamespace>SixLabors.ImageSharp</RootNamespace> <RootNamespace>SixLabors.ImageSharp</RootNamespace>
</PropertyGroup> </PropertyGroup>
<!-- TODO: Include .NETSTANDARD2.1 when released-->
<PropertyGroup Condition=" $(TargetFramework.StartsWith('netcoreapp2')) ">
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" $(TargetFramework.StartsWith('netcoreapp2.1')) ">
<DefineConstants>$(DefineConstants);SUPPORTS_HASHCODE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' OR '$(TargetFramework)' == 'net472' ">
<DefineConstants>$(DefineConstants);SUPPORTS_EXTENDED_INTRINSICS</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\shared-infrastructure\**\*.cs" /> <Compile Include="..\..\shared-infrastructure\**\*.cs" />
</ItemGroup> </ItemGroup>

16
tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs

@ -433,5 +433,21 @@ namespace SixLabors.ImageSharp.Tests.Drawing
} }
} }
[Theory]
[WithBlankImages(200, 200, PixelTypes.Rgb24)]
public void BrushApplicatorIsThreadSafeIssue1044<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
provider.VerifyOperation(
TolerantComparer,
img =>
{
var brush = new PathGradientBrush(
new[] { new PointF(0, 0), new PointF(200, 0), new PointF(200, 200), new PointF(0, 200), new PointF(0, 0) },
new[] { Color.Red, Color.Yellow, Color.Green, Color.DarkCyan, Color.Red });
img.Mutate(m => m.Fill(brush));
}, false, false);
}
} }
} }

5
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs

@ -31,6 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Issues.InvalidAPP0721, TestImages.Jpeg.Issues.InvalidAPP0721,
TestImages.Jpeg.Issues.ExifGetString750Load, TestImages.Jpeg.Issues.ExifGetString750Load,
TestImages.Jpeg.Issues.ExifGetString750Transform, TestImages.Jpeg.Issues.ExifGetString750Transform,
TestImages.Jpeg.Issues.BadSubSampling1076,
// LibJpeg can open this despite the invalid density units. // LibJpeg can open this despite the invalid density units.
TestImages.Jpeg.Issues.Fuzz.ArgumentOutOfRangeException825B, TestImages.Jpeg.Issues.Fuzz.ArgumentOutOfRangeException825B,
@ -38,6 +39,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
// LibJpeg can open this despite incorrect colorspace metadata. // LibJpeg can open this despite incorrect colorspace metadata.
TestImages.Jpeg.Issues.IncorrectColorspace855, TestImages.Jpeg.Issues.IncorrectColorspace855,
// LibJpeg can open this despite the invalid subsampling units.
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824C,
// High depth images // High depth images
TestImages.Jpeg.Baseline.Testorig12bit, TestImages.Jpeg.Baseline.Testorig12bit,
}; };
@ -71,7 +75,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Issues.Fuzz.NullReferenceException823, TestImages.Jpeg.Issues.Fuzz.NullReferenceException823,
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824A, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824A,
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824B, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824B,
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824C,
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824D, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824D,
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824E, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824E,
TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824F, TestImages.Jpeg.Issues.Fuzz.IndexOutOfRangeException824F,

1
tests/ImageSharp.Tests/TestImages.cs

@ -192,6 +192,7 @@ namespace SixLabors.ImageSharp.Tests
public const string IncorrectColorspace855 = "Jpg/issues/issue855-incorrect-colorspace.jpg"; public const string IncorrectColorspace855 = "Jpg/issues/issue855-incorrect-colorspace.jpg";
public const string IncorrectResize1006 = "Jpg/issues/issue1006-incorrect-resize.jpg"; public const string IncorrectResize1006 = "Jpg/issues/issue1006-incorrect-resize.jpg";
public const string ExifResize1049 = "Jpg/issues/issue1049-exif-resize.jpg"; public const string ExifResize1049 = "Jpg/issues/issue1049-exif-resize.jpg";
public const string BadSubSampling1076 = "Jpg/issues/issue-1076-invalid-subsampling.jpg";
public static class Fuzz public static class Fuzz
{ {

2
tests/Images/External

@ -1 +1 @@
Subproject commit d8ea82085ac39a6aa6ca8e0806a9518d3a7d3337 Subproject commit fbba5e2a78aa479c0752dc0fd91ec25b4948704a

3
tests/Images/Input/Jpg/issues/issue-1076-invalid-subsampling.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1507746a6c37697cb985fc7427709fd68478ff7cbdfe20f6cfbe7257ed6c7ccd
size 39149
Loading…
Cancel
Save