Skip to content

Commit 4d844ba

Browse files
Merge branch 'main' into js/parallel-cleanup
2 parents 418f9c3 + b3f3793 commit 4d844ba

File tree

88 files changed

+5351
-35
lines changed

Some content is hidden

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

88 files changed

+5351
-35
lines changed

ImageSharp.sln

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3
3737
ProjectSection(SolutionItems) = preProject
3838
src\Directory.Build.props = src\Directory.Build.props
3939
src\Directory.Build.targets = src\Directory.Build.targets
40-
src\README.md = src\README.md
4140
src\ImageSharp.ruleset = src\ImageSharp.ruleset
41+
src\README.md = src\README.md
4242
EndProjectSection
4343
EndProject
4444
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}"
@@ -215,6 +215,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68
215215
ProjectSection(SolutionItems) = preProject
216216
tests\Images\Input\Jpg\issues\issue-1076-invalid-subsampling.jpg = tests\Images\Input\Jpg\issues\issue-1076-invalid-subsampling.jpg
217217
tests\Images\Input\Jpg\issues\issue-1221-identify-multi-frame.jpg = tests\Images\Input\Jpg\issues\issue-1221-identify-multi-frame.jpg
218+
tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg
218219
tests\Images\Input\Jpg\issues\issue1006-incorrect-resize.jpg = tests\Images\Input\Jpg\issues\issue1006-incorrect-resize.jpg
219220
tests\Images\Input\Jpg\issues\issue1049-exif-resize.jpg = tests\Images\Input\Jpg\issues\issue1049-exif-resize.jpg
220221
tests\Images\Input\Jpg\issues\Issue159-MissingFF00-Progressive-Bedroom.jpg = tests\Images\Input\Jpg\issues\Issue159-MissingFF00-Progressive-Bedroom.jpg
@@ -238,7 +239,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68
238239
tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg = tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg
239240
tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg = tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg
240241
tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg = tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg
241-
tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg
242242
EndProjectSection
243243
EndProject
244244
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fuzz", "fuzz", "{516A3532-6AC2-417B-AD79-9BD5D0D378A0}"

src/ImageSharp/Common/Helpers/ColorNumerics.cs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public static ushort Get16BitBT709Luminance(float r, float g, float b)
9797
/// Scales a value from a 16 bit <see cref="ushort"/> to an
9898
/// 8 bit <see cref="byte"/> equivalent.
9999
/// </summary>
100-
/// <param name="component">The 8 bit component value.</param>
100+
/// <param name="component">The 16 bit component value.</param>
101101
/// <returns>The <see cref="byte"/></returns>
102102
[MethodImpl(MethodImplOptions.AggressiveInlining)]
103103
public static byte From16BitTo8Bit(ushort component) =>
@@ -132,6 +132,49 @@ public static byte From16BitTo8Bit(ushort component) =>
132132
// (V * 255 + 32895) >> 16
133133
(byte)(((component * 255) + 32895) >> 16);
134134

135+
/// <summary>
136+
/// Scales a value from a 32 bit <see cref="uint"/> to an
137+
/// 8 bit <see cref="byte"/> equivalent.
138+
/// </summary>
139+
/// <param name="component">The 32 bit component value.</param>
140+
/// <returns>The <see cref="byte"/> value.</returns>
141+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
142+
public static byte From32BitTo8Bit(uint component) =>
143+
144+
// To scale to 8 bits from a 32-bit value V the required value is:
145+
//
146+
// (V * 255) / 4294967295
147+
//
148+
// Since:
149+
//
150+
// 4294967295 = 255 * 16843009
151+
//
152+
// this reduces exactly to:
153+
//
154+
// V / 16843009
155+
//
156+
// To round to nearest using integer arithmetic we add half the divisor
157+
// before dividing:
158+
//
159+
// (V + 16843009 / 2) / 16843009
160+
//
161+
// where:
162+
//
163+
// 16843009 / 2 = 8421504.5
164+
//
165+
// Using 8421504 ensures correct round-to-nearest behaviour:
166+
//
167+
// 8421504 -> 0
168+
// 8421505 -> 1
169+
//
170+
// The addition must be performed in 64-bit to avoid overflow for large
171+
// input values (for example uint.MaxValue).
172+
//
173+
// Final exact integer implementation:
174+
//
175+
// ((ulong)V + 8421504) / 16843009
176+
(byte)((component + 8421504UL) / 16843009UL);
177+
135178
/// <summary>
136179
/// Scales a value from an 8 bit <see cref="byte"/> to
137180
/// an 16 bit <see cref="ushort"/> equivalent.
@@ -142,6 +185,26 @@ public static byte From16BitTo8Bit(ushort component) =>
142185
public static ushort From8BitTo16Bit(byte component)
143186
=> (ushort)(component * 257);
144187

188+
/// <summary>
189+
/// Scales a value from an 16 bit <see cref="byte"/> to
190+
/// an 16 bit <see cref="uint"/> equivalent.
191+
/// </summary>
192+
/// <param name="component">The 16 bit component value.</param>
193+
/// <returns>The 32 bit <see cref="uint"/></returns>
194+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
195+
public static uint From16BitTo32Bit(ushort component)
196+
=> (uint)(component * 65537);
197+
198+
/// <summary>
199+
/// Scales a value from an 8 bit <see cref="byte"/> to
200+
/// an 32 bit <see cref="ushort"/> equivalent.
201+
/// </summary>
202+
/// <param name="component">The 8 bit component value.</param>
203+
/// <returns>The 32 bit <see cref="uint"/></returns>
204+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
205+
public static uint From8BitTo32Bit(byte component)
206+
=> (uint)(component * 16843009);
207+
145208
/// <summary>
146209
/// Returns how many bits are required to store the specified number of colors.
147210
/// Performs a Log2() on the value.

src/ImageSharp/Configuration.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using SixLabors.ImageSharp.Formats;
66
using SixLabors.ImageSharp.Formats.Bmp;
77
using SixLabors.ImageSharp.Formats.Cur;
8+
using SixLabors.ImageSharp.Formats.Exr;
89
using SixLabors.ImageSharp.Formats.Gif;
910
using SixLabors.ImageSharp.Formats.Ico;
1011
using SixLabors.ImageSharp.Formats.Jpeg;
@@ -214,6 +215,7 @@ public void Configure(IImageFormatConfigurationModule configuration)
214215
/// <see cref="TgaConfigurationModule"/>.
215216
/// <see cref="TiffConfigurationModule"/>.
216217
/// <see cref="WebpConfigurationModule"/>.
218+
/// <see cref="ExrConfigurationModule"/>.
217219
/// <see cref="QoiConfigurationModule"/>.
218220
/// </summary>
219221
/// <returns>The default configuration of <see cref="Configuration"/>.</returns>
@@ -226,6 +228,7 @@ public void Configure(IImageFormatConfigurationModule configuration)
226228
new TgaConfigurationModule(),
227229
new TiffConfigurationModule(),
228230
new WebpConfigurationModule(),
231+
new ExrConfigurationModule(),
229232
new QoiConfigurationModule(),
230233
new IcoConfigurationModule(),
231234
new CurConfigurationModule());

src/ImageSharp/Formats/Bmp/BmpConstants.cs

Lines changed: 1 addition & 1 deletion
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 Six Labors Split License.
33

44
namespace SixLabors.ImageSharp.Formats.Bmp;

src/ImageSharp/Formats/Bmp/BmpFormat.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ private BmpFormat()
3030
public IEnumerable<string> FileExtensions => BmpConstants.FileExtensions;
3131

3232
/// <inheritdoc/>
33-
public BmpMetadata CreateDefaultFormatMetadata() => new();
33+
public BmpMetadata CreateDefaultFormatMetadata() => new BmpMetadata();
3434
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Memory;
5+
6+
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
7+
8+
/// <summary>
9+
/// Compressor for EXR image data which does not use any compression method.
10+
/// </summary>
11+
internal class NoneExrCompressor : ExrBaseCompressor
12+
{
13+
/// <summary>
14+
/// Initializes a new instance of the <see cref="NoneExrCompressor"/> class.
15+
/// </summary>
16+
/// <param name="output">The output stream to write the compressed image data to.</param>
17+
/// <param name="allocator">The memory allocator.</param>
18+
/// <param name="bytesPerBlock">Bytes per row block.</param>
19+
/// <param name="bytesPerRow">Bytes per pixel row.</param>
20+
public NoneExrCompressor(Stream output, MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow)
21+
: base(output, allocator, bytesPerBlock, bytesPerRow)
22+
{
23+
}
24+
25+
/// <inheritdoc/>
26+
public override uint CompressRowBlock(Span<byte> rows, int rowCount)
27+
{
28+
this.Output.Write(rows);
29+
return (uint)rows.Length;
30+
}
31+
32+
/// <inheritdoc/>
33+
protected override void Dispose(bool disposing)
34+
{
35+
}
36+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Six Labors Split License.
3+
4+
using SixLabors.ImageSharp.Compression.Zlib;
5+
using SixLabors.ImageSharp.Memory;
6+
7+
namespace SixLabors.ImageSharp.Formats.Exr.Compression.Compressors;
8+
9+
/// <summary>
10+
/// Compressor for EXR image data using the ZIP compression.
11+
/// </summary>
12+
internal class ZipExrCompressor : ExrBaseCompressor
13+
{
14+
private readonly DeflateCompressionLevel compressionLevel;
15+
16+
private readonly MemoryStream memoryStream;
17+
18+
private readonly System.Buffers.IMemoryOwner<byte> buffer;
19+
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="ZipExrCompressor"/> class.
22+
/// </summary>
23+
/// <param name="output">The stream to write the compressed data to.</param>
24+
/// <param name="allocator">The memory allocator.</param>
25+
/// <param name="bytesPerBlock">The bytes per block.</param>
26+
/// <param name="bytesPerRow">The bytes per row.</param>
27+
/// <param name="compressionLevel">The compression level for deflate compression.</param>
28+
public ZipExrCompressor(Stream output, MemoryAllocator allocator, uint bytesPerBlock, uint bytesPerRow, DeflateCompressionLevel compressionLevel)
29+
: base(output, allocator, bytesPerBlock, bytesPerRow)
30+
{
31+
this.compressionLevel = compressionLevel;
32+
this.buffer = allocator.Allocate<byte>((int)bytesPerBlock);
33+
this.memoryStream = new();
34+
}
35+
36+
/// <inheritdoc/>
37+
public override uint CompressRowBlock(Span<byte> rows, int rowCount)
38+
{
39+
// Re-oder pixel values.
40+
Span<byte> reordered = this.buffer.GetSpan()[..(int)(rowCount * this.BytesPerRow)];
41+
int n = reordered.Length;
42+
int t1 = 0;
43+
int t2 = (n + 1) >> 1;
44+
for (int i = 0; i < n; i++)
45+
{
46+
bool isOdd = (i & 1) == 1;
47+
reordered[isOdd ? t2++ : t1++] = rows[i];
48+
}
49+
50+
// Predictor.
51+
Span<byte> predicted = reordered;
52+
byte p = predicted[0];
53+
for (int i = 1; i < predicted.Length; i++)
54+
{
55+
int d = (predicted[i] - p + 128 + 256) & 255;
56+
p = predicted[i];
57+
predicted[i] = (byte)d;
58+
}
59+
60+
this.memoryStream.Seek(0, SeekOrigin.Begin);
61+
using (ZlibDeflateStream stream = new(this.Allocator, this.memoryStream, this.compressionLevel))
62+
{
63+
stream.Write(predicted);
64+
stream.Flush();
65+
}
66+
67+
int size = (int)this.memoryStream.Position;
68+
byte[] buffer = this.memoryStream.GetBuffer();
69+
this.Output.Write(buffer, 0, size);
70+
71+
// Reset memory stream for next pixel row.
72+
this.memoryStream.Seek(0, SeekOrigin.Begin);
73+
this.memoryStream.SetLength(0);
74+
75+
return (uint)size;
76+
}
77+
78+
/// <inheritdoc/>
79+
protected override void Dispose(bool disposing)
80+
{
81+
this.buffer.Dispose();
82+
this.memoryStream?.Dispose();
83+
}
84+
}

0 commit comments

Comments
 (0)