Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions src/BlurHashSharp.SkiaSharp/BlurHashEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ public static class BlurHashEncoder
/// <param name="yComponent">The number y components.</param>
/// <param name="stream">The IO stream of an encoded image.</param>
/// <returns>BlurHash representation of the image.</returns>
/// <exception cref="InvalidDataException">The image is in an unsupported format or could not be decoded.</exception>
public static string Encode(int xComponent, int yComponent, Stream stream)
{
using (SKCodec codec = SKCodec.Create(stream))
using (SKCodec codec = CreateCodec(stream))
{
return Encode(xComponent, yComponent, codec);
}
Expand All @@ -30,9 +31,11 @@ public static string Encode(int xComponent, int yComponent, Stream stream)
/// <param name="yComponent">The number y components.</param>
/// <param name="filename">The path to an encoded image on the file system.</param>
/// <returns>BlurHash representation of the image.</returns>
/// <exception cref="FileNotFoundException">The file does not exist.</exception>
/// <exception cref="InvalidDataException">The image is in an unsupported format or could not be decoded.</exception>
public static string Encode(int xComponent, int yComponent, string filename)
{
using (SKCodec codec = SKCodec.Create(filename))
using (SKCodec codec = CreateCodec(filename))
{
return Encode(xComponent, yComponent, codec);
}
Expand All @@ -49,7 +52,7 @@ internal static string Encode(int xComponent, int yComponent, SKCodec codec)
ColorSpace = SKColorSpace.CreateSrgb()
};

using (SKBitmap bitmap = SKBitmap.Decode(codec, newInfo))
using (SKBitmap bitmap = DecodeBitmap(codec, newInfo))
{
return EncodeInternal(xComponent, yComponent, bitmap);
}
Expand All @@ -64,9 +67,10 @@ internal static string Encode(int xComponent, int yComponent, SKCodec codec)
/// <param name="maxWidth">The maximum width to resize the image to.</param>
/// <param name="maxHeight">The maximum height to resize the image to.</param>
/// <returns>BlurHash representation of the image.</returns>
/// <exception cref="InvalidDataException">The image is in an unsupported format or could not be decoded.</exception>
public static string Encode(int xComponent, int yComponent, Stream stream, int maxWidth, int maxHeight)
{
using (SKCodec codec = SKCodec.Create(stream))
using (SKCodec codec = CreateCodec(stream))
{
return Encode(xComponent, yComponent, codec, maxWidth, maxHeight);
}
Expand All @@ -81,9 +85,11 @@ public static string Encode(int xComponent, int yComponent, Stream stream, int m
/// <param name="maxWidth">The maximum width to resize the image to.</param>
/// <param name="maxHeight">The maximum height to resize the image to.</param>
/// <returns>BlurHash representation of the image.</returns>
/// <exception cref="FileNotFoundException">The file does not exist.</exception>
/// <exception cref="InvalidDataException">The image is in an unsupported format or could not be decoded.</exception>
public static string Encode(int xComponent, int yComponent, string filename, int maxWidth, int maxHeight)
{
using (SKCodec codec = SKCodec.Create(filename))
using (SKCodec codec = CreateCodec(filename))
{
return Encode(xComponent, yComponent, codec, maxWidth, maxHeight);
}
Expand Down Expand Up @@ -111,7 +117,7 @@ internal static string Encode(int xComponent, int yComponent, SKCodec codec, int
ColorSpace = SKColorSpace.CreateSrgb()
};

using (SKBitmap bitmap = SKBitmap.Decode(codec, newInfo))
using (SKBitmap bitmap = DecodeBitmap(codec, newInfo))
{
if (scaleFactor == 0f)
{
Expand All @@ -129,6 +135,25 @@ internal static string Encode(int xComponent, int yComponent, SKCodec codec, int
}
}

private static SKCodec CreateCodec(Stream stream)
=> SKCodec.Create(stream)
?? throw new InvalidDataException("The stream does not contain an image in a format supported by SkiaSharp.");

private static SKCodec CreateCodec(string filename)
{
if (!File.Exists(filename))
{
throw new FileNotFoundException("The image file could not be found.", filename);
}

return SKCodec.Create(filename)
?? throw new InvalidDataException($"The file '{filename}' does not contain an image in a format supported by SkiaSharp.");
}

private static SKBitmap DecodeBitmap(SKCodec codec, SKImageInfo info)
=> SKBitmap.Decode(codec, info)
?? throw new InvalidDataException("The image could not be decoded; the data is corrupt or truncated.");

internal static string EncodeInternal(int xComponent, int yComponent, SKBitmap bitmap)
=> CoreBlurHashEncoder.Encode(xComponent, yComponent, bitmap.Width, bitmap.Height, bitmap.GetPixelSpan(), bitmap.RowBytes, PixelFormat.RGB888x);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using System;
using System.IO;
using Xunit;

namespace BlurHashSharp.SkiaSharp.Tests
{
public class BlurHashEncoderInvalidInputTests
{
// A 64x96 progressive JPEG cut off half way through its first scan: Skia reads the header
// and creates a codec, but decoding the pixels fails with InvalidInput.
private static readonly string TruncatedImagePath = Path.Join(AppContext.BaseDirectory, "TestData", "truncated-progressive.jpg");

private static byte[] UnrecognizedData()
{
var data = new byte[2048];
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)i;
}

return data;
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Encode_UnrecognizedStream_ThrowsInvalidDataException(bool resize)
{
using var stream = new MemoryStream(UnrecognizedData());

Assert.Throws<InvalidDataException>(() => resize
? BlurHashEncoder.Encode(4, 3, stream, 128, 128)
: BlurHashEncoder.Encode(4, 3, stream));
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Encode_UnrecognizedFile_ThrowsInvalidDataException(bool resize)
{
var path = Path.Join(Path.GetTempPath(), Path.GetRandomFileName() + ".jpg");
File.WriteAllBytes(path, UnrecognizedData());
try
{
Assert.Throws<InvalidDataException>(() => resize
? BlurHashEncoder.Encode(4, 3, path, 128, 128)
: BlurHashEncoder.Encode(4, 3, path));
}
finally
{
File.Delete(path);
}
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Encode_TruncatedStream_ThrowsInvalidDataException(bool resize)
{
using var stream = File.OpenRead(TruncatedImagePath);

Assert.Throws<InvalidDataException>(() => resize
? BlurHashEncoder.Encode(4, 3, stream, 32, 32)
: BlurHashEncoder.Encode(4, 3, stream));
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Encode_TruncatedFile_ThrowsInvalidDataException(bool resize)
{
Assert.Throws<InvalidDataException>(() => resize
? BlurHashEncoder.Encode(4, 3, TruncatedImagePath, 32, 32)
: BlurHashEncoder.Encode(4, 3, TruncatedImagePath));
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Encode_MissingFile_ThrowsFileNotFoundException(bool resize)
{
var path = Path.Join(Path.GetTempPath(), Path.GetRandomFileName() + ".png");

Assert.Throws<FileNotFoundException>(() => resize
? BlurHashEncoder.Encode(4, 3, path, 128, 128)
: BlurHashEncoder.Encode(4, 3, path));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="3.119.2" />
</ItemGroup>

<ItemGroup>
<None Include="TestData/**" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../../src/BlurHashSharp.SkiaSharp/BlurHashSharp.SkiaSharp.csproj" />
</ItemGroup>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.