Skip to content

Commit 430ceee

Browse files
Merge branch 'main' into js/convolution-api
2 parents 014ac52 + 2d7cf48 commit 430ceee

File tree

45 files changed

+1049
-721
lines changed

Some content is hidden

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

45 files changed

+1049
-721
lines changed

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,31 @@ jobs:
1919
isARM:
2020
- ${{ contains(github.event.pull_request.labels.*.name, 'arch:arm32') || contains(github.event.pull_request.labels.*.name, 'arch:arm64') }}
2121
options:
22+
- os: ubuntu-latest
23+
framework: net9.0
24+
sdk: 9.0.x
25+
sdk-preview: true
26+
runtime: -x64
27+
codecov: false
28+
- os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable
29+
framework: net9.0
30+
sdk: 9.0.x
31+
sdk-preview: true
32+
runtime: -x64
33+
codecov: false
34+
- os: windows-latest
35+
framework: net9.0
36+
sdk: 9.0.x
37+
sdk-preview: true
38+
runtime: -x64
39+
codecov: false
40+
- os: buildjet-4vcpu-ubuntu-2204-arm
41+
framework: net9.0
42+
sdk: 9.0.x
43+
sdk-preview: true
44+
runtime: -x64
45+
codecov: false
46+
2247
- os: ubuntu-latest
2348
framework: net8.0
2449
sdk: 8.0.x
@@ -100,7 +125,7 @@ jobs:
100125
uses: actions/setup-dotnet@v4
101126
with:
102127
dotnet-version: |
103-
8.0.x
128+
9.0.x
104129
105130
- name: DotNet Build
106131
if: ${{ matrix.options.sdk-preview != true }}

src/ImageSharp.ruleset

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<RuleSet Name="ImageSharp" ToolsVersion="17.0">
33
<Include Path="..\shared-infrastructure\sixlabors.ruleset" Action="Default" />
4+
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.NetAnalyzers" RuleNamespace="Microsoft.CodeAnalysis.CSharp.NetAnalyzers">
5+
<Rule Id="CA2022" Action="Info" />
6+
</Rules>
47
</RuleSet>

src/ImageSharp/Formats/ImageEncoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ private void EncodeWithSeekableStream<TPixel>(Image<TPixel> image, Stream stream
5151
else
5252
{
5353
using ChunkedMemoryStream ms = new(configuration.MemoryAllocator);
54-
this.Encode(image, stream, cancellationToken);
54+
this.Encode(image, ms, cancellationToken);
5555
ms.Position = 0;
5656
ms.CopyTo(stream, configuration.StreamProcessingBufferSize);
5757
}

src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
using SixLabors.ImageSharp.Metadata.Profiles.Icc;
1717
using SixLabors.ImageSharp.Metadata.Profiles.Iptc;
1818
using SixLabors.ImageSharp.Metadata.Profiles.Xmp;
19-
using SixLabors.ImageSharp.PixelFormats;
2019

2120
namespace SixLabors.ImageSharp.Formats.Jpeg;
2221

@@ -1473,7 +1472,7 @@ private void ProcessStartOfScanMarker(BufferedReadStream stream, int remaining)
14731472

14741473
this.Frame.ComponentOrder[i / 2] = (byte)componentIndex;
14751474

1476-
IJpegComponent component = this.Frame.Components[componentIndex];
1475+
JpegComponent component = this.Frame.Components[componentIndex];
14771476

14781477
// 1 byte: Huffman table selectors.
14791478
// 4 bits - dc

src/ImageSharp/Formats/Webp/AlphaDecoder.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ public void Decode()
183183
else
184184
{
185185
this.LosslessDecoder.DecodeImageData(this.Vp8LDec, this.Vp8LDec.Pixels.Memory.Span);
186-
this.ExtractAlphaRows(this.Vp8LDec);
186+
this.ExtractAlphaRows(this.Vp8LDec, this.Width);
187187
}
188188
}
189189

@@ -257,14 +257,15 @@ public void ExtractPalettedAlphaRows(int lastRow)
257257
/// Once the image-stream is decoded into ARGB color values, the transparency information will be extracted from the green channel of the ARGB quadruplet.
258258
/// </summary>
259259
/// <param name="dec">The VP8L decoder.</param>
260-
private void ExtractAlphaRows(Vp8LDecoder dec)
260+
/// <param name="width">The image width.</param>
261+
private void ExtractAlphaRows(Vp8LDecoder dec, int width)
261262
{
262263
int numRowsToProcess = dec.Height;
263-
int width = dec.Width;
264264
Span<uint> input = dec.Pixels.Memory.Span;
265265
Span<byte> output = this.Alpha.Memory.Span;
266266

267267
// Extract alpha (which is stored in the green plane).
268+
// the final width (!= dec->width_)
268269
int pixelCount = width * numRowsToProcess;
269270
WebpLosslessDecoder.ApplyInverseTransforms(dec, input, this.memoryAllocator);
270271
ExtractGreen(input, output, pixelCount);

src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,11 @@ private static void SubtractGreenFromBlueAndRedScalar(Span<uint> pixelData)
269269
/// </summary>
270270
/// <param name="transform">The transform data contains color table size and the entries in the color table.</param>
271271
/// <param name="pixelData">The pixel data to apply the reverse transform on.</param>
272-
public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint> pixelData)
272+
/// <param name="outputSpan">The resulting pixel data with the reversed transformation data.</param>
273+
public static void ColorIndexInverseTransform(
274+
Vp8LTransform transform,
275+
Span<uint> pixelData,
276+
Span<uint> outputSpan)
273277
{
274278
int bitsPerPixel = 8 >> transform.Bits;
275279
int width = transform.XSize;
@@ -282,7 +286,6 @@ public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint
282286
int countMask = pixelsPerByte - 1;
283287
int bitMask = (1 << bitsPerPixel) - 1;
284288

285-
uint[] decodedPixelData = new uint[width * height];
286289
int pixelDataPos = 0;
287290
for (int y = 0; y < height; y++)
288291
{
@@ -298,12 +301,12 @@ public static void ColorIndexInverseTransform(Vp8LTransform transform, Span<uint
298301
packedPixels = GetArgbIndex(pixelData[pixelDataPos++]);
299302
}
300303

301-
decodedPixelData[decodedPixels++] = colorMap[(int)(packedPixels & bitMask)];
304+
outputSpan[decodedPixels++] = colorMap[(int)(packedPixels & bitMask)];
302305
packedPixels >>= bitsPerPixel;
303306
}
304307
}
305308

306-
decodedPixelData.AsSpan().CopyTo(pixelData);
309+
outputSpan.CopyTo(pixelData);
307310
}
308311
else
309312
{

src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,7 @@ public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span<uint> pixelD
684684
List<Vp8LTransform> transforms = decoder.Transforms;
685685
for (int i = transforms.Count - 1; i >= 0; i--)
686686
{
687+
// TODO: Review these 1D allocations. They could conceivably exceed limits.
687688
Vp8LTransform transform = transforms[i];
688689
switch (transform.TransformType)
689690
{
@@ -701,7 +702,11 @@ public static void ApplyInverseTransforms(Vp8LDecoder decoder, Span<uint> pixelD
701702
LosslessUtils.ColorSpaceInverseTransform(transform, pixelData);
702703
break;
703704
case Vp8LTransformType.ColorIndexingTransform:
704-
LosslessUtils.ColorIndexInverseTransform(transform, pixelData);
705+
using (IMemoryOwner<uint> output = memoryAllocator.Allocate<uint>(transform.XSize * transform.YSize, AllocationOptions.Clean))
706+
{
707+
LosslessUtils.ColorIndexInverseTransform(transform, pixelData, output.GetSpan());
708+
}
709+
705710
break;
706711
}
707712
}

src/ImageSharp/Formats/Webp/Lossy/Vp8Encoding.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -667,12 +667,12 @@ public static void EncPredChroma8(Span<byte> dst, Span<byte> left, Span<byte> to
667667

668668
// V block.
669669
dst = dst[8..];
670-
if (top != default)
670+
if (!top.IsEmpty)
671671
{
672672
top = top[8..];
673673
}
674674

675-
if (left != default)
675+
if (!left.IsEmpty)
676676
{
677677
left = left[16..];
678678
}
@@ -701,7 +701,7 @@ public static void EncPredLuma4(Span<byte> dst, Span<byte> top, int topOffset, S
701701

702702
private static void VerticalPred(Span<byte> dst, Span<byte> top, int size)
703703
{
704-
if (top != default)
704+
if (!top.IsEmpty)
705705
{
706706
for (int j = 0; j < size; j++)
707707
{
@@ -716,7 +716,7 @@ private static void VerticalPred(Span<byte> dst, Span<byte> top, int size)
716716

717717
public static void HorizontalPred(Span<byte> dst, Span<byte> left, int size)
718718
{
719-
if (left != default)
719+
if (!left.IsEmpty)
720720
{
721721
left = left[1..]; // in the reference implementation, left starts at - 1.
722722
for (int j = 0; j < size; j++)
@@ -732,9 +732,9 @@ public static void HorizontalPred(Span<byte> dst, Span<byte> left, int size)
732732

733733
public static void TrueMotion(Span<byte> dst, Span<byte> left, Span<byte> top, int size)
734734
{
735-
if (left != default)
735+
if (!left.IsEmpty)
736736
{
737-
if (top != default)
737+
if (!top.IsEmpty)
738738
{
739739
Span<byte> clip = Clip1.AsSpan(255 - left[0]); // left [0] instead of left[-1], original left starts at -1
740740
for (int y = 0; y < size; y++)
@@ -759,7 +759,7 @@ public static void TrueMotion(Span<byte> dst, Span<byte> left, Span<byte> top, i
759759
// is equivalent to VE prediction where you just copy the top samples.
760760
// Note that if top samples are not available, the default value is
761761
// then 129, and not 127 as in the VerticalPred case.
762-
if (top != default)
762+
if (!top.IsEmpty)
763763
{
764764
VerticalPred(dst, top, size);
765765
}
@@ -774,14 +774,14 @@ private static void DcMode(Span<byte> dst, Span<byte> left, Span<byte> top, int
774774
{
775775
int dc = 0;
776776
int j;
777-
if (top != default)
777+
if (!top.IsEmpty)
778778
{
779779
for (j = 0; j < size; j++)
780780
{
781781
dc += top[j];
782782
}
783783

784-
if (left != default)
784+
if (!left.IsEmpty)
785785
{
786786
// top and left present.
787787
left = left[1..]; // in the reference implementation, left starts at -1.
@@ -798,7 +798,7 @@ private static void DcMode(Span<byte> dst, Span<byte> left, Span<byte> top, int
798798

799799
dc = (dc + round) >> shift;
800800
}
801-
else if (left != default)
801+
else if (!left.IsEmpty)
802802
{
803803
// left but no top.
804804
left = left[1..]; // in the reference implementation, left starts at -1.

src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ private static void UpSampleScalar(Span<byte> topY, Span<byte> bottomY, Span<byt
4848
uint uv0 = ((3 * tluv) + luv + 0x00020002u) >> 2;
4949
YuvToBgr(topY[0], (int)(uv0 & 0xff), (int)(uv0 >> 16), topDst);
5050

51-
if (bottomY != default)
51+
if (!bottomY.IsEmpty)
5252
{
5353
uv0 = ((3 * luv) + tluv + 0x00020002u) >> 2;
5454
YuvToBgr(bottomY[0], (int)uv0 & 0xff, (int)(uv0 >> 16), bottomDst);
@@ -69,7 +69,7 @@ private static void UpSampleScalar(Span<byte> topY, Span<byte> bottomY, Span<byt
6969
YuvToBgr(topY[xMul2 - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), topDst[((xMul2 - 1) * xStep)..]);
7070
YuvToBgr(topY[xMul2 - 0], (int)(uv1 & 0xff), (int)(uv1 >> 16), topDst[((xMul2 - 0) * xStep)..]);
7171

72-
if (bottomY != default)
72+
if (!bottomY.IsEmpty)
7373
{
7474
uv0 = (diag03 + luv) >> 1;
7575
uv1 = (diag12 + uv) >> 1;
@@ -85,7 +85,7 @@ private static void UpSampleScalar(Span<byte> topY, Span<byte> bottomY, Span<byt
8585
{
8686
uv0 = ((3 * tluv) + luv + 0x00020002u) >> 2;
8787
YuvToBgr(topY[len - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), topDst[((len - 1) * xStep)..]);
88-
if (bottomY != default)
88+
if (!bottomY.IsEmpty)
8989
{
9090
uv0 = ((3 * luv) + tluv + 0x00020002u) >> 2;
9191
YuvToBgr(bottomY[len - 1], (int)(uv0 & 0xff), (int)(uv0 >> 16), bottomDst[((len - 1) * xStep)..]);
@@ -120,7 +120,7 @@ private static void UpSampleSse41(Span<byte> topY, Span<byte> bottomY, Span<byte
120120
int u0t = (topU[0] + uDiag) >> 1;
121121
int v0t = (topV[0] + vDiag) >> 1;
122122
YuvToBgr(topY[0], u0t, v0t, topDst);
123-
if (bottomY != default)
123+
if (!bottomY.IsEmpty)
124124
{
125125
int u0b = (curU[0] + uDiag) >> 1;
126126
int v0b = (curV[0] + vDiag) >> 1;
@@ -134,7 +134,7 @@ private static void UpSampleSse41(Span<byte> topY, Span<byte> bottomY, Span<byte
134134
ref byte topVRef = ref MemoryMarshal.GetReference(topV);
135135
ref byte curURef = ref MemoryMarshal.GetReference(curU);
136136
ref byte curVRef = ref MemoryMarshal.GetReference(curV);
137-
if (bottomY != default)
137+
if (!bottomY.IsEmpty)
138138
{
139139
for (pos = 1, uvPos = 0; pos + 32 + 1 <= len; pos += 32, uvPos += 16)
140140
{
@@ -160,12 +160,12 @@ private static void UpSampleSse41(Span<byte> topY, Span<byte> bottomY, Span<byte
160160
Span<byte> tmpTopDst = ru[(4 * 32)..];
161161
Span<byte> tmpBottomDst = tmpTopDst[(4 * 32)..];
162162
Span<byte> tmpTop = tmpBottomDst[(4 * 32)..];
163-
Span<byte> tmpBottom = (bottomY == default) ? null : tmpTop[32..];
163+
Span<byte> tmpBottom = bottomY.IsEmpty ? null : tmpTop[32..];
164164
UpSampleLastBlock(topU[uvPos..], curU[uvPos..], leftOver, ru);
165165
UpSampleLastBlock(topV[uvPos..], curV[uvPos..], leftOver, rv);
166166

167167
topY[pos..len].CopyTo(tmpTop);
168-
if (bottomY != default)
168+
if (!bottomY.IsEmpty)
169169
{
170170
bottomY[pos..len].CopyTo(tmpBottom);
171171
ConvertYuvToBgrWithBottomYSse41(tmpTop, tmpBottom, tmpTopDst, tmpBottomDst, ru, rv, 0, xStep);
@@ -176,7 +176,7 @@ private static void UpSampleSse41(Span<byte> topY, Span<byte> bottomY, Span<byte
176176
}
177177

178178
tmpTopDst[..((len - pos) * xStep)].CopyTo(topDst[(pos * xStep)..]);
179-
if (bottomY != default)
179+
if (!bottomY.IsEmpty)
180180
{
181181
tmpBottomDst[..((len - pos) * xStep)].CopyTo(bottomDst[(pos * xStep)..]);
182182
}

0 commit comments

Comments
 (0)