Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
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 PixelTypeInfo DetectPixelType(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, "stream");

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

/// <inheritdoc/>
public PixelTypeInfo DetectPixelType(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
int bitsPerPixel = (buffer[0] & 0x07) + 1; // The lowest 3 bits represent the bit depth minus 1
return new PixelTypeInfo(bitsPerPixel);
}
}
}
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 <see cref="PixelTypeInfo"/> object</returns>
PixelTypeInfo DetectPixelType(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 PixelTypeInfo DetectPixelType(Configuration configuration, Stream stream)
{
Guard.NotNull(stream, "stream");

using (JpegDecoderCore decoder = new JpegDecoderCore(configuration, this))
{
return new PixelTypeInfo(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
22 changes: 22 additions & 0 deletions src/ImageSharp/Formats/PixelTypeInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace ImageSharp.Formats
{
/// <summary>
/// Stores information about pixel
/// </summary>
public class PixelTypeInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="PixelTypeInfo"/> class.
/// </summary>
/// <param name="bitsPerPixel">color depth, in number of bits per pixel</param>
internal PixelTypeInfo(int bitsPerPixel)
{
this.BitsPerPixel = bitsPerPixel;
}

/// <summary>
/// Gets color depth, in number of bits per pixel
/// </summary>
public int BitsPerPixel { get; }
}
}
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 PixelTypeInfo DetectPixelType(Configuration configuration, Stream stream)
{
var decoder = new PngDecoderCore(configuration, this);
return new PixelTypeInfo(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 @@ -346,6 +398,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 <see cref="PixelTypeInfo"/> or null if suitable decoder not found.
/// </returns>
private static PixelTypeInfo InternalDetectPixelType(Stream stream, Configuration config)
{
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat _);
return decoder?.DetectPixelType(config, stream);
}
}
}
31 changes: 31 additions & 0 deletions src/ImageSharp/Image/Image.FromStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,37 @@ 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 <see cref="PixelTypeInfo"/> or null if suitable decoder not found.
/// </returns>
public static PixelTypeInfo DetectPixelType(Stream stream)
{
return DetectPixelType(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 <see cref="PixelTypeInfo"/> or null if suitable decoder not found.
/// </returns>
public static PixelTypeInfo DetectPixelType(Configuration config, Stream stream)
{
return WithSeekableStream(stream, s => InternalDetectPixelType(s, config ?? Configuration.Default));
}

/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
Expand Down
8 changes: 4 additions & 4 deletions src/ImageSharp/ImageSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta001">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.3.0" />
<PackageReference Include="System.Buffers" Version="4.4.0" />
<PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.Numerics.Vectors" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.4.0" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>
Expand Down
2 changes: 1 addition & 1 deletion tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Colourful" Version="1.1.2" />
<PackageReference Include="System.Numerics.Vectors" Version="4.3.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.4.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.10.7" />
Expand Down
22 changes: 18 additions & 4 deletions tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// <copyright file="BmpEncoderTests.cs" company="James Jackson-South">
// <copyright file="BmpDecoderTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>

using ImageSharp.Formats;

namespace ImageSharp.Tests
{
using System.IO;

using ImageSharp.PixelFormats;

using Xunit;
Expand All @@ -23,5 +23,19 @@ public void OpenAllBmpFiles_SaveBmp<TPixel>(TestImageProvider<TPixel> provider)
provider.Utility.SaveTestOutputFile(image, "bmp");
}
}

[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.DetectPixelType(stream)?.BitsPerPixel);
}
}
}
}
}
Loading