Skip to content

Commit dea1ee8

Browse files
committed
Optimizing avoiding casts to byte
Also removing benchmark test and fixing a typo in PngEncoderCore
1 parent ef78f98 commit dea1ee8

File tree

6 files changed

+41
-66
lines changed

6 files changed

+41
-66
lines changed

src/ImageSharp/Formats/Png/PngEncoderCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
3434
private readonly MemoryAllocator memoryAllocator;
3535

3636
/// <summary>
37-
/// The configuration instance for the decoding operation.
37+
/// The configuration instance for the encoding operation.
3838
/// </summary>
3939
private readonly Configuration configuration;
4040

src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,9 @@ private void ProcessPixels<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> p
202202

203203
// Get one pixel from the difference (-2..1) of the previous pixel
204204
case QoiChunk.QoiOpDiff:
205-
byte redDifference = (byte)((operationByte & 0b00110000) >> 4);
206-
byte greenDifference = (byte)((operationByte & 0b00001100) >> 2);
207-
byte blueDifference = (byte)(operationByte & 0b00000011);
205+
int redDifference = (operationByte & 0b00110000) >> 4;
206+
int greenDifference = (operationByte & 0b00001100) >> 2;
207+
int blueDifference = operationByte & 0b00000011;
208208
readPixel = previousPixel with
209209
{
210210
R = (byte)Numerics.Modulo256(previousPixel.R + (redDifference - 2)),
@@ -219,14 +219,14 @@ private void ProcessPixels<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> p
219219
// Get green difference in 6 bits and red and blue differences
220220
// depending on the green one
221221
case QoiChunk.QoiOpLuma:
222-
byte diffGreen = (byte)(operationByte & 0b00111111);
223-
byte currentGreen = (byte)Numerics.Modulo256(previousPixel.G + (diffGreen - 32));
224-
byte nextByte = (byte)stream.ReadByte();
225-
byte diffRedDG = (byte)(nextByte >> 4);
226-
byte diffBlueDG = (byte)(nextByte & 0b00001111);
227-
byte currentRed = (byte)Numerics.Modulo256(diffRedDG - 8 + (diffGreen - 32) + previousPixel.R);
228-
byte currentBlue = (byte)Numerics.Modulo256(diffBlueDG - 8 + (diffGreen - 32) + previousPixel.B);
229-
readPixel = previousPixel with { R = currentRed, B = currentBlue, G = currentGreen };
222+
int diffGreen = operationByte & 0b00111111;
223+
int currentGreen = Numerics.Modulo256(previousPixel.G + (diffGreen - 32));
224+
int nextByte = stream.ReadByte();
225+
int diffRedDG = nextByte >> 4;
226+
int diffBlueDG = nextByte & 0b00001111;
227+
int currentRed = Numerics.Modulo256(diffRedDG - 8 + (diffGreen - 32) + previousPixel.R);
228+
int currentBlue = Numerics.Modulo256(diffBlueDG - 8 + (diffGreen - 32) + previousPixel.B);
229+
readPixel = previousPixel with { R = (byte)currentRed, B = (byte)currentBlue, G = (byte)currentGreen };
230230
pixel.FromRgba32(readPixel);
231231
pixelArrayPosition = GetArrayPosition(readPixel);
232232
previouslySeenPixels[pixelArrayPosition] = readPixel;

src/ImageSharp/Formats/Qoi/QoiEncoder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class QoiEncoder : ImageEncoder
2727
/// <inheritdoc />
2828
protected override void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken cancellationToken)
2929
{
30-
QoiEncoderCore encoder = new(this, image.GetMemoryAllocator());
30+
QoiEncoderCore encoder = new(this, image.GetMemoryAllocator(), image.GetConfiguration());
3131
encoder.Encode(image, stream, cancellationToken);
3232
}
3333
}

src/ImageSharp/Formats/Qoi/QoiEncoderCore.cs

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,21 @@ public class QoiEncoderCore : IImageEncoderInternals
2424
/// </summary>
2525
private readonly MemoryAllocator memoryAllocator;
2626

27+
/// <summary>
28+
/// The configuration instance for the encoding operation.
29+
/// </summary>
30+
private readonly Configuration configuration;
31+
2732
/// <summary>
2833
/// Initializes a new instance of the <see cref="QoiEncoderCore"/> class.
2934
/// </summary>
3035
/// <param name="encoder">The encoder with options.</param>
3136
/// <param name="memoryAllocator">The <see cref="MemoryAllocator" /> to use for buffer allocations.</param>
32-
public QoiEncoderCore(QoiEncoder encoder, MemoryAllocator memoryAllocator)
37+
public QoiEncoderCore(QoiEncoder encoder, MemoryAllocator memoryAllocator, Configuration configuration)
3338
{
3439
this.encoder = encoder;
3540
this.memoryAllocator = memoryAllocator;
41+
this.configuration = configuration;
3642
}
3743

3844
/// <inheritdoc />
@@ -75,15 +81,17 @@ private void WritePixels<TPixel>(Image<TPixel> image, Stream stream)
7581
Rgba32 previousPixel = new(0, 0, 0, 255);
7682
Rgba32 currentRgba32 = default;
7783
Buffer2D<TPixel> pixels = image.Frames[0].PixelBuffer;
84+
using IMemoryOwner<Rgba32> rgbaRowBuffer = this.memoryAllocator.Allocate<Rgba32>(pixels.Width);
85+
Span<Rgba32> rgbaRow = rgbaRowBuffer.GetSpan();
7886

7987
for (int i = 0; i < pixels.Height; i++)
8088
{
8189
Span<TPixel> row = pixels.DangerousGetRowSpan(i);
90+
PixelOperations<TPixel>.Instance.ToRgba32(this.configuration, row, rgbaRow);
8291
for (int j = 0; j < row.Length && i < pixels.Height; j++)
8392
{
8493
// We get the RGBA value from pixels
85-
TPixel currentPixel = row[j];
86-
currentPixel.ToRgba32(ref currentRgba32);
94+
currentRgba32 = rgbaRow[j];
8795

8896
// First, we check if the current pixel is equal to the previous one
8997
// If so, we do a QOI_OP_RUN
@@ -97,7 +105,7 @@ private void WritePixels<TPixel>(Image<TPixel> image, Stream stream)
97105
* and we should discuss what to do about this approach and
98106
* if it's correct
99107
*/
100-
byte repetitions = 0;
108+
int repetitions = 0;
101109
do
102110
{
103111
repetitions++;
@@ -112,15 +120,15 @@ private void WritePixels<TPixel>(Image<TPixel> image, Stream stream)
112120
}
113121

114122
row = pixels.DangerousGetRowSpan(i);
123+
PixelOperations<TPixel>.Instance.ToRgba32(this.configuration, row, rgbaRow);
115124
}
116125

117-
currentPixel = row[j];
118-
currentPixel.ToRgba32(ref currentRgba32);
126+
currentRgba32 = rgbaRow[j];
119127
}
120128
while (currentRgba32.Equals(previousPixel) && repetitions < 62);
121129

122130
j--;
123-
stream.WriteByte((byte)((byte)QoiChunk.QoiOpRun | (repetitions - 1)));
131+
stream.WriteByte((byte)((int)QoiChunk.QoiOpRun | (repetitions - 1)));
124132

125133
/* If it's a QOI_OP_RUN, we don't overwrite the previous pixel since
126134
* it will be taken and compared on the next iteration
@@ -131,7 +139,7 @@ private void WritePixels<TPixel>(Image<TPixel> image, Stream stream)
131139
// else, we check if it exists in the previously seen pixels
132140
// If so, we do a QOI_OP_INDEX
133141
int pixelArrayPosition = GetArrayPosition(currentRgba32);
134-
if (previouslySeenPixels[pixelArrayPosition].Equals(currentPixel))
142+
if (previouslySeenPixels[pixelArrayPosition].Equals(currentRgba32))
135143
{
136144
stream.WriteByte((byte)pixelArrayPosition);
137145
}
@@ -141,9 +149,9 @@ private void WritePixels<TPixel>(Image<TPixel> image, Stream stream)
141149
// Since it wasn't found on the previously seen pixels, we save it
142150
previouslySeenPixels[pixelArrayPosition] = currentRgba32;
143151

144-
sbyte diffRed = (sbyte)(currentRgba32.R - previousPixel.R);
145-
sbyte diffGreen = (sbyte)(currentRgba32.G - previousPixel.G);
146-
sbyte diffBlue = (sbyte)(currentRgba32.B - previousPixel.B);
152+
int diffRed = currentRgba32.R - previousPixel.R;
153+
int diffGreen = currentRgba32.G - previousPixel.G;
154+
int diffBlue = currentRgba32.B - previousPixel.B;
147155

148156
// If so, we do a QOI_OP_DIFF
149157
if (diffRed is >= -2 and <= 1 &&
@@ -152,26 +160,26 @@ private void WritePixels<TPixel>(Image<TPixel> image, Stream stream)
152160
currentRgba32.A == previousPixel.A)
153161
{
154162
// Bottom limit is -2, so we add 2 to make it equal to 0
155-
byte dr = (byte)(diffRed + 2);
156-
byte dg = (byte)(diffGreen + 2);
157-
byte db = (byte)(diffBlue + 2);
158-
byte valueToWrite = (byte)((byte)QoiChunk.QoiOpDiff | (dr << 4) | (dg << 2) | db);
163+
int dr = diffRed + 2;
164+
int dg = diffGreen + 2;
165+
int db = diffBlue + 2;
166+
byte valueToWrite = (byte)((int)QoiChunk.QoiOpDiff | (dr << 4) | (dg << 2) | db);
159167
stream.WriteByte(valueToWrite);
160168
}
161169
else
162170
{
163171
// else, we check if the green difference is less than -32..31 and the rest -8..7
164172
// If so, we do a QOI_OP_LUMA
165-
sbyte diffRedGreen = (sbyte)(diffRed - diffGreen);
166-
sbyte diffBlueGreen = (sbyte)(diffBlue - diffGreen);
173+
int diffRedGreen = diffRed - diffGreen;
174+
int diffBlueGreen = diffBlue - diffGreen;
167175
if (diffGreen is >= -32 and <= 31 &&
168176
diffRedGreen is >= -8 and <= 7 &&
169177
diffBlueGreen is >= -8 and <= 7 &&
170178
currentRgba32.A == previousPixel.A)
171179
{
172-
byte dr_dg = (byte)(diffRedGreen + 8);
173-
byte db_dg = (byte)(diffBlueGreen + 8);
174-
byte byteToWrite1 = (byte)((byte)QoiChunk.QoiOpLuma | (diffGreen + 32));
180+
int dr_dg = diffRedGreen + 8;
181+
int db_dg = diffBlueGreen + 8;
182+
byte byteToWrite1 = (byte)((int)QoiChunk.QoiOpLuma | (diffGreen + 32));
175183
byte byteToWrite2 = (byte)((dr_dg << 4) | db_dg);
176184
stream.WriteByte(byteToWrite1);
177185
stream.WriteByte(byteToWrite2);

tests/ImageSharp.Benchmarks/Codecs/Qoi/IdentifyQoi.cs

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

tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,5 @@
6969
<Compile Remove="PixelBlenders\**" />
7070
<Compile Remove="Processing\Resize.cs" />
7171
</ItemGroup>
72-
<ItemGroup>
73-
<Folder Include="Codecs\Qoi\" />
74-
</ItemGroup>
7572

7673
</Project>

0 commit comments

Comments
 (0)