Skip to content

Commit dd850fc

Browse files
Merge branch 'main' into js/lay-glyph-renderer
2 parents fad1078 + dd8f167 commit dd850fc

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1473
-354
lines changed

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ on:
44
push:
55
branches:
66
- main
7+
- release/*
78
tags:
89
- "v*"
910
pull_request:
1011
branches:
1112
- main
13+
- release/*
1214
types: [ labeled, opened, synchronize, reopened ]
15+
1316
jobs:
1417
# Prime a single LFS cache and expose the exact key for the matrix
1518
WarmLFS:
@@ -112,14 +115,14 @@ jobs:
112115
options:
113116
os: buildjet-4vcpu-ubuntu-2204-arm
114117

115-
runs-on: ${{matrix.options.os}}
118+
runs-on: ${{ matrix.options.os }}
116119

117120
steps:
118121
- name: Install libgdi+, which is required for tests running on ubuntu
119122
if: ${{ contains(matrix.options.os, 'ubuntu') }}
120123
run: |
121-
sudo apt-get update
122-
sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev
124+
sudo apt-get update
125+
sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev
123126
124127
- name: Git Config
125128
shell: bash
@@ -141,6 +144,7 @@ jobs:
141144
key: ${{ needs.WarmLFS.outputs.lfs_key }}
142145

143146
- name: Git Pull LFS
147+
shell: bash
144148
run: git lfs pull
145149

146150
- name: NuGet Install
@@ -211,14 +215,10 @@ jobs:
211215
with:
212216
flags: unittests
213217

214-
215218
Publish:
216219
needs: [Build]
217-
218220
runs-on: ubuntu-latest
219-
220221
if: (github.event_name == 'push')
221-
222222
steps:
223223
- name: Git Config
224224
shell: bash
@@ -259,4 +259,3 @@ jobs:
259259
run: |
260260
dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json --skip-duplicate
261261
dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.NUGET_TOKEN}} -s https://api.nuget.org/v3/index.json --skip-duplicate
262-

ImageSharp.Drawing.sln

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 18
44
VisualStudioVersion = 18.0.11012.119 d18.0
5+
VisualStudioVersion = 18.0.11123.170 d18.0
56
MinimumVisualStudioVersion = 10.0.40219.1
67
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_root", "_root", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
78
ProjectSection(SolutionItems) = preProject
@@ -365,6 +366,14 @@ Global
365366
{4A922B77-34EC-EA6A-8E96-8353C8FA0640}.Debug|Any CPU.Build.0 = Debug|Any CPU
366367
{4A922B77-34EC-EA6A-8E96-8353C8FA0640}.Release|Any CPU.ActiveCfg = Release|Any CPU
367368
{4A922B77-34EC-EA6A-8E96-8353C8FA0640}.Release|Any CPU.Build.0 = Release|Any CPU
369+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
370+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
371+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
372+
{FCEDD229-22BC-4B82-87DE-786BBFC52EDE}.Release|Any CPU.Build.0 = Release|Any CPU
373+
{5490DFAF-0891-535F-08B4-2BF03C2BB778}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
374+
{5490DFAF-0891-535F-08B4-2BF03C2BB778}.Debug|Any CPU.Build.0 = Debug|Any CPU
375+
{5490DFAF-0891-535F-08B4-2BF03C2BB778}.Release|Any CPU.ActiveCfg = Release|Any CPU
376+
{5490DFAF-0891-535F-08B4-2BF03C2BB778}.Release|Any CPU.Build.0 = Release|Any CPU
368377
EndGlobalSection
369378
GlobalSection(SolutionProperties) = preSolution
370379
HideSolutionNode = FALSE

src/ImageSharp.Drawing/Common/Extensions/GraphicsOptionsExtensions.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Six Labors Split License.
33

4-
using System.Numerics;
5-
64
namespace SixLabors.ImageSharp.Drawing;
75

86
/// <summary>
@@ -28,20 +26,19 @@ public static bool IsOpaqueColorWithoutBlending(this GraphicsOptions options, Co
2826
return false;
2927
}
3028

31-
if (options.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver
32-
&& options.AlphaCompositionMode != PixelAlphaCompositionMode.Src)
29+
if (options.AlphaCompositionMode is not PixelAlphaCompositionMode.SrcOver and not PixelAlphaCompositionMode.Src)
3330
{
3431
return false;
3532
}
3633

37-
const float Opaque = 1F;
34+
const float opaque = 1f;
3835

39-
if (options.BlendPercentage != Opaque)
36+
if (options.BlendPercentage != opaque)
4037
{
4138
return false;
4239
}
4340

44-
if (color.ToScaledVector4().W != Opaque)
41+
if (color.ToScaledVector4().W != opaque)
4542
{
4643
return false;
4744
}

src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
<Otherwise>
3636
<PropertyGroup>
3737
<TargetFrameworks>net8.0</TargetFrameworks>
38-
<IsTrimmable>true</IsTrimmable>
3938
</PropertyGroup>
4039
</Otherwise>
4140
</Choose>

src/ImageSharp.Drawing/Processing/PatternBrush.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ public PatternBrushApplicator(
156156
public override void Apply(Span<float> scanline, int x, int y)
157157
{
158158
int patternY = y % this.pattern.Rows;
159-
Span<float> amounts = this.blenderBuffers.AmountSpan.Slice(0, scanline.Length);
160-
Span<TPixel> overlays = this.blenderBuffers.OverlaySpan.Slice(0, scanline.Length);
159+
Span<float> amounts = this.blenderBuffers.AmountSpan[..scanline.Length];
160+
Span<TPixel> overlays = this.blenderBuffers.OverlaySpan[..scanline.Length];
161161

162162
for (int i = 0; i < scanline.Length; i++)
163163
{

src/ImageSharp.Drawing/Processing/Pen.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ protected Pen(Brush strokeFill, float strokeWidth)
5151
protected Pen(Brush strokeFill, float strokeWidth, float[] strokePattern)
5252
{
5353
Guard.NotNull(strokeFill, nameof(strokeFill));
54+
5455
Guard.MustBeGreaterThan(strokeWidth, 0, nameof(strokeWidth));
5556
Guard.NotNull(strokePattern, nameof(strokePattern));
5657

src/ImageSharp.Drawing/Processing/Processors/Drawing/FillPathProcessor{TPixel}.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ protected override void OnFrameApply(ImageFrame<TPixel> source)
6767

6868
// We need to offset the pixel grid to account for when we outline a path.
6969
// 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]
70-
// 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#
70+
// 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
7171
// region to align with the pixel grid.
7272
if (graphicsOptions.Antialias)
7373
{

src/ImageSharp.Drawing/Processing/RecolorBrush.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ public RecolorBrushApplicator(
100100
float threshold)
101101
: base(configuration, options, source)
102102
{
103-
this.sourceColor = sourceColor.ToVector4();
103+
this.sourceColor = sourceColor.ToScaledVector4();
104104
this.targetColorPixel = targetColor;
105105

106+
// TODO: Review this. We can skip the conversion from/to Vector4.
106107
// Lets hack a min max extremes for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :)
107108
TPixel maxColor = TPixel.FromVector4(new Vector4(float.MaxValue));
108109
TPixel minColor = TPixel.FromVector4(new Vector4(float.MinValue));

src/ImageSharp.Drawing/Shapes/ArcLineSegment.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ public ArcLineSegment(PointF from, PointF to, SizeF radius, float rotation, bool
4444
{
4545
this.linePoints = EllipticArcFromEndParams(from, to, radius, rotation, largeArc, sweep);
4646
}
47-
48-
this.EndPoint = this.linePoints[^1];
4947
}
5048

5149
/// <summary>
@@ -80,18 +78,15 @@ public ArcLineSegment(PointF center, SizeF radius, float rotation, float startAn
8078
{
8179
this.linePoints = EllipticArcFromEndParams(from, to, radius, rotation, largeArc, sweep);
8280
}
83-
84-
this.EndPoint = this.linePoints[^1];
8581
}
8682

8783
private ArcLineSegment(PointF[] linePoints)
8884
{
8985
this.linePoints = linePoints;
90-
this.EndPoint = this.linePoints[^1];
9186
}
9287

9388
/// <inheritdoc/>
94-
public PointF EndPoint { get; }
89+
public PointF EndPoint => this.linePoints[^1];
9590

9691
/// <inheritdoc/>
9792
public ReadOnlyMemory<PointF> Flatten() => this.linePoints;

src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs

Lines changed: 58 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Six Labors Split License.
33

44
using System.Buffers;
5+
using System.Diagnostics.CodeAnalysis;
56
using System.Numerics;
67

78
namespace SixLabors.ImageSharp.Drawing;
@@ -14,8 +15,9 @@ namespace SixLabors.ImageSharp.Drawing;
1415
public sealed class ComplexPolygon : IPath, IPathInternals, IInternalPathOwner
1516
{
1617
private readonly IPath[] paths;
17-
private readonly List<InternalPath> internalPaths;
18-
private readonly float length;
18+
private List<InternalPath>? internalPaths;
19+
private float length;
20+
private RectangleF? bounds;
1921

2022
/// <summary>
2123
/// Initializes a new instance of the <see cref="ComplexPolygon"/> class.
@@ -45,53 +47,10 @@ public ComplexPolygon(params IPath[] paths)
4547
Guard.NotNull(paths, nameof(paths));
4648

4749
this.paths = paths;
48-
this.internalPaths = new List<InternalPath>(this.paths.Length);
49-
50-
if (paths.Length > 0)
51-
{
52-
float minX = float.MaxValue;
53-
float maxX = float.MinValue;
54-
float minY = float.MaxValue;
55-
float maxY = float.MinValue;
56-
float length = 0;
57-
58-
foreach (IPath p in this.paths)
59-
{
60-
if (p.Bounds.Left < minX)
61-
{
62-
minX = p.Bounds.Left;
63-
}
64-
65-
if (p.Bounds.Right > maxX)
66-
{
67-
maxX = p.Bounds.Right;
68-
}
69-
70-
if (p.Bounds.Top < minY)
71-
{
72-
minY = p.Bounds.Top;
73-
}
74-
75-
if (p.Bounds.Bottom > maxY)
76-
{
77-
maxY = p.Bounds.Bottom;
78-
}
79-
80-
foreach (ISimplePath s in p.Flatten())
81-
{
82-
InternalPath ip = new(s.Points, s.IsClosed);
83-
length += ip.Length;
84-
this.internalPaths.Add(ip);
85-
}
86-
}
8750

88-
this.length = length;
89-
this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
90-
}
91-
else
51+
if (paths.Length == 0)
9252
{
93-
this.length = 0;
94-
this.Bounds = RectangleF.Empty;
53+
this.bounds = RectangleF.Empty;
9554
}
9655

9756
this.PathType = PathTypes.Mixed;
@@ -106,7 +65,7 @@ public ComplexPolygon(params IPath[] paths)
10665
public IEnumerable<IPath> Paths => this.paths;
10766

10867
/// <inheritdoc/>
109-
public RectangleF Bounds { get; }
68+
public RectangleF Bounds => this.bounds ??= this.CalcBounds();
11069

11170
/// <inheritdoc/>
11271
public IPath Transform(Matrix3x2 matrix)
@@ -118,10 +77,10 @@ public IPath Transform(Matrix3x2 matrix)
11877
}
11978

12079
IPath[] shapes = new IPath[this.paths.Length];
121-
int i = 0;
122-
foreach (IPath s in this.Paths)
80+
81+
for (int i = 0; i < shapes.Length; i++)
12382
{
124-
shapes[i++] = s.Transform(matrix);
83+
shapes[i] = this.paths[i].Transform(matrix);
12584
}
12685

12786
return new ComplexPolygon(shapes);
@@ -159,6 +118,11 @@ public IPath AsClosedPath()
159118
/// <inheritdoc/>
160119
SegmentInfo IPathInternals.PointAlongPath(float distance)
161120
{
121+
if (this.internalPaths == null)
122+
{
123+
this.InitInternalPaths();
124+
}
125+
162126
distance %= this.length;
163127
foreach (InternalPath p in this.internalPaths)
164128
{
@@ -177,7 +141,49 @@ SegmentInfo IPathInternals.PointAlongPath(float distance)
177141

178142
/// <inheritdoc/>
179143
IReadOnlyList<InternalPath> IInternalPathOwner.GetRingsAsInternalPath()
180-
=> this.internalPaths;
144+
{
145+
this.InitInternalPaths();
146+
return this.internalPaths;
147+
}
148+
149+
/// <summary>
150+
/// Initializes <see cref="internalPaths"/> and <see cref="length"/>.
151+
/// </summary>
152+
[MemberNotNull(nameof(internalPaths))]
153+
private void InitInternalPaths()
154+
{
155+
this.internalPaths = new List<InternalPath>(this.paths.Length);
156+
157+
foreach (IPath p in this.paths)
158+
{
159+
foreach (ISimplePath s in p.Flatten())
160+
{
161+
InternalPath ip = new(s.Points, s.IsClosed);
162+
this.length += ip.Length;
163+
this.internalPaths.Add(ip);
164+
}
165+
}
166+
}
167+
168+
private RectangleF CalcBounds()
169+
{
170+
float minX = float.MaxValue;
171+
float maxX = float.MinValue;
172+
float minY = float.MaxValue;
173+
float maxY = float.MinValue;
174+
175+
foreach (IPath p in this.paths)
176+
{
177+
RectangleF pBounds = p.Bounds;
178+
179+
minX = MathF.Min(minX, pBounds.Left);
180+
maxX = MathF.Max(maxX, pBounds.Right);
181+
minY = MathF.Min(minY, pBounds.Top);
182+
maxY = MathF.Max(maxY, pBounds.Bottom);
183+
}
184+
185+
return new RectangleF(minX, minY, maxX - minX, maxY - minY);
186+
}
181187

182188
private static InvalidOperationException ThrowOutOfRange() => new("Should not be possible to reach this line");
183189
}

0 commit comments

Comments
 (0)