Skip to content

Commit 8c36d8c

Browse files
Merge branch 'main' into sw/rich-text
2 parents 806d0ab + 66cac83 commit 8c36d8c

13 files changed

Lines changed: 243 additions & 30 deletions

File tree

.github/dependabot.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"

.github/workflows/build-and-test.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ jobs:
5050
git config --global core.longpaths true
5151
5252
- name: Git Checkout
53-
uses: actions/checkout@v2
53+
uses: actions/checkout@v3
5454
with:
5555
fetch-depth: 0
5656
submodules: recursive
@@ -60,7 +60,7 @@ jobs:
6060
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
6161

6262
- name: Git Setup LFS Cache
63-
uses: actions/cache@v2
63+
uses: actions/cache@v3
6464
id: lfs-cache
6565
with:
6666
path: .git/lfs
@@ -73,15 +73,15 @@ jobs:
7373
uses: NuGet/setup-nuget@v1
7474

7575
- name: NuGet Setup Cache
76-
uses: actions/cache@v2
76+
uses: actions/cache@v3
7777
id: nuget-cache
7878
with:
7979
path: ~/.nuget
8080
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
8181
restore-keys: ${{ runner.os }}-nuget-
8282

8383
- name: DotNet Setup
84-
uses: actions/setup-dotnet@v1
84+
uses: actions/setup-dotnet@v3
8585
with:
8686
dotnet-version: |
8787
6.0.x
@@ -103,14 +103,14 @@ jobs:
103103
XUNIT_PATH: .\tests\ImageSharp.Drawing.Tests # Required for xunit
104104

105105
- name: Export Failed Output
106-
uses: actions/upload-artifact@v2
106+
uses: actions/upload-artifact@v3
107107
if: failure()
108108
with:
109109
name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
110110
path: tests/Images/ActualOutput/
111111

112112
- name: Codecov Update
113-
uses: codecov/codecov-action@v1
113+
uses: codecov/codecov-action@v3
114114
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
115115
with:
116116
flags: unittests
@@ -130,7 +130,7 @@ jobs:
130130
git config --global core.longpaths true
131131
132132
- name: Git Checkout
133-
uses: actions/checkout@v2
133+
uses: actions/checkout@v3
134134
with:
135135
fetch-depth: 0
136136
submodules: recursive
@@ -139,7 +139,7 @@ jobs:
139139
uses: NuGet/setup-nuget@v1
140140

141141
- name: NuGet Setup Cache
142-
uses: actions/cache@v2
142+
uses: actions/cache@v3
143143
id: nuget-cache
144144
with:
145145
path: ~/.nuget

src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
<None Include="..\..\shared-infrastructure\branding\icons\imagesharp.drawing\sixlabors.imagesharp.drawing.128.png" Pack="true" PackagePath="" />
1818
</ItemGroup>
1919
<ItemGroup>
20-
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta16.13" />
21-
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.1-alpha.0.2" />
20+
<PackageReference Include="SixLabors.Fonts" Version="1.0.0-beta18" />
21+
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
2222
</ItemGroup>
2323
<Import Project="..\..\shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems" Label="Shared" />
2424
</Project>

src/ImageSharp.Drawing/Processing/ImageBrush.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public override void Apply(Span<float> scanline, int x, int y)
172172
Span<TPixel> overlaySpan = overlay.Memory.Span;
173173

174174
int offsetX = x - this.offsetX;
175-
int sourceY = ((y - this.offsetY) % this.sourceRegion.Width) + this.sourceRegion.Y;
175+
int sourceY = ((y - this.offsetY) % this.sourceRegion.Height) + this.sourceRegion.Y;
176176
Span<TPixel> sourceRow = this.sourceFrame.PixelBuffer.DangerousGetRowSpan(sourceY);
177177

178178
for (int i = 0; i < scanline.Length; i++)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Numerics;
7+
8+
namespace SixLabors.ImageSharp.Drawing
9+
{
10+
/// <summary>
11+
/// A path that is always empty.
12+
/// </summary>
13+
public class EmptyPath : IPath
14+
{
15+
private EmptyPath(PathTypes pathType) => this.PathType = pathType;
16+
17+
/// <summary>
18+
/// Gets the closed path instance of the empty path
19+
/// </summary>
20+
public static EmptyPath ClosedPath { get; } = new EmptyPath(PathTypes.Closed);
21+
22+
/// <summary>
23+
/// Gets the open path instance of the empty path
24+
/// </summary>
25+
public static EmptyPath OpenPath { get; } = new EmptyPath(PathTypes.Open);
26+
27+
/// <inheritdoc />
28+
public PathTypes PathType { get; }
29+
30+
/// <inheritdoc />
31+
public RectangleF Bounds => RectangleF.Empty;
32+
33+
/// <inheritdoc />
34+
public IPath AsClosedPath() => ClosedPath;
35+
36+
/// <inheritdoc />
37+
public IEnumerable<ISimplePath> Flatten() => Array.Empty<ISimplePath>();
38+
39+
/// <inheritdoc />
40+
public IPath Transform(Matrix3x2 matrix) => this;
41+
}
42+
}

src/ImageSharp.Drawing/Shapes/InternalPath.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,22 @@ private InternalPath(PointData[] points, bool isClosedPath)
8080

8181
if (this.points.Length > 0)
8282
{
83-
float minX = this.points.Min(x => x.Point.X);
84-
float maxX = this.points.Max(x => x.Point.X);
85-
float minY = this.points.Min(x => x.Point.Y);
86-
float maxY = this.points.Max(x => x.Point.Y);
83+
float minX, minY, maxX, maxY, length;
84+
length = 0;
85+
minX = minY = float.MaxValue;
86+
maxX = maxY = float.MinValue;
87+
88+
foreach (var point in this.points)
89+
{
90+
length += point.Length;
91+
minX = Math.Min(point.Point.X, minX);
92+
minY = Math.Min(point.Point.Y, minY);
93+
maxX = Math.Max(point.Point.X, maxX);
94+
maxY = Math.Max(point.Point.Y, maxY);
95+
}
8796

8897
this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
89-
this.Length = this.points.Sum(x => x.Length);
98+
this.Length = length;
9099
}
91100
else
92101
{

src/ImageSharp.Drawing/Shapes/OutlinePathExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public static class OutlinePathExtensions
3838
/// <exception cref="ClipperException">Thrown when an offset cannot be calculated.</exception>
3939
public static IPath GenerateOutline(this IPath path, float width, JointStyle jointStyle, EndCapStyle endCapStyle)
4040
{
41+
if (width <= 0)
42+
{
43+
return Path.Empty;
44+
}
45+
4146
ClipperOffset offset = new(MiterOffsetDelta);
4247
offset.AddPath(path, jointStyle, endCapStyle);
4348

@@ -93,6 +98,11 @@ public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<f
9398
/// <exception cref="ClipperException">Thrown when an offset cannot be calculated.</exception>
9499
public static IPath GenerateOutline(this IPath path, float width, ReadOnlySpan<float> pattern, bool startOff, JointStyle jointStyle, EndCapStyle endCapStyle)
95100
{
101+
if (width <= 0)
102+
{
103+
return Path.Empty;
104+
}
105+
96106
if (pattern.Length < 2)
97107
{
98108
return path.GenerateOutline(width, jointStyle, endCapStyle);

src/ImageSharp.Drawing/Shapes/Path.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ public Path(Path path)
4242
public Path(params ILineSegment[] segments)
4343
=> this.lineSegments = segments ?? throw new ArgumentNullException(nameof(segments));
4444

45+
/// <summary>
46+
/// Gets the default empty path.
47+
/// </summary>
48+
public static IPath Empty { get; } = EmptyPath.OpenPath;
49+
4550
/// <inheritdoc/>
4651
bool ISimplePath.IsClosed => this.IsClosed;
4752

src/ImageSharp.Drawing/Shapes/PathCollection.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,17 @@ public PathCollection(params IPath[] paths)
4040
}
4141
else
4242
{
43-
float minX = this.paths.Min(x => x.Bounds.Left);
44-
float maxX = this.paths.Max(x => x.Bounds.Right);
43+
float minX, minY, maxX, maxY;
44+
minX = minY = float.MaxValue;
45+
maxX = maxY = float.MinValue;
4546

46-
float minY = this.paths.Min(x => x.Bounds.Top);
47-
float maxY = this.paths.Max(x => x.Bounds.Bottom);
47+
foreach (var path in this.paths)
48+
{
49+
minX = Math.Min(path.Bounds.Left, minX);
50+
minY = Math.Min(path.Bounds.Top, minY);
51+
maxX = Math.Max(path.Bounds.Right, maxX);
52+
maxY = Math.Max(path.Bounds.Bottom, maxY);
53+
}
4854

4955
this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
5056
}

tests/ImageSharp.Drawing.Tests/Drawing/FillImageBrushTests.cs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,52 @@ public void UseBrushOfDifferentPixelType<TPixel>(TestImageProvider<TPixel> provi
3333
where TPixel : unmanaged, IPixel<TPixel>
3434
{
3535
byte[] data = TestFile.Create(TestImages.Png.Ducky).Bytes;
36-
using (Image<TPixel> background = provider.GetImage())
37-
using (Image overlay = provider.PixelType == PixelTypes.Rgba32
38-
? (Image)Image.Load<Bgra32>(data)
39-
: Image.Load<Rgba32>(data))
40-
{
41-
var brush = new ImageBrush(overlay);
42-
background.Mutate(c => c.Fill(brush));
36+
using Image<TPixel> background = provider.GetImage();
37+
using Image overlay = provider.PixelType == PixelTypes.Rgba32
38+
? Image.Load<Bgra32>(data)
39+
: Image.Load<Rgba32>(data);
4340

44-
background.DebugSave(provider, appendSourceFileOrDescription: false);
45-
background.CompareToReferenceOutput(provider, appendSourceFileOrDescription: false);
46-
}
41+
var brush = new ImageBrush(overlay);
42+
background.Mutate(c => c.Fill(brush));
43+
44+
background.DebugSave(provider, appendSourceFileOrDescription: false);
45+
background.CompareToReferenceOutput(provider, appendSourceFileOrDescription: false);
46+
}
47+
48+
[Theory]
49+
[WithTestPatternImage(200, 200, PixelTypes.Rgba32)]
50+
public void CanDrawLandscapeImage<TPixel>(TestImageProvider<TPixel> provider)
51+
where TPixel : unmanaged, IPixel<TPixel>
52+
{
53+
byte[] data = TestFile.Create(TestImages.Png.Ducky).Bytes;
54+
using Image<TPixel> background = provider.GetImage();
55+
using Image overlay = Image.Load<Rgba32>(data);
56+
57+
overlay.Mutate(c => c.Crop(new Rectangle(0, 0, 125, 90)));
58+
59+
var brush = new ImageBrush(overlay);
60+
background.Mutate(c => c.Fill(brush));
61+
62+
background.DebugSave(provider, appendSourceFileOrDescription: false);
63+
background.CompareToReferenceOutput(provider, appendSourceFileOrDescription: false);
64+
}
65+
66+
[Theory]
67+
[WithTestPatternImage(200, 200, PixelTypes.Rgba32)]
68+
public void CanDrawPortraitImage<TPixel>(TestImageProvider<TPixel> provider)
69+
where TPixel : unmanaged, IPixel<TPixel>
70+
{
71+
byte[] data = TestFile.Create(TestImages.Png.Ducky).Bytes;
72+
using Image<TPixel> background = provider.GetImage();
73+
using Image overlay = Image.Load<Rgba32>(data);
74+
75+
overlay.Mutate(c => c.Crop(new Rectangle(0, 0, 90, 125)));
76+
77+
var brush = new ImageBrush(overlay);
78+
background.Mutate(c => c.Fill(brush));
79+
80+
background.DebugSave(provider, appendSourceFileOrDescription: false);
81+
background.CompareToReferenceOutput(provider, appendSourceFileOrDescription: false);
4782
}
4883
}
4984
}

0 commit comments

Comments
 (0)