Skip to content

Commit 64e7d6a

Browse files
Merge pull request #1304 from SixLabors/js/simplify-jpeg-encoder
Simplify jpeg encoder and fix for Windows ARM
2 parents a31a541 + 0c524d6 commit 64e7d6a

File tree

10 files changed

+135
-127
lines changed

10 files changed

+135
-127
lines changed

Directory.Build.props

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@
3030

3131
<!--
3232
https://apisof.net/
33-
+===================+=======+==========+=====================+=============+=================+====================+==============+=========+
34-
| SUPPORTS | MATHF | HASHCODE | EXTENDED_INTRINSICS | SPAN_STREAM | ENCODING_STRING | RUNTIME_INTRINSICS | CODECOVERAGE | HOTPATH |
35-
+===================+=======+==========+=====================+=============+=================+====================+==============+=========|
36-
| netcoreapp3.1 | Y | Y | Y | Y | Y | Y | Y | Y |
37-
| netcoreapp2.1 | Y | Y | Y | Y | Y | N | Y | N |
38-
| netcoreapp2.0 | Y | N | N | N | N | N | Y | N |
39-
| netstandard2.1 | Y | Y | N | Y | Y | N | Y | N |
40-
| netstandard2.0 | N | N | N | N | N | N | Y | N |
41-
| netstandard1.3 | N | N | N | N | N | N | N | N |
42-
| net472 | N | N | Y | N | N | N | Y | N |
43-
+===================+=======+==========+=====================+=============+=================+====================+==============+=========|
33+
+===================+=======+==========+=====================+=============+=================+====================+==============+=========+============|
34+
| SUPPORTS | MATHF | HASHCODE | EXTENDED_INTRINSICS | SPAN_STREAM | ENCODING_STRING | RUNTIME_INTRINSICS | CODECOVERAGE | HOTPATH | CREATESPAN |
35+
+===================+=======+==========+=====================+=============+=================+====================+==============+=========|============|
36+
| netcoreapp3.1 | Y | Y | Y | Y | Y | Y | Y | Y | Y |
37+
| netcoreapp2.1 | Y | Y | Y | Y | Y | N | Y | N | Y |
38+
| netcoreapp2.0 | Y | N | N | N | N | N | Y | N | Y |
39+
| netstandard2.1 | Y | Y | N | Y | Y | N | Y | N | Y |
40+
| netstandard2.0 | N | N | N | N | N | N | Y | N | N |
41+
| netstandard1.3 | N | N | N | N | N | N | N | N | N |
42+
| net472 | N | N | Y | N | N | N | Y | N | N |
43+
+===================+=======+==========+=====================+=============+=================+====================+==============+=========|============|
4444
-->
4545

4646
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
@@ -52,6 +52,7 @@
5252
<DefineConstants>$(DefineConstants);SUPPORTS_RUNTIME_INTRINSICS</DefineConstants>
5353
<DefineConstants>$(DefineConstants);SUPPORTS_CODECOVERAGE</DefineConstants>
5454
<DefineConstants>$(DefineConstants);SUPPORTS_HOTPATH</DefineConstants>
55+
<DefineConstants>$(DefineConstants);SUPPORTS_CREATESPAN</DefineConstants>
5556
</PropertyGroup>
5657
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.1'">
5758
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF</DefineConstants>
@@ -60,17 +61,20 @@
6061
<DefineConstants>$(DefineConstants);SUPPORTS_SPAN_STREAM</DefineConstants>
6162
<DefineConstants>$(DefineConstants);SUPPORTS_ENCODING_STRING</DefineConstants>
6263
<DefineConstants>$(DefineConstants);SUPPORTS_CODECOVERAGE</DefineConstants>
64+
<DefineConstants>$(DefineConstants);SUPPORTS_CREATESPAN</DefineConstants>
6365
</PropertyGroup>
6466
<PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
6567
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF</DefineConstants>
6668
<DefineConstants>$(DefineConstants);SUPPORTS_CODECOVERAGE</DefineConstants>
69+
<DefineConstants>$(DefineConstants);SUPPORTS_CREATESPAN</DefineConstants>
6770
</PropertyGroup>
6871
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.1'">
6972
<DefineConstants>$(DefineConstants);SUPPORTS_MATHF</DefineConstants>
7073
<DefineConstants>$(DefineConstants);SUPPORTS_HASHCODE</DefineConstants>
7174
<DefineConstants>$(DefineConstants);SUPPORTS_SPAN_STREAM</DefineConstants>
7275
<DefineConstants>$(DefineConstants);SUPPORTS_ENCODING_STRING</DefineConstants>
7376
<DefineConstants>$(DefineConstants);SUPPORTS_CODECOVERAGE</DefineConstants>
77+
<DefineConstants>$(DefineConstants);SUPPORTS_CREATESPAN</DefineConstants>
7478
</PropertyGroup>
7579
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
7680
<DefineConstants>$(DefineConstants);SUPPORTS_CODECOVERAGE</DefineConstants>

src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -376,45 +376,40 @@ public static unsafe void DequantizeBlock(Block8x8F* blockPtr, Block8x8F* qtPtr,
376376
/// <param name="block">Source block</param>
377377
/// <param name="dest">Destination block</param>
378378
/// <param name="qt">The quantization table</param>
379-
/// <param name="unzigPtr">Pointer to elements of <see cref="ZigZag"/></param>
379+
/// <param name="unZig">The 8x8 Unzig block.</param>
380380
public static unsafe void Quantize(
381-
Block8x8F* block,
382-
Block8x8F* dest,
383-
Block8x8F* qt,
384-
byte* unzigPtr)
381+
ref Block8x8F block,
382+
ref Block8x8F dest,
383+
ref Block8x8F qt,
384+
ref ZigZag unZig)
385385
{
386-
float* s = (float*)block;
387-
float* d = (float*)dest;
388-
389386
for (int zig = 0; zig < Size; zig++)
390387
{
391-
d[zig] = s[unzigPtr[zig]];
388+
dest[zig] = block[unZig[zig]];
392389
}
393390

394-
DivideRoundAll(ref *dest, ref *qt);
391+
DivideRoundAll(ref dest, ref qt);
395392
}
396393

397394
/// <summary>
398395
/// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block.
399396
/// </summary>
400397
/// <param name="destination">The destination block.</param>
401398
/// <param name="source">The source block.</param>
402-
public static unsafe void Scale16X16To8X8(Block8x8F* destination, Block8x8F* source)
399+
public static unsafe void Scale16X16To8X8(ref Block8x8F destination, ReadOnlySpan<Block8x8F> source)
403400
{
404-
float* d = (float*)destination;
405401
for (int i = 0; i < 4; i++)
406402
{
407403
int dstOff = ((i & 2) << 4) | ((i & 1) << 2);
408-
409-
float* iSource = (float*)(source + i);
404+
Block8x8F iSource = source[i];
410405

411406
for (int y = 0; y < 4; y++)
412407
{
413408
for (int x = 0; x < 4; x++)
414409
{
415410
int j = (16 * y) + (2 * x);
416411
float sum = iSource[j] + iSource[j + 1] + iSource[j + 8] + iSource[j + 9];
417-
d[(8 * y) + x + dstOff] = (sum + 2) / 4;
412+
destination[(8 * y) + x + dstOff] = (sum + 2) * .25F;
418413
}
419414
}
420415
}
@@ -589,7 +584,7 @@ private static Vector<float> NormalizeAndRound(Vector<float> row, Vector<float>
589584
private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor)
590585
{
591586
// sign(dividend) = max(min(dividend, 1), -1)
592-
var sign = Vector4Utilities.FastClamp(dividend, NegativeOne, Vector4.One);
587+
Vector4 sign = Vector4Utilities.FastClamp(dividend, NegativeOne, Vector4.One);
593588

594589
// AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend)
595590
return (dividend / divisor) + (sign * Offset);

src/ImageSharp/Formats/Jpeg/Components/Encoder/BlockQuad.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) Six Labors.
1+
// Copyright (c) Six Labors.
22
// Licensed under the Apache License, Version 2.0.
33

44
using System.Runtime.CompilerServices;
@@ -96,30 +96,27 @@ public static RgbToYCbCrTables Create()
9696
/// Optimized method to allocates the correct y, cb, and cr values to the DCT blocks from the given r, g, b values.
9797
/// </summary>
9898
[MethodImpl(MethodImplOptions.AggressiveInlining)]
99-
public void ConvertPixelInto(int r, int g, int b, ref float yResult, ref float cbResult, ref float crResult)
99+
public void ConvertPixelInto(
100+
int r,
101+
int g,
102+
int b,
103+
ref Block8x8F yResult,
104+
ref Block8x8F cbResult,
105+
ref Block8x8F crResult,
106+
int i)
100107
{
101-
ref int start = ref Unsafe.As<RgbToYCbCrTables, int>(ref this);
108+
// float y = (0.299F * r) + (0.587F * g) + (0.114F * b);
109+
yResult[i] = (this.YRTable[r] + this.YGTable[g] + this.YBTable[b]) >> ScaleBits;
102110

103-
ref int yR = ref start;
104-
ref int yG = ref Unsafe.Add(ref start, 256 * 1);
105-
ref int yB = ref Unsafe.Add(ref start, 256 * 2);
111+
// float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b));
112+
cbResult[i] = (this.CbRTable[r] + this.CbGTable[g] + this.CbBTable[b]) >> ScaleBits;
106113

107-
ref int cbR = ref Unsafe.Add(ref start, 256 * 3);
108-
ref int cbG = ref Unsafe.Add(ref start, 256 * 4);
109-
ref int cbB = ref Unsafe.Add(ref start, 256 * 5);
110-
111-
ref int crG = ref Unsafe.Add(ref start, 256 * 6);
112-
ref int crB = ref Unsafe.Add(ref start, 256 * 7);
113-
114-
yResult = (Unsafe.Add(ref yR, r) + Unsafe.Add(ref yG, g) + Unsafe.Add(ref yB, b)) >> ScaleBits;
115-
cbResult = (Unsafe.Add(ref cbR, r) + Unsafe.Add(ref cbG, g) + Unsafe.Add(ref cbB, b)) >> ScaleBits;
116-
crResult = (Unsafe.Add(ref cbB, r) + Unsafe.Add(ref crG, g) + Unsafe.Add(ref crB, b)) >> ScaleBits;
114+
// float cr = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
115+
crResult[i] = (this.CbBTable[r] + this.CrGTable[g] + this.CrBTable[b]) >> ScaleBits;
117116
}
118117

119118
[MethodImpl(MethodImplOptions.AggressiveInlining)]
120119
private static int Fix(float x)
121-
{
122-
return (int)((x * (1L << ScaleBits)) + 0.5F);
123-
}
120+
=> (int)((x * (1L << ScaleBits)) + 0.5F);
124121
}
125-
}
122+
}

src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ public void Convert(ImageFrame<TPixel> frame, int x, int y, in RowOctet<TPixel>
6262
Span<Rgb24> rgbSpan = this.rgbBlock.AsSpanUnsafe();
6363
PixelOperations<TPixel>.Instance.ToRgb24(frame.GetConfiguration(), this.pixelBlock.AsSpanUnsafe(), rgbSpan);
6464

65-
ref float yBlockStart = ref Unsafe.As<Block8x8F, float>(ref this.Y);
66-
ref float cbBlockStart = ref Unsafe.As<Block8x8F, float>(ref this.Cb);
67-
ref float crBlockStart = ref Unsafe.As<Block8x8F, float>(ref this.Cr);
65+
ref Block8x8F yBlock = ref this.Y;
66+
ref Block8x8F cbBlock = ref this.Cb;
67+
ref Block8x8F crBlock = ref this.Cr;
6868
ref Rgb24 rgbStart = ref rgbSpan[0];
6969

7070
for (int i = 0; i < 64; i++)
@@ -75,9 +75,10 @@ public void Convert(ImageFrame<TPixel> frame, int x, int y, in RowOctet<TPixel>
7575
c.R,
7676
c.G,
7777
c.B,
78-
ref Unsafe.Add(ref yBlockStart, i),
79-
ref Unsafe.Add(ref cbBlockStart, i),
80-
ref Unsafe.Add(ref crBlockStart, i));
78+
ref yBlock,
79+
ref cbBlock,
80+
ref crBlock,
81+
i);
8182
}
8283
}
8384
}

src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System;
55
using System.Runtime.CompilerServices;
66
using System.Runtime.InteropServices;
7-
using SixLabors.ImageSharp.Advanced;
87
using SixLabors.ImageSharp.Memory;
98
using SixLabors.ImageSharp.PixelFormats;
109

@@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
1615
/// </summary>
1716
[StructLayout(LayoutKind.Sequential)]
1817
internal unsafe partial struct GenericBlock8x8<T>
19-
where T : struct
18+
where T : unmanaged
2019
{
2120
public const int Size = 64;
2221

@@ -110,6 +109,14 @@ public void LoadAndStretchEdges(Buffer2D<T> source, int sourceX, int sourceY, in
110109
/// <summary>
111110
/// Only for on-stack instances!
112111
/// </summary>
113-
public Span<T> AsSpanUnsafe() => new Span<T>(Unsafe.AsPointer(ref this), Size);
112+
public Span<T> AsSpanUnsafe()
113+
{
114+
#if SUPPORTS_CREATESPAN
115+
Span<GenericBlock8x8<T>> s = MemoryMarshal.CreateSpan(ref this, 1);
116+
return MemoryMarshal.Cast<GenericBlock8x8<T>, T>(s);
117+
#else
118+
return new Span<T>(Unsafe.AsPointer(ref this), Size);
119+
#endif
120+
}
114121
}
115122
}

0 commit comments

Comments
 (0)