Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f8573e3
Add an equivalent for System.Drawing.Image.GetPixelFormatSize() (#258)
Aug 10, 2017
a56893a
merge with master
Aug 14, 2017
1d81aed
fixes on code review
Aug 18, 2017
47454de
sync with upstream
Aug 24, 2017
ebe664c
update packages
Aug 24, 2017
d6a2d40
fix test image filename
Aug 24, 2017
75a89d6
sync with upstream
Sep 26, 2017
93419ab
fix bugs after merge
Sep 26, 2017
4a59c6f
remove duplicates in .csproj files
Sep 26, 2017
e1dcdef
Merge branch 'master' into master
xakep139 Sep 27, 2017
b5855a0
Merge branch 'master' into master
xakep139 Oct 4, 2017
79e2523
Merge branch 'master' into master
xakep139 Oct 6, 2017
d0e802d
Merge branch 'master' into master
xakep139 Oct 9, 2017
d204e88
Merge branch 'master' into master
xakep139 Oct 10, 2017
a44ceb8
merge with upstream
Oct 13, 2017
68af168
Merge branch 'master' of https://github.com/xakep139/ImageSharp
Oct 13, 2017
8ad7769
Merge branch 'master' into master
xakep139 Oct 18, 2017
5fa82af
Merge branch 'master' into master
xakep139 Nov 23, 2017
d2c0338
Merge branch 'master' into master
xakep139 Dec 8, 2017
75efd72
Merge branch 'master' into master
xakep139 Jan 10, 2018
def3d93
Merge branch 'master' into master
xakep139 Jan 17, 2018
a631a64
Added an API to read base image information without decoding it
denisivan0v Jan 17, 2018
52af4e3
Merge branch 'master' of https://github.com/xakep139/ImageSharp
denisivan0v Jan 17, 2018
b435f5e
codestyle fixes
denisivan0v Jan 17, 2018
9f719d5
codestyle fix
denisivan0v Jan 17, 2018
e88e138
bugfix in GifDecoderCore.Identity
denisivan0v Jan 18, 2018
61c9caf
changes on code review
denisivan0v Jan 19, 2018
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
11 changes: 11 additions & 0 deletions src/ImageSharp/Formats/Bmp/BmpDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,16 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)

return new BmpDecoderCore(configuration, this).Decode<TPixel>(stream);
}

/// <inheritdoc/>
public int DetectPixelSize(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, "stream");

byte[] buffer = new byte[2];
stream.Skip(28);
stream.Read(buffer, 0, 2);
return BitConverter.ToInt16(buffer, 0);
}
}
}
11 changes: 11 additions & 0 deletions src/ImageSharp/Formats/Gif/GifDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,16 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
var decoder = new GifDecoderCore<TPixel>(configuration, this);
return decoder.Decode(stream);
}

/// <inheritdoc/>
public int DetectPixelSize(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, "stream");

byte[] buffer = new byte[1];
stream.Skip(10); // Skip the identifier and size
stream.Read(buffer, 0, 1); // Skip the identifier and size
return (buffer[0] & 0x07) + 1; // The lowest 3 bits represent the bit depth minus 1
}
}
}
8 changes: 8 additions & 0 deletions src/ImageSharp/Formats/IImageDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,13 @@ public interface IImageDecoder
/// <returns>The decoded image</returns>
Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>;

/// <summary>
/// Detects the image pixel size from the specified stream.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The color depth, in number of bits per pixel</returns>
int DetectPixelSize(Configuration configuration, Stream stream);
}
}
11 changes: 11 additions & 0 deletions src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,16 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
return decoder.Decode<TPixel>(stream);
}
}

/// <inheritdoc/>
public int DetectPixelSize(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, "stream");

using (JpegDecoderCore decoder = new JpegDecoderCore(configuration, this))
{
return decoder.DetectPixelSize(stream);
}
}
}
}
22 changes: 19 additions & 3 deletions src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ internal sealed unsafe class JpegDecoderCore : IDisposable
/// </summary>
public const int MaxTq = 3;

/// <summary>
/// The only supported precision
/// </summary>
public const int SupportedPrecision = 8;

// Complex value type field + mutable + available to other classes = the field MUST NOT be private :P
#pragma warning disable SA1401 // FieldsMustBePrivate

Expand Down Expand Up @@ -191,7 +196,7 @@ public JpegDecoderCore(Configuration configuration, IJpegDecoderOptions options)
public bool IgnoreMetadata { get; private set; }

/// <summary>
/// Decodes the image from the specified <see cref="Stream"/> and sets
/// Decodes the image from the specified <see cref="Stream"/> and sets
/// the data to image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
Expand All @@ -208,6 +213,17 @@ public Image<TPixel> Decode<TPixel>(Stream stream)
return image;
}

/// <summary>
/// Detects the image pixel size from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The color depth, in number of bits per pixel</returns>
public int DetectPixelSize(Stream stream)
{
this.ProcessStream(new ImageMetaData(), stream, true);
return this.ComponentCount * SupportedPrecision;
}

/// <summary>
/// Dispose
/// </summary>
Expand Down Expand Up @@ -1196,7 +1212,7 @@ private void ProcessStartOfFrameMarker(int remaining)
this.InputProcessor.ReadFull(this.Temp, 0, remaining);

// We only support 8-bit precision.
if (this.Temp[0] != 8)
if (this.Temp[0] != SupportedPrecision)
{
throw new ImageFormatException("Only 8-Bit precision supported.");
}
Expand Down Expand Up @@ -1238,7 +1254,7 @@ private void ProcessStartOfFrameMarker(int remaining)

if (h == 3 || v == 3)
{
throw new ImageFormatException("Lnsupported subsampling ratio");
throw new ImageFormatException("Unsupported subsampling ratio");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix typo

}

switch (this.ComponentCount)
Expand Down
12 changes: 12 additions & 0 deletions src/ImageSharp/Formats/Png/PngDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,17 @@ public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
var decoder = new PngDecoderCore(configuration, this);
return decoder.Decode<TPixel>(stream);
}

/// <summary>
/// Detects the image pixel size from the specified stream.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The color depth, in number of bits per pixel</returns>
public int DetectPixelSize(Configuration configuration, Stream stream)
{
var decoder = new PngDecoderCore(configuration, this);
return decoder.DetectPixelSize(stream);
}
}
}
74 changes: 74 additions & 0 deletions src/ImageSharp/Formats/Png/PngDecoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,58 @@ public Image<TPixel> Decode<TPixel>(Stream stream)
}
}

/// <summary>
/// Detects the image pixel size from the specified stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The color depth, in number of bits per pixel</returns>
public int DetectPixelSize(Stream stream)
{
this.currentStream = stream;
this.currentStream.Skip(8);
try
{
PngChunk currentChunk;
while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
{
try
{
switch (currentChunk.Type)
{
case PngChunkTypes.Header:
this.ReadHeaderChunk(currentChunk.Data);
this.ValidateHeader();
this.isEndChunkReached = true;
break;
case PngChunkTypes.End:
this.isEndChunkReached = true;
break;
}
}
finally
{
// Data is rented in ReadChunkData()
if (currentChunk.Data != null)
{
ArrayPool<byte>.Shared.Return(currentChunk.Data);
}
}
}
}
finally
{
this.scanline?.Dispose();
this.previousScanline?.Dispose();
}

if (this.header == null)
{
throw new ImageFormatException("PNG Image hasn't header chunk");
}

return this.CalculateBitsPerPixel();
}

/// <summary>
/// Converts a byte array to a new array where each value in the original array is represented by the specified number of bits.
/// </summary>
Expand Down Expand Up @@ -343,6 +395,28 @@ private void InitializeImage<TPixel>(ImageMetaData metadata, out Image<TPixel> i
this.scanline = Buffer<byte>.CreateClean(this.bytesPerScanline);
}

/// <summary>
/// Calculates the correct number of bits per pixel for the given color type.
/// </summary>
/// <returns>The <see cref="int"/></returns>
private int CalculateBitsPerPixel()
{
switch (this.pngColorType)
{
case PngColorType.Grayscale:
case PngColorType.Palette:
return this.header.BitDepth;
case PngColorType.GrayscaleWithAlpha:
return this.header.BitDepth * 2;
case PngColorType.Rgb:
return this.header.BitDepth * 3;
case PngColorType.RgbWithAlpha:
return this.header.BitDepth * 4;
default:
throw new NotSupportedException("Unsupported PNG color type");
}
}

/// <summary>
/// Calculates the correct number of bytes per pixel for the given color type.
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions src/ImageSharp/Image/Image.Decode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,19 @@ private static (Image<TPixel> img, IImageFormat format) Decode<TPixel>(Stream st
Image<TPixel> img = decoder.Decode<TPixel>(config, stream);
return (img, format);
}

/// <summary>
/// Detects the image pixel size.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="config">the configuration.</param>
/// <returns>
/// The color depth, in number of bits per pixel or null if suitable decoder not found.
/// </returns>
private static int? InternalDetectPixelSize(Stream stream, Configuration config)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat _);
return decoder?.DetectPixelSize(config, stream);
}
}
}
27 changes: 27 additions & 0 deletions src/ImageSharp/Image/Image.FromStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,33 @@ public static IImageFormat DetectFormat(Configuration config, Stream stream)
return WithSeekableStream(stream, s => InternalDetectFormat(s, config ?? Configuration.Default));
}

/// <summary>
/// By reading the header on the provided stream this calculates the images color depth.
/// </summary>
/// <param name="stream">The image stream to read the header from.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The color depth, in number of bits per pixel or null if suitable decoder not found</returns>
public static int? DetectPixelSize(Stream stream)
{
return DetectPixelSize(null, stream);
}

/// <summary>
/// By reading the header on the provided stream this calculates the images color depth.
/// </summary>
/// <param name="config">The configuration.</param>
/// <param name="stream">The image stream to read the header from.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The color depth, in number of bits per pixel or null if suitable decoder not found</returns>
public static int? DetectPixelSize(Configuration config, Stream stream)
{
return WithSeekableStream(stream, s => InternalDetectPixelSize(s, config ?? Configuration.Default));
}

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
Expand Down
29 changes: 29 additions & 0 deletions tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// <copyright file="GifDecoderTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>

// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests
{
using System.IO;

using Xunit;

public class BmpDecoderTests
{
[Theory]
[InlineData(TestImages.Bmp.Car, 24)]
[InlineData(TestImages.Bmp.F, 24)]
[InlineData(TestImages.Bmp.NegHeight, 24)]
[InlineData(TestImages.Bmp.Bpp8, 8)]
public void DetectPixelSize(string imagePath, int expectedPixelSize)
{
TestFile testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
Assert.Equal(expectedPixelSize, Image.DetectPixelSize(stream));
}
}
}
}
15 changes: 15 additions & 0 deletions tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests
{
using System.IO;
using System.Text;
using Xunit;

Expand Down Expand Up @@ -80,5 +81,19 @@ public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding()
Assert.Equal("浉条卥慨灲", image.MetaData.Properties[0].Value);
}
}

[Theory]
[InlineData(TestImages.Gif.Cheers, 8)]
[InlineData(TestImages.Gif.Giphy, 8)]

@xakep139 xakep139 Aug 11, 2017

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these two GIFs Image.GetPixelFormatSize() returns 32 which is not correct

[InlineData(TestImages.Gif.Rings, 8)]
[InlineData(TestImages.Gif.Trans, 8)]
public void DetectPixelSize(string imagePath, int expectedPixelSize)
{
TestFile testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
Assert.Equal(expectedPixelSize, Image.DetectPixelSize(stream));
}
}
}
}
16 changes: 16 additions & 0 deletions tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,5 +152,21 @@ public void Decode_IgnoreMetadataIsTrue_ExifProfileIgnored()
Assert.Null(image.MetaData.ExifProfile);
}
}

[Theory]
[InlineData(TestImages.Jpeg.Progressive.Progress, 24)]
[InlineData(TestImages.Jpeg.Progressive.Fb, 24)]
[InlineData(TestImages.Jpeg.Baseline.Cmyk, 32)]
[InlineData(TestImages.Jpeg.Baseline.Ycck, 32)]
[InlineData(TestImages.Jpeg.Baseline.Jpeg400, 8)]
[InlineData(TestImages.Jpeg.Baseline.Snake, 24)]
public void DetectPixelSize(string imagePath, int expectedPixelSize)
{
TestFile testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
Assert.Equal(expectedPixelSize, Image.DetectPixelSize(stream));
}
}
}
}
18 changes: 18 additions & 0 deletions tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace ImageSharp.Tests
{
using System.IO;
using System.Text;
using Xunit;

Expand Down Expand Up @@ -82,5 +83,22 @@ public void Decode_TextEncodingSetToUnicode_TextIsReadWithCorrectEncoding()
Assert.Equal("潓瑦慷敲", image.MetaData.Properties[0].Name);
}
}

[Theory]
[InlineData(TestImages.Png.Bpp1, 1)]
[InlineData(TestImages.Png.Gray4Bpp, 4)]
[InlineData(TestImages.Png.Palette8Bpp, 8)]
[InlineData(TestImages.Png.Pd, 24)]
[InlineData(TestImages.Png.Blur, 32)]
[InlineData(TestImages.Png.Rgb48Bpp, 48)]
[InlineData(TestImages.Png.Rgb48BppInterlaced, 48)]
public void DetectPixelSize(string imagePath, int expectedPixelSize)
{
TestFile testFile = TestFile.Create(imagePath);
using (var stream = new MemoryStream(testFile.Bytes, false))
{
Assert.Equal(expectedPixelSize, Image.DetectPixelSize(stream));
}
}
}
}
Loading