Skip to content

Commit 0dc1cb8

Browse files
committed
Added ReadAsync to MagickImage.
1 parent 87b571a commit 0dc1cb8

File tree

4 files changed

+336
-0
lines changed

4 files changed

+336
-0
lines changed

src/Magick.NET.Core/IMagickImage.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
using System.Collections.Generic;
1515
using System.Diagnostics.CodeAnalysis;
1616
using System.IO;
17+
#if NETSTANDARD
18+
using System.Threading.Tasks;
19+
#endif
1720

1821
namespace ImageMagick
1922
{
@@ -2609,6 +2612,25 @@ public interface IMagickImage : IDisposable
26092612
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
26102613
void Read(string fileName, MagickFormat format);
26112614

2615+
#if NETSTANDARD
2616+
/// <summary>
2617+
/// Read single image frame.
2618+
/// </summary>
2619+
/// <param name="stream">The stream to read the image data from.</param>
2620+
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
2621+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
2622+
Task ReadAsync(Stream stream);
2623+
2624+
/// <summary>
2625+
/// Read single image frame.
2626+
/// </summary>
2627+
/// <param name="stream">The stream to read the image data from.</param>
2628+
/// <param name="format">The format to use.</param>
2629+
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
2630+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
2631+
Task ReadAsync(Stream stream, MagickFormat format);
2632+
#endif
2633+
26122634
/// <summary>
26132635
/// Reduce noise in image using a noise peak elimination filter.
26142636
/// </summary>

src/Magick.NET.Core/IMagickImage{TQuantumType}.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
using System;
1414
using System.Collections.Generic;
1515
using System.IO;
16+
#if NETSTANDARD
17+
using System.Threading.Tasks;
18+
#endif
1619

1720
namespace ImageMagick
1821
{
@@ -724,6 +727,17 @@ public interface IMagickImage<TQuantumType> : IMagickImage, IEquatable<IMagickIm
724727
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
725728
void Read(string fileName, IMagickReadSettings<TQuantumType> readSettings);
726729

730+
#if NETSTANDARD
731+
/// <summary>
732+
/// Read single image frame.
733+
/// </summary>
734+
/// <param name="stream">The stream to read the image data from.</param>
735+
/// <param name="readSettings">The settings to use when reading the image.</param>
736+
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
737+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
738+
Task ReadAsync(Stream stream, IMagickReadSettings<TQuantumType> readSettings);
739+
#endif
740+
727741
/// <summary>
728742
/// Read single image frame.
729743
/// </summary>

src/Magick.NET/MagickImage.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
using System.Diagnostics.CodeAnalysis;
1717
using System.Globalization;
1818
using System.IO;
19+
#if NETSTANDARD
20+
using System.Threading.Tasks;
21+
#endif
1922

2023
#if Q8
2124
using QuantumType = System.Byte;
@@ -4989,6 +4992,47 @@ public void Read(string fileName, MagickFormat format)
49894992
public void Read(string fileName, IMagickReadSettings<QuantumType> readSettings)
49904993
=> Read(fileName, readSettings, false);
49914994

4995+
#if NETSTANDARD
4996+
/// <summary>
4997+
/// Read single image frame.
4998+
/// </summary>
4999+
/// <param name="stream">The stream to read the image data from.</param>
5000+
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
5001+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
5002+
public Task ReadAsync(Stream stream)
5003+
=> ReadAsync(stream, null);
5004+
5005+
/// <summary>
5006+
/// Read single image frame.
5007+
/// </summary>
5008+
/// <param name="stream">The stream to read the image data from.</param>
5009+
/// <param name="format">The format to use.</param>
5010+
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
5011+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
5012+
public Task ReadAsync(Stream stream, MagickFormat format)
5013+
=> ReadAsync(stream, new MagickReadSettings { Format = format });
5014+
5015+
/// <summary>
5016+
/// Read single image frame.
5017+
/// </summary>
5018+
/// <param name="stream">The stream to read the image data from.</param>
5019+
/// <param name="readSettings">The settings to use when reading the image.</param>
5020+
/// <exception cref="MagickException">Thrown when an error is raised by ImageMagick.</exception>
5021+
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
5022+
public async Task ReadAsync(Stream stream, IMagickReadSettings<QuantumType> readSettings)
5023+
{
5024+
Throw.IfNull(nameof(stream), stream);
5025+
5026+
using (var memStream = new MemoryStream())
5027+
{
5028+
await stream.CopyToAsync(memStream).ConfigureAwait(false);
5029+
5030+
memStream.Position = 0;
5031+
Read(memStream, readSettings, false);
5032+
}
5033+
}
5034+
#endif
5035+
49925036
/// <summary>
49935037
/// Read single image frame from pixel data.
49945038
/// </summary>
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
// Copyright 2013-2020 Dirk Lemstra <https://github.com/dlemstra/Magick.NET/>
2+
//
3+
// Licensed under the ImageMagick License (the "License"); you may not use this file except in
4+
// compliance with the License. You may obtain a copy of the License at
5+
//
6+
// https://www.imagemagick.org/script/license.php
7+
//
8+
// Unless required by applicable law or agreed to in writing, software distributed under the
9+
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
10+
// either express or implied. See the License for the specific language governing permissions
11+
// and limitations under the License.
12+
13+
#if NETCOREAPP
14+
using System;
15+
using System.IO;
16+
using System.Text;
17+
using System.Threading.Tasks;
18+
using ImageMagick;
19+
using Xunit;
20+
21+
namespace Magick.NET.Tests
22+
{
23+
public partial class MagickImageTests
24+
{
25+
public partial class TheReadAsyncMethod
26+
{
27+
public class WithStream
28+
{
29+
[Fact]
30+
public async Task ShouldThrowExceptionWhenStreamIsNull()
31+
{
32+
using (var image = new MagickImage())
33+
{
34+
await Assert.ThrowsAsync<ArgumentNullException>("stream", () => image.ReadAsync(null));
35+
}
36+
}
37+
38+
[Fact]
39+
public async Task ShouldThrowExceptionWhenStreamIsEmpty()
40+
{
41+
using (var image = new MagickImage())
42+
{
43+
await Assert.ThrowsAsync<ArgumentException>("stream", () => image.ReadAsync(new MemoryStream()));
44+
}
45+
}
46+
47+
[Fact]
48+
public async Task ShouldThrowExceptionWhenStreamIsNotReadable()
49+
{
50+
using (var testStream = new TestStream(false, true, true))
51+
{
52+
using (var image = new MagickImage())
53+
{
54+
await Assert.ThrowsAsync<NotSupportedException>(() => image.ReadAsync(testStream));
55+
}
56+
}
57+
}
58+
59+
[Fact]
60+
public async Task ShouldReadImage()
61+
{
62+
using (var image = new MagickImage())
63+
{
64+
using (var fileStream = File.OpenRead(Files.SnakewarePNG))
65+
{
66+
await image.ReadAsync(fileStream);
67+
Assert.Equal(286, image.Width);
68+
Assert.Equal(67, image.Height);
69+
Assert.Equal(MagickFormat.Png, image.Format);
70+
}
71+
}
72+
}
73+
74+
[Fact]
75+
public async Task ShouldReadImageFromSeekablePartialStream()
76+
{
77+
using (var image = new MagickImage())
78+
{
79+
using (var fileStream = File.OpenRead(Files.ImageMagickJPG))
80+
{
81+
await image.ReadAsync(fileStream);
82+
83+
fileStream.Position = 0;
84+
using (var partialStream = new PartialStream(fileStream, true))
85+
{
86+
using (var testImage = new MagickImage())
87+
{
88+
await testImage.ReadAsync(partialStream);
89+
90+
Assert.Equal(image.Width, testImage.Width);
91+
Assert.Equal(image.Height, testImage.Height);
92+
Assert.Equal(image.Format, testImage.Format);
93+
Assert.Equal(0.0, image.Compare(testImage, ErrorMetric.RootMeanSquared));
94+
}
95+
}
96+
}
97+
}
98+
}
99+
100+
[Fact]
101+
public async Task ShouldReadImageFromNonSeekablePartialStream()
102+
{
103+
using (var image = new MagickImage())
104+
{
105+
using (var fileStream = File.OpenRead(Files.ImageMagickJPG))
106+
{
107+
await image.ReadAsync(fileStream);
108+
109+
fileStream.Position = 0;
110+
using (var partialStream = new PartialStream(fileStream, false))
111+
{
112+
using (var testImage = new MagickImage())
113+
{
114+
await testImage.ReadAsync(partialStream);
115+
116+
Assert.Equal(image.Width, testImage.Width);
117+
Assert.Equal(image.Height, testImage.Height);
118+
Assert.Equal(image.Format, testImage.Format);
119+
Assert.Equal(0.0, image.Compare(testImage, ErrorMetric.RootMeanSquared));
120+
}
121+
}
122+
}
123+
}
124+
}
125+
}
126+
127+
public class WithStreamAndMagickFormat
128+
{
129+
[Fact]
130+
public async Task ShouldThrowExceptionWhenStreamIsNull()
131+
{
132+
using (var image = new MagickImage())
133+
{
134+
await Assert.ThrowsAsync<ArgumentNullException>("stream", () => image.ReadAsync(null, MagickFormat.Png));
135+
}
136+
}
137+
138+
[Fact]
139+
public async Task ShouldThrowExceptionWhenStreamIsEmpty()
140+
{
141+
using (var image = new MagickImage())
142+
{
143+
await Assert.ThrowsAsync<ArgumentException>("stream", () => image.ReadAsync(new MemoryStream(), MagickFormat.Png));
144+
}
145+
}
146+
147+
[Fact]
148+
public async Task ShouldUseTheCorrectReaderWhenFormatIsSet()
149+
{
150+
var bytes = Encoding.ASCII.GetBytes("%PDF-");
151+
152+
using (MemoryStream stream = new MemoryStream(bytes))
153+
{
154+
using (var image = new MagickImage())
155+
{
156+
var exception = await Assert.ThrowsAsync<MagickCorruptImageErrorException>(() => image.ReadAsync(stream, MagickFormat.Png));
157+
158+
Assert.Contains("ReadPNGImage", exception.Message);
159+
}
160+
}
161+
}
162+
163+
[Fact]
164+
public async Task ShouldResetTheFormatAfterReadingStream()
165+
{
166+
using (var stream = File.OpenRead(Files.CirclePNG))
167+
{
168+
using (var image = new MagickImage())
169+
{
170+
await image.ReadAsync(stream, MagickFormat.Png);
171+
172+
Assert.Equal(MagickFormat.Unknown, image.Settings.Format);
173+
}
174+
}
175+
}
176+
}
177+
178+
public class WithStreamAndMagickReadSettings
179+
{
180+
[Fact]
181+
public async Task ShouldThrowExceptionWhenStreamIsNull()
182+
{
183+
var settings = new MagickReadSettings();
184+
185+
using (var image = new MagickImage())
186+
{
187+
await Assert.ThrowsAsync<ArgumentNullException>("stream", () => image.ReadAsync(null, settings));
188+
}
189+
}
190+
191+
[Fact]
192+
public async Task ShouldThrowExceptionWhenStreamIsEmpty()
193+
{
194+
var settings = new MagickReadSettings();
195+
196+
using (var image = new MagickImage())
197+
{
198+
await Assert.ThrowsAsync<ArgumentException>("stream", () => image.ReadAsync(new MemoryStream(), settings));
199+
}
200+
}
201+
202+
[Fact]
203+
public async Task ShouldNotThrowExceptionWhenSettingsIsNull()
204+
{
205+
using (var fileStream = File.OpenRead(Files.CirclePNG))
206+
{
207+
using (var image = new MagickImage())
208+
{
209+
await image.ReadAsync(fileStream, null);
210+
}
211+
}
212+
}
213+
214+
[Fact]
215+
public async Task ShouldUseTheCorrectReaderWhenFormatIsSet()
216+
{
217+
var bytes = Encoding.ASCII.GetBytes("%PDF-");
218+
var settings = new MagickReadSettings
219+
{
220+
Format = MagickFormat.Png,
221+
};
222+
223+
using (MemoryStream stream = new MemoryStream(bytes))
224+
{
225+
using (var image = new MagickImage())
226+
{
227+
var exception = await Assert.ThrowsAsync<MagickCorruptImageErrorException>(() => image.ReadAsync(stream, settings));
228+
229+
Assert.Contains("ReadPNGImage", exception.Message);
230+
}
231+
}
232+
}
233+
234+
[Fact]
235+
public async Task ShouldResetTheFormatAfterReadingStream()
236+
{
237+
var readSettings = new MagickReadSettings
238+
{
239+
Format = MagickFormat.Png,
240+
};
241+
242+
using (var stream = File.OpenRead(Files.CirclePNG))
243+
{
244+
using (var image = new MagickImage())
245+
{
246+
await image.ReadAsync(stream, readSettings);
247+
248+
Assert.Equal(MagickFormat.Unknown, image.Settings.Format);
249+
}
250+
}
251+
}
252+
}
253+
}
254+
}
255+
}
256+
#endif

0 commit comments

Comments
 (0)