Browse Source

Merge branch 'master' into colorspace-transforms

af/merge-core
James Jackson-South 8 years ago
parent
commit
21ef3eeba6
  1. 32
      README.md
  2. 8
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  3. 10
      src/ImageSharp.Drawing/Processing/Drawing/DrawImageExtensions.cs
  4. 2
      src/ImageSharp.Drawing/Processing/Drawing/DrawRectangleExtensions.cs
  5. 4
      src/ImageSharp.Drawing/Processing/Drawing/FillRectangleExtensions.cs
  6. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs
  7. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs
  8. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs
  9. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs
  10. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs
  11. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs
  12. 33
      src/ImageSharp/Common/Extensions/ByteExtensions.cs
  13. 28
      src/ImageSharp/Common/Helpers/Guard.cs
  14. 10
      src/ImageSharp/Formats/Gif/GifConstants.cs
  15. 4
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  16. 82
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  17. 100
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  18. 25
      src/ImageSharp/Formats/Png/Zlib/Adler32.cs
  19. 23
      src/ImageSharp/Formats/Png/Zlib/Crc32.cs
  20. 22
      src/ImageSharp/Formats/Png/Zlib/IChecksum.cs
  21. 2
      src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs
  22. 84
      src/ImageSharp/IO/BigEndianBitConverter.cs
  23. 277
      src/ImageSharp/IO/EndianBinaryReader.cs
  24. 188
      src/ImageSharp/IO/EndianBinaryWriter.cs
  25. 61
      src/ImageSharp/IO/EndianBitConverter.Conversion.cs
  26. 143
      src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs
  27. 137
      src/ImageSharp/IO/EndianBitConverter.GetBytes.cs
  28. 139
      src/ImageSharp/IO/EndianBitConverter.ToType.cs
  29. 127
      src/ImageSharp/IO/EndianBitConverter.cs
  30. 81
      src/ImageSharp/IO/LittleEndianBitConverter.cs
  31. 16
      src/ImageSharp/Image.LoadPixelData.cs
  32. 7
      src/ImageSharp/ImageFrame.LoadPixelData.cs
  33. 2
      src/ImageSharp/ImageFrame{TPixel}.cs
  34. 4
      src/ImageSharp/ImageSharp.csproj
  35. 2
      src/ImageSharp/Memory/BasicArrayBuffer.cs
  36. 40
      src/ImageSharp/Memory/SpanHelper.cs
  37. 25
      src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs
  38. 6
      src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs
  39. 2
      src/ImageSharp/PixelAccessor{TPixel}.cs
  40. 56
      src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs
  41. 14
      src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt
  42. 12
      src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs
  43. 4
      src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt
  44. 30
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  45. 16
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  46. 4
      src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs
  47. 2
      src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs
  48. 2
      tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs
  49. 57
      tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs
  50. 75
      tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs
  51. 57
      tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs
  52. 32
      tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs
  53. 35
      tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs
  54. 28
      tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs
  55. 63
      tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs
  56. 37
      tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs
  57. 31
      tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs
  58. 63
      tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs
  59. 32
      tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs
  60. 2
      tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs
  61. 43
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs
  62. 25
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs
  63. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs
  64. 30
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs
  65. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs
  66. 2
      tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
  67. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
  68. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  69. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  70. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  71. 2
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  72. 2
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs
  73. 2
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs
  74. 2
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs
  75. 2
      tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs
  76. 2
      tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs
  77. 5
      tests/ImageSharp.Benchmarks/Config.cs
  78. 10
      tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs
  79. 56
      tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs
  80. 74
      tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs
  81. 56
      tests/ImageSharp.Benchmarks/Image/DecodeGif.cs
  82. 43
      tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs
  83. 63
      tests/ImageSharp.Benchmarks/Image/EncodeGif.cs
  84. 54
      tests/ImageSharp.Benchmarks/Image/EncodeGifMultiple.cs
  85. 83
      tests/ImageSharp.Benchmarks/Image/EncodePng.cs
  86. 41
      tests/ImageSharp.Benchmarks/Image/GetSetPixel.cs
  87. 44
      tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs
  88. 8
      tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs
  89. 2
      tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs
  90. 228
      tests/ImageSharp.Tests/IO/BigEndianBitConverter.CopyBytesTests.cs
  91. 129
      tests/ImageSharp.Tests/IO/BigEndianBitConverter.GetBytesTests.cs
  92. 216
      tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs
  93. 61
      tests/ImageSharp.Tests/IO/EndianBinaryReaderTests.cs
  94. 97
      tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs
  95. 228
      tests/ImageSharp.Tests/IO/LittleEndianBitConverter.CopyBytesTests.cs
  96. 129
      tests/ImageSharp.Tests/IO/LittleEndianBitConverter.GetBytesTests.cs
  97. 214
      tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs
  98. 15
      tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
  99. 2
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs

32
README.md

@ -1,16 +1,21 @@
<h1 align="center"> <h1 align="center">
<img src="https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-256.png" alt="ImageSharp" width="175"/>
<br> <img src="https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.512.png" alt="SixLabors.ImageSharp" width="256"/>
ImageSharp <br/>
<br> SixLabors.ImageSharp
<br>
<a href="https://raw.githubusercontent.com/SixLabors/ImageSharp/master/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202-blue.svg" alt="GitHub license" data-canonical-src="https://img.shields.io/badge/license-Apache%202-blue.svg" style="max-width:100%;"></a>
<a href="https://gitter.im/ImageSharp/General?utm_source=badge&amp;utm_medium=badge&amp;utm_campaign=pr-badge&amp;utm_content=badge"><img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter" data-canonical-src="https://badges.gitter.im/Join%20Chat.svg" style="max-width:100%;"></a>
<a href="https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&amp;text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&amp;url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&amp;via=sixlabors"><img src="https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter" alt="Twitter" data-canonical-src="https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter" style="max-width:100%;"></a>
<a href="#backers"><img src="https://opencollective.com/imagesharp/backers/badge.svg" alt="OpenCollective" data-canonical-src="https://opencollective.com/imagesharp/backers/badge.svg" style="max-width:100%;"></a>
<a href="#sponsors"><img src="https://opencollective.com/imagesharp/sponsors/badge.svg" alt="OpenCollective" data-canonical-src="https://opencollective.com/imagesharp/sponsors/badge.svg" style="max-width:100%;"></a>
</h1> </h1>
<div align="center">
[![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/SixLabors/ImageSharp/master/LICENSE)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/ImageSharp/General?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=flat&logo=twitter)](https://twitter.com/intent/tweet?hashtags=imagesharp,dotnet,oss&text=ImageSharp.+A+new+cross-platform+2D+graphics+API+in+C%23&url=https%3a%2f%2fgithub.com%2fSixLabors%2fImageSharp&via=sixlabors)
[![OpenCollective](https://opencollective.com/imagesharp/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/imagesharp/sponsors/badge.svg)](#sponsors)
</div>
### **ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API. ### **ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API.
Designed to democratize image processing, ImageSharp brings you an incredibly powerful yet beautifully simple API. Designed to democratize image processing, ImageSharp brings you an incredibly powerful yet beautifully simple API.
@ -21,7 +26,7 @@ Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and emb
### Installation ### Installation
Install stable releases via Nuget;evelopment releases are available via MyGet. Install stable releases via Nuget; development releases are available via MyGet.
| Package Name | Release (NuGet) | Nightly (MyGet) | | Package Name | Release (NuGet) | Nightly (MyGet) |
|--------------------------------|-----------------|-----------------| |--------------------------------|-----------------|-----------------|
@ -51,7 +56,8 @@ The **ImageSharp** library is made up of multiple packages:
### Questions? ### Questions?
Do you have questions? We are happy to help! Please [join our gitter channel](https://gitter.im/ImageSharp/General), or ask them on [stackoverflow](https://stackoverflow.com) using the `ImageSharp` tag. - Do you have questions? We are happy to help! Please [join our gitter channel](https://gitter.im/ImageSharp/General), or ask them on [stackoverflow](https://stackoverflow.com) using the `ImageSharp` tag. **Do not** open issues for questions!
- Please read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening issues or pull requests!
### API ### API
@ -122,7 +128,7 @@ git clone https://github.com/SixLabors/ImageSharp
### How can you help? ### How can you help?
Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Make sure to read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/master/.github/CONTRIBUTING.md) before opening a PR.
### The ImageSharp Team ### The ImageSharp Team

8
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -11,7 +11,7 @@
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName> <AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
<PackageId>SixLabors.ImageSharp.Drawing</PackageId> <PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags> <PackageTags>Image Draw Shape Path Font</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl> <PackageIconUrl>https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl> <PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl> <PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
@ -36,9 +36,9 @@
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" /> <ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-ci0005" /> <PackageReference Include="SixLabors.Core" Version="1.0.0-beta0005" />
<PackageReference Include="SixLabors.Shapes.Text" Version="1.0.0-ci0005" /> <PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0004" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-ci0005" /> <PackageReference Include="SixLabors.Shapes.Text" Version="1.0.0-beta0004" />
<AdditionalFiles Include="..\..\stylecop.json" /> <AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004"> <PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<PrivateAssets>All</PrivateAssets> <PrivateAssets>All</PrivateAssets>

10
src/ImageSharp.Drawing/Processing/Drawing/DrawImageExtensions.cs

@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="image">The image to blend with the currently processing image.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity));
@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="blender">The blending mode.</param> /// <param name="blender">The blending mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float opacity) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity, blender)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity, blender));
@ -45,11 +45,9 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <param name="options">The options, including the blending type and blending amount.</param> /// <param name="options">The options, including the blending type and blending amount.</param>
/// <param name="image">The image to blend with the currently processing image.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Image<TPixel> image) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Image<TPixel> image)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, options));
return source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, options));
}
/// <summary> /// <summary>
/// Draws the given image together with the current one by blending their pixels. /// Draws the given image together with the current one by blending their pixels.

2
src/ImageSharp.Drawing/Processing/Drawing/DrawRectangleExtensions.cs

@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, RectangleF shape) public static IImageProcessingContext<TPixel> Draw<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IPen<TPixel> pen, RectangleF shape)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Draw(options, pen, new RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height)); => source.Draw(options, pen, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary> /// <summary>
/// Draws the outline of the rectangle with the provided pen. /// Draws the outline of the rectangle with the provided pen.

4
src/ImageSharp.Drawing/Processing/Drawing/FillRectangleExtensions.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, RectangleF shape) public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, IBrush<TPixel> brush, RectangleF shape)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Fill(options, brush, new RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height)); => source.Fill(options, brush, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary> /// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush. /// Flood fills the image in the shape of the provided rectangle with the specified brush.
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, RectangleF shape) public static IImageProcessingContext<TPixel> Fill<TPixel>(this IImageProcessingContext<TPixel> source, IBrush<TPixel> brush, RectangleF shape)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.Fill(brush, new RectangularePolygon(shape.X, shape.Y, shape.Width, shape.Height)); => source.Fill(brush, new RectangularPolygon(shape.X, shape.Y, shape.Width, shape.Height));
/// <summary> /// <summary>
/// Flood fills the image in the shape of the provided rectangle with the specified brush. /// Flood fills the image in the shape of the provided rectangle with the specified brush.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/> /// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/> /// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks> /// </remarks>
public class GammaCompanding : ICompanding internal class GammaCompanding : ICompanding
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GammaCompanding"/> class. /// Initializes a new instance of the <see cref="GammaCompanding"/> class.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/> /// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/> /// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks> /// </remarks>
public class LCompanding : ICompanding internal class LCompanding : ICompanding
{ {
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy /// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy
/// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf /// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf
/// </remarks> /// </remarks>
public static class LmsAdaptationMatrix internal static class LmsAdaptationMatrix
{ {
/// <summary> /// <summary>
/// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65) /// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65)

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/> /// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// For 10-bits, companding is identical to <see cref="Rec709Companding"/> /// For 10-bits, companding is identical to <see cref="Rec709Companding"/>
/// </remarks> /// </remarks>
public class Rec2020Companding : ICompanding internal class Rec2020Companding : ICompanding
{ {
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <remarks> /// <remarks>
/// http://en.wikipedia.org/wiki/Rec._709 /// http://en.wikipedia.org/wiki/Rec._709
/// </remarks> /// </remarks>
public class Rec709Companding : ICompanding internal class Rec709Companding : ICompanding
{ {
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/> /// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/> /// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks> /// </remarks>
public class SRgbCompanding : ICompanding internal class SRgbCompanding : ICompanding
{ {
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

33
src/ImageSharp/Common/Extensions/ByteExtensions.cs

@ -12,39 +12,6 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
internal static class ByteExtensions internal static class ByteExtensions
{ {
/// <summary>
/// Optimized <see cref="T:byte[]"/> reversal algorithm.
/// </summary>
/// <param name="source">The byte array.</param>
public static void ReverseBytes(this byte[] source)
{
ReverseBytes(source, 0, source.Length);
}
/// <summary>
/// Optimized <see cref="T:byte[]"/> reversal algorithm.
/// </summary>
/// <param name="source">The byte array.</param>
/// <param name="index">The index.</param>
/// <param name="length">The length.</param>
/// <exception cref="System.ArgumentNullException"><paramref name="source"/> is null.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ReverseBytes(this byte[] source, int index, int length)
{
Guard.NotNull(source, nameof(source));
int i = index;
int j = index + length - 1;
while (i < j)
{
byte temp = source[i];
source[i] = source[j];
source[j] = temp;
i++;
j--;
}
}
/// <summary> /// <summary>
/// Returns a reference to the given position of the array unsafe casted to <see cref="ImageSharp.PixelFormats.Rgb24"/>. /// Returns a reference to the given position of the array unsafe casted to <see cref="ImageSharp.PixelFormats.Rgb24"/>.
/// </summary> /// </summary>

28
src/ImageSharp/Common/Helpers/Guard.cs

@ -230,18 +230,36 @@ namespace SixLabors.ImageSharp
} }
/// <summary> /// <summary>
/// Verifies, that the `target` span has the length of 'minSpan', or longer. /// Verifies, that the `source` span has the length of 'minSpan', or longer.
/// </summary> /// </summary>
/// <typeparam name="T">The element type of the spans</typeparam> /// <typeparam name="T">The element type of the spans</typeparam>
/// <param name="target">The target span.</param> /// <param name="source">The source span.</param>
/// <param name="minLength">The minimum length.</param> /// <param name="minLength">The minimum length.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param> /// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException"> /// <exception cref="ArgumentException">
/// <paramref name="target"/> is true /// <paramref name="source"/> is true
/// </exception>
public static void MustBeSizedAtLeast<T>(ReadOnlySpan<T> source, int minLength, string parameterName)
{
if (source.Length < minLength)
{
throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
}
}
/// <summary>
/// Verifies, that the `source` span has the length of 'minSpan', or longer.
/// </summary>
/// <typeparam name="T">The element type of the spans</typeparam>
/// <param name="source">The target span.</param>
/// <param name="minLength">The minimum length.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="source"/> is true
/// </exception> /// </exception>
public static void MustBeSizedAtLeast<T>(Span<T> target, int minLength, string parameterName) public static void MustBeSizedAtLeast<T>(Span<T> source, int minLength, string parameterName)
{ {
if (target.Length < minLength) if (source.Length < minLength)
{ {
throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName);
} }

10
src/ImageSharp/Formats/Gif/GifConstants.cs

@ -21,6 +21,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
public const string FileVersion = "89a"; public const string FileVersion = "89a";
/// <summary>
/// The ASCII encoded bytes used to identify the GIF file.
/// </summary>
internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion);
/// <summary> /// <summary>
/// The extension block introducer <value>!</value>. /// The extension block introducer <value>!</value>.
/// </summary> /// </summary>
@ -41,6 +46,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
public const string ApplicationIdentification = "NETSCAPE2.0"; public const string ApplicationIdentification = "NETSCAPE2.0";
/// <summary>
/// The ASCII encoded application identification bytes.
/// </summary>
internal static readonly byte[] ApplicationIdentificationBytes = Encoding.UTF8.GetBytes(ApplicationIdentification);
/// <summary> /// <summary>
/// The application block size. /// The application block size.
/// </summary> /// </summary>

4
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="writer">The writer to write to the stream with.</param> /// <param name="writer">The writer to write to the stream with.</param>
private void WriteHeader(EndianBinaryWriter writer) private void WriteHeader(EndianBinaryWriter writer)
{ {
writer.Write((GifConstants.FileType + GifConstants.FileVersion).ToCharArray()); writer.Write(GifConstants.MagicNumber);
} }
/// <summary> /// <summary>
@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
writer.Write(this.buffer, 0, 3); writer.Write(this.buffer, 0, 3);
writer.Write(GifConstants.ApplicationIdentification.ToCharArray()); // NETSCAPE2.0 writer.Write(GifConstants.ApplicationIdentificationBytes); // NETSCAPE2.0
writer.Write((byte)3); // Application block length writer.Write((byte)3); // Application block length
writer.Write((byte)1); // Data sub-block index (always 1) writer.Write((byte)1); // Data sub-block index (always 1)

82
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -348,13 +349,12 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Converts a byte array to a new array where each value in the original array is represented by the specified number of bits. /// Converts a byte array to a new array where each value in the original array is represented by the specified number of bits.
/// </summary> /// </summary>
/// <param name="source">The bytes to convert from. Cannot be null.</param> /// <param name="source">The bytes to convert from. Cannot be empty.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param> /// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bits">The number of bits per value.</param> /// <param name="bits">The number of bits per value.</param>
/// <returns>The resulting <see cref="Span{Byte}"/> array. Is never null.</returns> /// <returns>The resulting <see cref="ReadOnlySpan{Byte}"/> array.</returns>
/// <exception cref="System.ArgumentNullException"><paramref name="source"/> is null.</exception>
/// <exception cref="System.ArgumentException"><paramref name="bits"/> is less than or equals than zero.</exception> /// <exception cref="System.ArgumentException"><paramref name="bits"/> is less than or equals than zero.</exception>
private static Span<byte> ToArrayByBitsLength(Span<byte> source, int bytesPerScanline, int bits) private static ReadOnlySpan<byte> ToArrayByBitsLength(ReadOnlySpan<byte> source, int bytesPerScanline, int bits)
{ {
Guard.MustBeGreaterThan(source.Length, 0, nameof(source)); Guard.MustBeGreaterThan(source.Length, 0, nameof(source));
Guard.MustBeGreaterThan(bits, 0, nameof(bits)); Guard.MustBeGreaterThan(bits, 0, nameof(bits));
@ -414,14 +414,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
/// <param name="metadata">The metadata to read to.</param> /// <param name="metadata">The metadata to read to.</param>
/// <param name="data">The data containing physical data.</param> /// <param name="data">The data containing physical data.</param>
private void ReadPhysicalChunk(ImageMetaData metadata, byte[] data) private void ReadPhysicalChunk(ImageMetaData metadata, ReadOnlySpan<byte> data)
{ {
data.ReverseBytes(0, 4);
data.ReverseBytes(4, 4);
// 39.3700787 = inches in a meter. // 39.3700787 = inches in a meter.
metadata.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d; metadata.HorizontalResolution = BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)) / 39.3700787d;
metadata.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d; metadata.VerticalResolution = BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)) / 39.3700787d;
} }
/// <summary> /// <summary>
@ -671,7 +668,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
Span<TPixel> rowSpan = image.GetPixelRowSpan(this.currentRow); Span<TPixel> rowSpan = image.GetPixelRowSpan(this.currentRow);
this.ProcessInterlacedDefilteredScanline(this.scanline.Array, rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]); this.ProcessInterlacedDefilteredScanline(this.scanline.Span, rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
this.SwapBuffers(); this.SwapBuffers();
@ -699,20 +696,20 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="defilteredScanline">The de-filtered scanline</param> /// <param name="defilteredScanline">The de-filtered scanline</param>
/// <param name="pixels">The image</param> /// <param name="pixels">The image</param>
private void ProcessDefilteredScanline<TPixel>(byte[] defilteredScanline, ImageFrame<TPixel> pixels) private void ProcessDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, ImageFrame<TPixel> pixels)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var color = default(TPixel); var color = default(TPixel);
Span<TPixel> rowSpan = pixels.GetPixelRowSpan(this.currentRow); Span<TPixel> rowSpan = pixels.GetPixelRowSpan(this.currentRow);
// Trim the first marker byte from the buffer // Trim the first marker byte from the buffer
var scanlineBuffer = new Span<byte>(defilteredScanline, 1, defilteredScanline.Length - 1); ReadOnlySpan<byte> scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
switch (this.pngColorType) switch (this.pngColorType)
{ {
case PngColorType.Grayscale: case PngColorType.Grayscale:
int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1);
Span<byte> newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); ReadOnlySpan<byte> newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
@ -796,10 +793,10 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
Span<Rgb24> rgb24Span = scanlineBuffer.NonPortableCast<byte, Rgb24>(); ReadOnlySpan<Rgb24> rgb24Span = scanlineBuffer.NonPortableCast<byte, Rgb24>();
for (int x = 0; x < this.header.Width; x++) for (int x = 0; x < this.header.Width; x++)
{ {
ref Rgb24 rgb24 = ref rgb24Span[x]; ref readonly Rgb24 rgb24 = ref rgb24Span[x];
var rgba32 = default(Rgba32); var rgba32 = default(Rgba32);
rgba32.Rgb = rgb24; rgba32.Rgb = rgb24;
rgba32.A = (byte)(rgb24.Equals(this.rgb24Trans) ? 0 : 255); rgba32.A = (byte)(rgb24.Equals(this.rgb24Trans) ? 0 : 255);
@ -840,7 +837,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="target">The target buffer</param> /// <param name="target">The target buffer</param>
/// <param name="length">The target length</param> /// <param name="length">The target length</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void From16BitTo8Bit(Span<byte> source, Span<byte> target, int length) private void From16BitTo8Bit(ReadOnlySpan<byte> source, Span<byte> target, int length)
{ {
for (int i = 0, j = 0; i < length; i++, j += 2) for (int i = 0, j = 0; i < length; i++, j += 2)
{ {
@ -881,10 +878,10 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <typeparam name="TPixel">The type of pixel we are expanding to</typeparam> /// <typeparam name="TPixel">The type of pixel we are expanding to</typeparam>
/// <param name="defilteredScanline">The scanline</param> /// <param name="defilteredScanline">The scanline</param>
/// <param name="row">Thecurrent output image row</param> /// <param name="row">Thecurrent output image row</param>
private void ProcessScanlineFromPalette<TPixel>(Span<byte> defilteredScanline, Span<TPixel> row) private void ProcessScanlineFromPalette<TPixel>(ReadOnlySpan<byte> defilteredScanline, Span<TPixel> row)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Span<byte> newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); ReadOnlySpan<byte> newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
byte[] pal = this.palette; byte[] pal = this.palette;
var color = default(TPixel); var color = default(TPixel);
@ -931,19 +928,19 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="rowSpan">The current image row.</param> /// <param name="rowSpan">The current image row.</param>
/// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param> /// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param>
/// <param name="increment">The column increment. Always 1 for none interlaced images.</param> /// <param name="increment">The column increment. Always 1 for none interlaced images.</param>
private void ProcessInterlacedDefilteredScanline<TPixel>(byte[] defilteredScanline, Span<TPixel> rowSpan, int pixelOffset = 0, int increment = 1) private void ProcessInterlacedDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, Span<TPixel> rowSpan, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var color = default(TPixel); var color = default(TPixel);
// Trim the first marker byte from the buffer // Trim the first marker byte from the buffer
var scanlineBuffer = new Span<byte>(defilteredScanline, 1, defilteredScanline.Length - 1); ReadOnlySpan<byte> scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
switch (this.pngColorType) switch (this.pngColorType)
{ {
case PngColorType.Grayscale: case PngColorType.Grayscale:
int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1);
Span<byte> newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); ReadOnlySpan<byte> newScanline1 = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++)
{ {
@ -976,7 +973,7 @@ namespace SixLabors.ImageSharp.Formats.Png
case PngColorType.Palette: case PngColorType.Palette:
Span<byte> newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); ReadOnlySpan<byte> newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
var rgba = default(Rgba32); var rgba = default(Rgba32);
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
@ -1159,22 +1156,19 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// Reads a header chunk from the data. /// Reads a header chunk from the data.
/// </summary> /// </summary>
/// <param name="data">The <see cref="T:byte[]"/> containing data.</param> /// <param name="data">The <see cref="T:ReadOnlySpan{byte}"/> containing data.</param>
private void ReadHeaderChunk(byte[] data) private void ReadHeaderChunk(ReadOnlySpan<byte> data)
{ {
this.header = new PngHeader(); this.header = new PngHeader
{
data.ReverseBytes(0, 4); Width = BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)),
data.ReverseBytes(4, 4); Height = BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)),
BitDepth = data[8],
this.header.Width = BitConverter.ToInt32(data, 0); ColorType = (PngColorType)data[9],
this.header.Height = BitConverter.ToInt32(data, 4); CompressionMethod = data[10],
FilterMethod = data[11],
this.header.BitDepth = data[8]; InterlaceMethod = (PngInterlaceMode)data[12]
this.header.ColorType = (PngColorType)data[9]; };
this.header.CompressionMethod = data[10];
this.header.FilterMethod = data[11];
this.header.InterlaceMethod = (PngInterlaceMode)data[12];
} }
/// <summary> /// <summary>
@ -1256,18 +1250,17 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ReadChunkCrc(PngChunk chunk) private void ReadChunkCrc(PngChunk chunk)
{ {
int numBytes = this.currentStream.Read(this.crcBuffer, 0, 4); int numBytes = this.currentStream.Read(this.crcBuffer, 0, 4);
if (numBytes >= 1 && numBytes <= 3) if (numBytes >= 1 && numBytes <= 3)
{ {
throw new ImageFormatException("Image stream is not valid!"); throw new ImageFormatException("Image stream is not valid!");
} }
this.crcBuffer.ReverseBytes(); chunk.Crc = BinaryPrimitives.ReadUInt32BigEndian(this.crcBuffer);
chunk.Crc = BitConverter.ToUInt32(this.crcBuffer, 0);
this.crc.Reset(); this.crc.Reset();
this.crc.Update(this.chunkTypeBuffer); this.crc.Update(this.chunkTypeBuffer);
this.crc.Update(chunk.Data.Array, 0, chunk.Length); this.crc.Update(new ReadOnlySpan<byte>(chunk.Data.Array, 0, chunk.Length));
if (this.crc.Value != chunk.Crc && IsCriticalChunk(chunk)) if (this.crc.Value != chunk.Crc && IsCriticalChunk(chunk))
{ {
@ -1328,15 +1321,14 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ReadChunkLength(PngChunk chunk) private void ReadChunkLength(PngChunk chunk)
{ {
int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4); int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4);
if (numBytes < 4) if (numBytes < 4)
{ {
chunk.Length = -1; chunk.Length = -1;
return; return;
} }
this.chunkLengthBuffer.ReverseBytes(); chunk.Length = BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer);
chunk.Length = BitConverter.ToInt32(this.chunkLengthBuffer, 0);
} }
/// <summary> /// <summary>

100
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -2,8 +2,10 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Filters;
using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Formats.Png.Zlib;
@ -35,6 +37,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
private readonly byte[] chunkDataBuffer = new byte[16]; private readonly byte[] chunkDataBuffer = new byte[16];
/// <summary>
/// Reusable buffer for writing int data.
/// </summary>
private readonly byte[] intBuffer = new byte[4];
/// <summary> /// <summary>
/// Reusable crc for validating chunks. /// Reusable crc for validating chunks.
/// </summary> /// </summary>
@ -243,52 +250,12 @@ namespace SixLabors.ImageSharp.Formats.Png
this.paeth?.Dispose(); this.paeth?.Dispose();
} }
/// <summary>
/// Writes an integer to the byte array.
/// </summary>
/// <param name="data">The <see cref="T:byte[]"/> containing image data.</param>
/// <param name="offset">The amount to offset by.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(byte[] data, int offset, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
buffer.ReverseBytes();
Buffer.BlockCopy(buffer, 0, data, offset, 4);
}
/// <summary>
/// Writes an integer to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(Stream stream, int value)
{
byte[] buffer = BitConverter.GetBytes(value);
buffer.ReverseBytes();
stream.Write(buffer, 0, 4);
}
/// <summary>
/// Writes an unsigned integer to the stream.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="value">The value to write.</param>
private static void WriteInteger(Stream stream, uint value)
{
byte[] buffer = BitConverter.GetBytes(value);
buffer.ReverseBytes();
stream.Write(buffer, 0, 4);
}
/// <summary> /// <summary>
/// Collects a row of grayscale pixels. /// Collects a row of grayscale pixels.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="rowSpan">The image row span.</param> /// <param name="rowSpan">The image row span.</param>
private void CollectGrayscaleBytes<TPixel>(Span<TPixel> rowSpan) private void CollectGrayscaleBytes<TPixel>(ReadOnlySpan<TPixel> rowSpan)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
byte[] rawScanlineArray = this.rawScanline.Array; byte[] rawScanlineArray = this.rawScanline.Array;
@ -323,7 +290,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="rowSpan">The row span.</param> /// <param name="rowSpan">The row span.</param>
private void CollecTPixelBytes<TPixel>(Span<TPixel> rowSpan) private void CollecTPixelBytes<TPixel>(ReadOnlySpan<TPixel> rowSpan)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.bytesPerPixel == 4) if (this.bytesPerPixel == 4)
@ -344,7 +311,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="rowSpan">The row span.</param> /// <param name="rowSpan">The row span.</param>
/// <param name="row">The row.</param> /// <param name="row">The row.</param>
/// <returns>The <see cref="T:byte[]"/></returns> /// <returns>The <see cref="T:byte[]"/></returns>
private IManagedByteBuffer EncodePixelRow<TPixel>(Span<TPixel> rowSpan, int row) private IManagedByteBuffer EncodePixelRow<TPixel>(ReadOnlySpan<TPixel> rowSpan, int row)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
switch (this.pngColorType) switch (this.pngColorType)
@ -450,8 +417,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="header">The <see cref="PngHeader"/>.</param> /// <param name="header">The <see cref="PngHeader"/>.</param>
private void WriteHeaderChunk(Stream stream, PngHeader header) private void WriteHeaderChunk(Stream stream, PngHeader header)
{ {
WriteInteger(this.chunkDataBuffer, 0, header.Width); BinaryPrimitives.WriteInt32BigEndian(new Span<byte>(this.chunkDataBuffer, 0, 4), header.Width);
WriteInteger(this.chunkDataBuffer, 4, header.Height); BinaryPrimitives.WriteInt32BigEndian(new Span<byte>(this.chunkDataBuffer, 4, 4), header.Height);
this.chunkDataBuffer[8] = header.BitDepth; this.chunkDataBuffer[8] = header.BitDepth;
this.chunkDataBuffer[9] = (byte)header.ColorType; this.chunkDataBuffer[9] = (byte)header.ColorType;
@ -535,8 +502,8 @@ namespace SixLabors.ImageSharp.Formats.Png
int dpmX = (int)Math.Round(image.MetaData.HorizontalResolution * 39.3700787D); int dpmX = (int)Math.Round(image.MetaData.HorizontalResolution * 39.3700787D);
int dpmY = (int)Math.Round(image.MetaData.VerticalResolution * 39.3700787D); int dpmY = (int)Math.Round(image.MetaData.VerticalResolution * 39.3700787D);
WriteInteger(this.chunkDataBuffer, 0, dpmX); BinaryPrimitives.WriteInt32BigEndian(new Span<byte>(this.chunkDataBuffer, 0, 4), dpmX);
WriteInteger(this.chunkDataBuffer, 4, dpmY); BinaryPrimitives.WriteInt32BigEndian(new Span<byte>(this.chunkDataBuffer, 4, 4), dpmY);
this.chunkDataBuffer[8] = 1; this.chunkDataBuffer[8] = 1;
@ -552,14 +519,10 @@ namespace SixLabors.ImageSharp.Formats.Png
{ {
if (this.writeGamma) if (this.writeGamma)
{ {
int gammaValue = (int)(this.gamma * 100000F); // 4-byte unsigned integer of gamma * 100,000.
uint gammaValue = (uint)(this.gamma * 100_000F);
byte[] size = BitConverter.GetBytes(gammaValue); BinaryPrimitives.WriteUInt32BigEndian(new Span<byte>(this.chunkDataBuffer, 0, 4), gammaValue);
this.chunkDataBuffer[0] = size[3];
this.chunkDataBuffer[1] = size[2];
this.chunkDataBuffer[2] = size[1];
this.chunkDataBuffer[3] = size[0];
this.WriteChunk(stream, PngChunkTypes.Gamma, this.chunkDataBuffer, 0, 4); this.WriteChunk(stream, PngChunkTypes.Gamma, this.chunkDataBuffer, 0, 4);
} }
@ -591,15 +554,14 @@ namespace SixLabors.ImageSharp.Formats.Png
byte[] buffer; byte[] buffer;
int bufferLength; int bufferLength;
MemoryStream memoryStream = null;
try using (var memoryStream = new MemoryStream())
{ {
memoryStream = new MemoryStream();
using (var deflateStream = new ZlibDeflateStream(memoryStream, this.compressionLevel)) using (var deflateStream = new ZlibDeflateStream(memoryStream, this.compressionLevel))
{ {
for (int y = 0; y < this.height; y++) for (int y = 0; y < this.height; y++)
{ {
IManagedByteBuffer r = this.EncodePixelRow(pixels.GetPixelRowSpan(y), y); IManagedByteBuffer r = this.EncodePixelRow(pixels.GetPixelRowSpan(y).AsReadOnlySpan(), y);
deflateStream.Write(r.Array, 0, resultLength); deflateStream.Write(r.Array, 0, resultLength);
IManagedByteBuffer temp = this.rawScanline; IManagedByteBuffer temp = this.rawScanline;
@ -611,10 +573,6 @@ namespace SixLabors.ImageSharp.Formats.Png
buffer = memoryStream.ToArray(); buffer = memoryStream.ToArray();
bufferLength = buffer.Length; bufferLength = buffer.Length;
} }
finally
{
memoryStream?.Dispose();
}
// Store the chunks in repeated 64k blocks. // Store the chunks in repeated 64k blocks.
// This reduces the memory load for decoding the image for many decoders. // This reduces the memory load for decoding the image for many decoders.
@ -668,7 +626,9 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="length">The of the data to write.</param> /// <param name="length">The of the data to write.</param>
private void WriteChunk(Stream stream, string type, byte[] data, int offset, int length) private void WriteChunk(Stream stream, string type, byte[] data, int offset, int length)
{ {
WriteInteger(stream, length); BinaryPrimitives.WriteInt32BigEndian(this.intBuffer, length);
stream.Write(this.intBuffer, 0, 4); // write the length
this.chunkTypeBuffer[0] = (byte)type[0]; this.chunkTypeBuffer[0] = (byte)type[0];
this.chunkTypeBuffer[1] = (byte)type[1]; this.chunkTypeBuffer[1] = (byte)type[1];
@ -677,20 +637,20 @@ namespace SixLabors.ImageSharp.Formats.Png
stream.Write(this.chunkTypeBuffer, 0, 4); stream.Write(this.chunkTypeBuffer, 0, 4);
if (data != null)
{
stream.Write(data, offset, length);
}
this.crc.Reset(); this.crc.Reset();
this.crc.Update(this.chunkTypeBuffer); this.crc.Update(this.chunkTypeBuffer);
if (data != null && length > 0) if (data != null && length > 0)
{ {
this.crc.Update(data, offset, length); stream.Write(data, offset, length);
this.crc.Update(new ReadOnlySpan<byte>(data, offset, length));
} }
WriteInteger(stream, (uint)this.crc.Value); BinaryPrimitives.WriteUInt32BigEndian(this.intBuffer, (uint)this.crc.Value);
stream.Write(this.intBuffer, 0, 4); // write the crc
} }
} }
} }

25
src/ImageSharp/Formats/Png/Zlib/Adler32.cs

@ -113,30 +113,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer) public void Update(ReadOnlySpan<byte> data)
{ {
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
this.Update(buffer, 0, buffer.Length);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer, int offset, int count)
{
DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset));
DebugGuard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
DebugGuard.MustBeLessThan(offset, buffer.Length, nameof(offset));
DebugGuard.MustBeLessThanOrEqualTo(offset + count, buffer.Length, nameof(count));
// (By Per Bothner) // (By Per Bothner)
uint s1 = this.checksum & 0xFFFF; uint s1 = this.checksum & 0xFFFF;
uint s2 = this.checksum >> 16; uint s2 = this.checksum >> 16;
int count = data.Length;
int offset = 0;
while (count > 0) while (count > 0)
{ {
// We can defer the modulo operation: // We can defer the modulo operation:
@ -151,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
count -= n; count -= n;
while (--n >= 0) while (--n >= 0)
{ {
s1 = s1 + (uint)(buffer[offset++] & 0xff); s1 = s1 + (uint)(data[offset++] & 0xff);
s2 = s2 + s1; s2 = s2 + s1;
} }

23
src/ImageSharp/Formats/Png/Zlib/Crc32.cs

@ -137,30 +137,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer) public void Update(ReadOnlySpan<byte> data)
{ {
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
this.Update(buffer, 0, buffer.Length);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer, int offset, int count)
{
DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
DebugGuard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset));
DebugGuard.MustBeLessThanOrEqualTo(offset + count, buffer.Length, nameof(count));
this.crc ^= CrcSeed; this.crc ^= CrcSeed;
while (--count >= 0) for (int i = 0; i < data.Length; i++)
{ {
this.crc = CrcTable[(this.crc ^ buffer[offset++]) & 0xFF] ^ (this.crc >> 8); this.crc = CrcTable[(this.crc ^ data[i]) & 0xFF] ^ (this.crc >> 8);
} }
this.crc ^= CrcSeed; this.crc ^= CrcSeed;

22
src/ImageSharp/Formats/Png/Zlib/IChecksum.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Formats.Png.Zlib namespace SixLabors.ImageSharp.Formats.Png.Zlib
{ {
/// <summary> /// <summary>
@ -34,25 +36,11 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
void Update(int value); void Update(int value);
/// <summary> /// <summary>
/// Updates the data checksum with the bytes taken from the array. /// Updates the data checksum with the bytes taken from the span.
/// </summary> /// </summary>
/// <param name="buffer"> /// <param name="data">
/// buffer an array of bytes /// buffer an array of bytes
/// </param> /// </param>
void Update(byte[] buffer); void Update(ReadOnlySpan<byte> data);
/// <summary>
/// Adds the byte array to the data checksum.
/// </summary>
/// <param name = "buffer">
/// The buffer which contains the data
/// </param>
/// <param name = "offset">
/// The offset in the buffer where the data starts
/// </param>
/// <param name = "count">
/// the number of data bytes to add.
/// </param>
void Update(byte[] buffer, int offset, int count);
} }
} }

2
src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs

@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public override void Write(byte[] buffer, int offset, int count) public override void Write(byte[] buffer, int offset, int count)
{ {
this.deflateStream.Write(buffer, offset, count); this.deflateStream.Write(buffer, offset, count);
this.adler32.Update(buffer, offset, count); this.adler32.Update(new ReadOnlySpan<byte>(buffer, offset, count));
} }
/// <inheritdoc/> /// <inheritdoc/>

84
src/ImageSharp/IO/BigEndianBitConverter.cs

@ -1,84 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Implementation of EndianBitConverter which converts to/from big-endian byte arrays.
/// </summary>
internal sealed class BigEndianBitConverter : EndianBitConverter
{
/// <inheritdoc/>
public override Endianness Endianness
{
get { return Endianness.BigEndian; }
}
/// <inheritdoc/>
public override bool IsLittleEndian
{
get { return false; }
}
/// <inheritdoc/>
public override void CopyBytes(short value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 2);
buffer[index] = (byte)(value >> 8);
buffer[index + 1] = (byte)value;
}
/// <inheritdoc/>
public override void CopyBytes(int value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 4);
buffer[index] = (byte)(value >> 24);
buffer[index + 1] = (byte)(value >> 16);
buffer[index + 2] = (byte)(value >> 8);
buffer[index + 3] = (byte)value;
}
/// <inheritdoc/>
public override void CopyBytes(long value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 8);
buffer[index] = (byte)(value >> 56);
buffer[index + 1] = (byte)(value >> 48);
buffer[index + 2] = (byte)(value >> 40);
buffer[index + 3] = (byte)(value >> 32);
buffer[index + 4] = (byte)(value >> 24);
buffer[index + 5] = (byte)(value >> 16);
buffer[index + 6] = (byte)(value >> 8);
buffer[index + 7] = (byte)value;
}
/// <inheritdoc/>
public override short ToInt16(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 2);
return (short)((value[startIndex] << 8) | value[startIndex + 1]);
}
/// <inheritdoc/>
public override int ToInt32(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 4);
return (value[startIndex] << 24) | (value[startIndex + 1] << 16) | (value[startIndex + 2] << 8) | value[startIndex + 3];
}
/// <inheritdoc/>
public override long ToInt64(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 8);
long p1 = (value[startIndex] << 24) | (value[startIndex + 1] << 16) | (value[startIndex + 2] << 8) | value[startIndex + 3];
long p2 = (value[startIndex + 4] << 24) | (value[startIndex + 5] << 16) | (value[startIndex + 6] << 8) | value[startIndex + 7];
return (p2 & 0xFFFFFFFF) | (p1 << 32);
}
}
}

277
src/ImageSharp/IO/EndianBinaryReader.cs

@ -2,57 +2,32 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace SixLabors.ImageSharp.IO namespace SixLabors.ImageSharp.IO
{ {
/// <summary> /// <summary>
/// Equivalent of <see cref="BinaryReader"/>, but with either endianness, depending on the <see cref="EndianBitConverter"/> it is constructed with. /// Equivalent of <see cref="BinaryReader"/>, but with either endianness.
/// No data is buffered in the reader; the client may seek within the stream at will. /// No data is buffered in the reader; the client may seek within the stream at will.
/// </summary> /// </summary>
internal class EndianBinaryReader : IDisposable internal class EndianBinaryReader : IDisposable
{ {
/// <summary>
/// Decoder to use for string conversions.
/// </summary>
private readonly Decoder decoder;
/// <summary> /// <summary>
/// Buffer used for temporary storage before conversion into primitives /// Buffer used for temporary storage before conversion into primitives
/// </summary> /// </summary>
private readonly byte[] storageBuffer = new byte[16]; private readonly byte[] storageBuffer = new byte[16];
/// <summary>
/// Buffer used for temporary storage when reading a single character
/// </summary>
private readonly char[] charBuffer = new char[1];
/// <summary>
/// Minimum number of bytes used to encode a character
/// </summary>
private readonly int minBytesPerChar;
/// <summary> /// <summary>
/// Whether or not this reader has been disposed yet. /// Whether or not this reader has been disposed yet.
/// </summary> /// </summary>
private bool disposed; private bool disposed;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="EndianBinaryReader"/> class. /// The endianness used to read data
/// Equivalent of <see cref="System.IO.BinaryWriter"/>, but with either endianness, depending on
/// the EndianBitConverter it is constructed with.
/// </summary> /// </summary>
/// <param name="endianness"> private readonly Endianness endianness;
/// Endianness to use when reading data
/// </param>
/// <param name="stream">
/// Stream to read data from
/// </param>
public EndianBinaryReader(Endianness endianness, Stream stream)
: this(endianness, stream, Encoding.UTF8)
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="EndianBinaryReader"/> class. /// Initializes a new instance of the <see cref="EndianBinaryReader"/> class.
@ -61,40 +36,20 @@ namespace SixLabors.ImageSharp.IO
/// </summary> /// </summary>
/// <param name="endianness">Endianness to use when reading data</param> /// <param name="endianness">Endianness to use when reading data</param>
/// <param name="stream">Stream to read data from</param> /// <param name="stream">Stream to read data from</param>
/// <param name="encoding">Encoding to use when reading character data</param> public EndianBinaryReader(Endianness endianness, Stream stream)
public EndianBinaryReader(Endianness endianness, Stream stream, Encoding encoding)
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
Guard.NotNull(encoding, nameof(encoding));
Guard.IsTrue(stream.CanRead, nameof(stream), "Stream isn't readable"); Guard.IsTrue(stream.CanRead, nameof(stream), "Stream isn't readable");
this.BaseStream = stream; this.BaseStream = stream;
this.BitConverter = EndianBitConverter.GetConverter(endianness); this.endianness = endianness;
this.Encoding = encoding;
this.decoder = encoding.GetDecoder();
this.minBytesPerChar = 1;
if (encoding is UnicodeEncoding)
{
this.minBytesPerChar = 2;
}
} }
/// <summary>
/// Gets the encoding used to read strings
/// </summary>
public Encoding Encoding { get; }
/// <summary> /// <summary>
/// Gets the underlying stream of the EndianBinaryReader. /// Gets the underlying stream of the EndianBinaryReader.
/// </summary> /// </summary>
public Stream BaseStream { get; } public Stream BaseStream { get; }
/// <summary>
/// Gets the bit converter used to read values from the stream.
/// </summary>
internal EndianBitConverter BitConverter { get; }
/// <summary> /// <summary>
/// Closes the reader, including the underlying stream. /// Closes the reader, including the underlying stream.
/// </summary> /// </summary>
@ -141,7 +96,8 @@ namespace SixLabors.ImageSharp.IO
public bool ReadBoolean() public bool ReadBoolean()
{ {
this.ReadInternal(this.storageBuffer, 1); this.ReadInternal(this.storageBuffer, 1);
return this.BitConverter.ToBoolean(this.storageBuffer, 0);
return this.storageBuffer[0] != 0;
} }
/// <summary> /// <summary>
@ -152,7 +108,10 @@ namespace SixLabors.ImageSharp.IO
public short ReadInt16() public short ReadInt16()
{ {
this.ReadInternal(this.storageBuffer, 2); this.ReadInternal(this.storageBuffer, 2);
return this.BitConverter.ToInt16(this.storageBuffer, 0);
return (this.endianness == Endianness.BigEndian)
? BinaryPrimitives.ReadInt16BigEndian(this.storageBuffer)
: BinaryPrimitives.ReadInt16LittleEndian(this.storageBuffer);
} }
/// <summary> /// <summary>
@ -163,7 +122,10 @@ namespace SixLabors.ImageSharp.IO
public int ReadInt32() public int ReadInt32()
{ {
this.ReadInternal(this.storageBuffer, 4); this.ReadInternal(this.storageBuffer, 4);
return this.BitConverter.ToInt32(this.storageBuffer, 0);
return (this.endianness == Endianness.BigEndian)
? BinaryPrimitives.ReadInt32BigEndian(this.storageBuffer)
: BinaryPrimitives.ReadInt32LittleEndian(this.storageBuffer);
} }
/// <summary> /// <summary>
@ -174,7 +136,10 @@ namespace SixLabors.ImageSharp.IO
public long ReadInt64() public long ReadInt64()
{ {
this.ReadInternal(this.storageBuffer, 8); this.ReadInternal(this.storageBuffer, 8);
return this.BitConverter.ToInt64(this.storageBuffer, 0);
return (this.endianness == Endianness.BigEndian)
? BinaryPrimitives.ReadInt64BigEndian(this.storageBuffer)
: BinaryPrimitives.ReadInt64LittleEndian(this.storageBuffer);
} }
/// <summary> /// <summary>
@ -185,7 +150,10 @@ namespace SixLabors.ImageSharp.IO
public ushort ReadUInt16() public ushort ReadUInt16()
{ {
this.ReadInternal(this.storageBuffer, 2); this.ReadInternal(this.storageBuffer, 2);
return this.BitConverter.ToUInt16(this.storageBuffer, 0);
return (this.endianness == Endianness.BigEndian)
? BinaryPrimitives.ReadUInt16BigEndian(this.storageBuffer)
: BinaryPrimitives.ReadUInt16LittleEndian(this.storageBuffer);
} }
/// <summary> /// <summary>
@ -196,7 +164,10 @@ namespace SixLabors.ImageSharp.IO
public uint ReadUInt32() public uint ReadUInt32()
{ {
this.ReadInternal(this.storageBuffer, 4); this.ReadInternal(this.storageBuffer, 4);
return this.BitConverter.ToUInt32(this.storageBuffer, 0);
return (this.endianness == Endianness.BigEndian)
? BinaryPrimitives.ReadUInt32BigEndian(this.storageBuffer)
: BinaryPrimitives.ReadUInt32LittleEndian(this.storageBuffer);
} }
/// <summary> /// <summary>
@ -207,7 +178,10 @@ namespace SixLabors.ImageSharp.IO
public ulong ReadUInt64() public ulong ReadUInt64()
{ {
this.ReadInternal(this.storageBuffer, 8); this.ReadInternal(this.storageBuffer, 8);
return this.BitConverter.ToUInt64(this.storageBuffer, 0);
return (this.endianness == Endianness.BigEndian)
? BinaryPrimitives.ReadUInt64BigEndian(this.storageBuffer)
: BinaryPrimitives.ReadUInt64LittleEndian(this.storageBuffer);
} }
/// <summary> /// <summary>
@ -215,10 +189,11 @@ namespace SixLabors.ImageSharp.IO
/// for this reader. 4 bytes are read. /// for this reader. 4 bytes are read.
/// </summary> /// </summary>
/// <returns>The floating point value read</returns> /// <returns>The floating point value read</returns>
public float ReadSingle() public unsafe float ReadSingle()
{ {
this.ReadInternal(this.storageBuffer, 4); int intValue = this.ReadInt32();
return this.BitConverter.ToSingle(this.storageBuffer, 0);
return *((float*)&intValue);
} }
/// <summary> /// <summary>
@ -226,107 +201,11 @@ namespace SixLabors.ImageSharp.IO
/// for this reader. 8 bytes are read. /// for this reader. 8 bytes are read.
/// </summary> /// </summary>
/// <returns>The floating point value read</returns> /// <returns>The floating point value read</returns>
public double ReadDouble() public unsafe double ReadDouble()
{ {
this.ReadInternal(this.storageBuffer, 8); long value = this.ReadInt64();
return this.BitConverter.ToDouble(this.storageBuffer, 0);
}
/// <summary> return *((double*)&value);
/// Reads a decimal value from the stream, using the bit converter
/// for this reader. 16 bytes are read.
/// </summary>
/// <returns>The decimal value read</returns>
public decimal ReadDecimal()
{
this.ReadInternal(this.storageBuffer, 16);
return this.BitConverter.ToDecimal(this.storageBuffer, 0);
}
/// <summary>
/// Reads a single character from the stream, using the character encoding for
/// this reader. If no characters have been fully read by the time the stream ends,
/// -1 is returned.
/// </summary>
/// <returns>The character read, or -1 for end of stream.</returns>
public int Read()
{
int charsRead = this.Read(this.charBuffer, 0, 1);
if (charsRead == 0)
{
return -1;
}
else
{
return this.charBuffer[0];
}
}
/// <summary>
/// Reads the specified number of characters into the given buffer, starting at
/// the given index.
/// </summary>
/// <param name="data">The buffer to copy data into</param>
/// <param name="index">The first index to copy data into</param>
/// <param name="count">The number of characters to read</param>
/// <returns>The number of characters actually read. This will only be less than
/// the requested number of characters if the end of the stream is reached.
/// </returns>
public int Read(char[] data, int index, int count)
{
this.CheckDisposed();
Guard.NotNull(this.storageBuffer, nameof(this.storageBuffer));
Guard.MustBeGreaterThanOrEqualTo(index, 0, nameof(index));
Guard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
Guard.IsFalse(count + index > data.Length, nameof(data.Length), "Not enough space in buffer for specified number of characters starting at specified index.");
int read = 0;
bool firstTime = true;
// Use the normal buffer if we're only reading a small amount, otherwise
// use at most 4K at a time.
byte[] byteBuffer = this.storageBuffer;
if (byteBuffer.Length < count * this.minBytesPerChar)
{
byteBuffer = new byte[4096];
}
while (read < count)
{
int amountToRead;
// First time through we know we haven't previously read any data
if (firstTime)
{
amountToRead = count * this.minBytesPerChar;
firstTime = false;
}
else
{
// After that we can only assume we need to fully read 'chars left -1' characters
// and a single byte of the character we may be in the middle of
amountToRead = ((count - read - 1) * this.minBytesPerChar) + 1;
}
if (amountToRead > byteBuffer.Length)
{
amountToRead = byteBuffer.Length;
}
int bytesRead = this.TryReadInternal(byteBuffer, amountToRead);
if (bytesRead == 0)
{
return read;
}
int decoded = this.decoder.GetChars(byteBuffer, 0, bytesRead, data, index);
read += decoded;
index += decoded;
}
return read;
} }
/// <summary> /// <summary>
@ -411,84 +290,6 @@ namespace SixLabors.ImageSharp.IO
return ret; return ret;
} }
/// <summary>
/// Reads a 7-bit encoded integer from the stream. This is stored with the least significant
/// information first, with 7 bits of information per byte of value, and the top
/// bit as a continuation flag. This method is not affected by the endianness
/// of the bit converter.
/// </summary>
/// <returns>The 7-bit encoded integer read from the stream.</returns>
public int Read7BitEncodedInt()
{
this.CheckDisposed();
int ret = 0;
for (int shift = 0; shift < 35; shift += 7)
{
int b = this.BaseStream.ReadByte();
if (b == -1)
{
throw new EndOfStreamException();
}
ret = ret | ((b & 0x7f) << shift);
if ((b & 0x80) == 0)
{
return ret;
}
}
// Still haven't seen a byte with the high bit unset? Dodgy data.
throw new IOException("Invalid 7-bit encoded integer in stream.");
}
/// <summary>
/// Reads a 7-bit encoded integer from the stream. This is stored with the most significant
/// information first, with 7 bits of information per byte of value, and the top
/// bit as a continuation flag. This method is not affected by the endianness
/// of the bit converter.
/// </summary>
/// <returns>The 7-bit encoded integer read from the stream.</returns>
public int ReadBigEndian7BitEncodedInt()
{
this.CheckDisposed();
int ret = 0;
for (int i = 0; i < 5; i++)
{
int b = this.BaseStream.ReadByte();
if (b == -1)
{
throw new EndOfStreamException();
}
ret = (ret << 7) | (b & 0x7f);
if ((b & 0x80) == 0)
{
return ret;
}
}
// Still haven't seen a byte with the high bit unset? Dodgy data.
throw new IOException("Invalid 7-bit encoded integer in stream.");
}
/// <summary>
/// Reads a length-prefixed string from the stream, using the encoding for this reader.
/// A 7-bit encoded integer is first read, which specifies the number of bytes
/// to read from the stream. These bytes are then converted into a string with
/// the encoding for this reader.
/// </summary>
/// <returns>The string read from the stream.</returns>
public string ReadString()
{
int bytesToRead = this.Read7BitEncodedInt();
byte[] data = new byte[bytesToRead];
this.ReadInternal(data, bytesToRead);
return this.Encoding.GetString(data, 0, data.Length);
}
/// <summary> /// <summary>
/// Disposes of the underlying stream. /// Disposes of the underlying stream.
/// </summary> /// </summary>

188
src/ImageSharp/IO/EndianBinaryWriter.cs

@ -2,14 +2,13 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.IO; using System.IO;
using System.Text;
namespace SixLabors.ImageSharp.IO namespace SixLabors.ImageSharp.IO
{ {
/// <summary> /// <summary>
/// Equivalent of <see cref="BinaryWriter"/>, but with either endianness, depending on /// Equivalent of <see cref="BinaryWriter"/>, but with either endianness
/// the <see cref="EndianBitConverter"/> it is constructed with.
/// </summary> /// </summary>
internal class EndianBinaryWriter : IDisposable internal class EndianBinaryWriter : IDisposable
{ {
@ -19,61 +18,35 @@ namespace SixLabors.ImageSharp.IO
private readonly byte[] buffer = new byte[16]; private readonly byte[] buffer = new byte[16];
/// <summary> /// <summary>
/// Buffer used for Write(char) /// The endianness used to write the data
/// </summary> /// </summary>
private readonly char[] charBuffer = new char[1]; private readonly Endianness endianness;
/// <summary> /// <summary>
/// Whether or not this writer has been disposed yet. /// Whether or not this writer has been disposed yet.
/// </summary> /// </summary>
private bool disposed; private bool disposed;
/// <summary>
/// Initializes a new instance of the <see cref="EndianBinaryWriter"/> class
/// with the given bit converter, writing to the given stream, using UTF-8 encoding.
/// </summary>
/// <param name="endianness">Endianness to use when writing data</param>
/// <param name="stream">Stream to write data to</param>
public EndianBinaryWriter(Endianness endianness, Stream stream)
: this(endianness, stream, Encoding.UTF8)
{
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="EndianBinaryWriter"/> class /// Initializes a new instance of the <see cref="EndianBinaryWriter"/> class
/// with the given bit converter, writing to the given stream, using the given encoding. /// with the given bit converter, writing to the given stream, using the given encoding.
/// </summary> /// </summary>
/// <param name="endianness">Endianness to use when writing data</param> /// <param name="endianness">Endianness to use when writing data</param>
/// <param name="stream">Stream to write data to</param> /// <param name="stream">Stream to write data to</param>
/// <param name="encoding"> public EndianBinaryWriter(Endianness endianness, Stream stream)
/// Encoding to use when writing character data
/// </param>
public EndianBinaryWriter(Endianness endianness, Stream stream, Encoding encoding)
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));
Guard.NotNull(stream, nameof(encoding));
Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable"); Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable");
this.BaseStream = stream; this.BaseStream = stream;
this.BitConverter = EndianBitConverter.GetConverter(endianness); this.endianness = endianness;
this.Encoding = encoding;
} }
/// <summary>
/// Gets the encoding used to write strings
/// </summary>
public Encoding Encoding { get; }
/// <summary> /// <summary>
/// Gets the underlying stream of the EndianBinaryWriter. /// Gets the underlying stream of the EndianBinaryWriter.
/// </summary> /// </summary>
public Stream BaseStream { get; } public Stream BaseStream { get; }
/// <summary>
/// Gets the bit converter used to write values to the stream
/// </summary>
internal EndianBitConverter BitConverter { get; }
/// <summary> /// <summary>
/// Closes the writer, including the underlying stream. /// Closes the writer, including the underlying stream.
/// </summary> /// </summary>
@ -108,7 +81,8 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(bool value) public void Write(bool value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); this.buffer[0] = value ? (byte)1 : (byte)0;
this.WriteInternal(this.buffer, 1); this.WriteInternal(this.buffer, 1);
} }
@ -119,7 +93,15 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(short value) public void Write(short value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); if (this.endianness == Endianness.BigEndian)
{
BinaryPrimitives.WriteInt16BigEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteInt16LittleEndian(this.buffer, value);
}
this.WriteInternal(this.buffer, 2); this.WriteInternal(this.buffer, 2);
} }
@ -130,7 +112,15 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(int value) public void Write(int value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); if (this.endianness == Endianness.BigEndian)
{
BinaryPrimitives.WriteInt32BigEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteInt32LittleEndian(this.buffer, value);
}
this.WriteInternal(this.buffer, 4); this.WriteInternal(this.buffer, 4);
} }
@ -141,7 +131,15 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(long value) public void Write(long value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); if (this.endianness == Endianness.BigEndian)
{
BinaryPrimitives.WriteInt64BigEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteInt64LittleEndian(this.buffer, value);
}
this.WriteInternal(this.buffer, 8); this.WriteInternal(this.buffer, 8);
} }
@ -152,7 +150,15 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(ushort value) public void Write(ushort value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); if (this.endianness == Endianness.BigEndian)
{
BinaryPrimitives.WriteUInt16BigEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, value);
}
this.WriteInternal(this.buffer, 2); this.WriteInternal(this.buffer, 2);
} }
@ -163,7 +169,15 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(uint value) public void Write(uint value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); if (this.endianness == Endianness.BigEndian)
{
BinaryPrimitives.WriteUInt32BigEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value);
}
this.WriteInternal(this.buffer, 4); this.WriteInternal(this.buffer, 4);
} }
@ -174,7 +188,15 @@ namespace SixLabors.ImageSharp.IO
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(ulong value) public void Write(ulong value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); if (this.endianness == Endianness.BigEndian)
{
BinaryPrimitives.WriteUInt64BigEndian(this.buffer, value);
}
else
{
BinaryPrimitives.WriteUInt64LittleEndian(this.buffer, value);
}
this.WriteInternal(this.buffer, 8); this.WriteInternal(this.buffer, 8);
} }
@ -183,10 +205,9 @@ namespace SixLabors.ImageSharp.IO
/// for this writer. 4 bytes are written. /// for this writer. 4 bytes are written.
/// </summary> /// </summary>
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(float value) public unsafe void Write(float value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); this.Write(*((int*)&value));
this.WriteInternal(this.buffer, 4);
} }
/// <summary> /// <summary>
@ -194,21 +215,9 @@ namespace SixLabors.ImageSharp.IO
/// for this writer. 8 bytes are written. /// for this writer. 8 bytes are written.
/// </summary> /// </summary>
/// <param name="value">The value to write</param> /// <param name="value">The value to write</param>
public void Write(double value) public unsafe void Write(double value)
{
this.BitConverter.CopyBytes(value, this.buffer, 0);
this.WriteInternal(this.buffer, 8);
}
/// <summary>
/// Writes a decimal value to the stream, using the bit converter for this writer.
/// 16 bytes are written.
/// </summary>
/// <param name="value">The value to write</param>
public void Write(decimal value)
{ {
this.BitConverter.CopyBytes(value, this.buffer, 0); this.Write(*((long*)&value));
this.WriteInternal(this.buffer, 16);
} }
/// <summary> /// <summary>
@ -255,71 +264,6 @@ namespace SixLabors.ImageSharp.IO
this.BaseStream.Write(value, offset, count); this.BaseStream.Write(value, offset, count);
} }
/// <summary>
/// Writes a single character to the stream, using the encoding for this writer.
/// </summary>
/// <param name="value">The value to write</param>
public void Write(char value)
{
this.charBuffer[0] = value;
this.Write(this.charBuffer);
}
/// <summary>
/// Writes an array of characters to the stream, using the encoding for this writer.
/// </summary>
/// <param name="value">An array containing the characters to write</param>
/// <exception cref="ArgumentNullException">value is null</exception>
public void Write(char[] value)
{
Guard.NotNull(value, nameof(value));
this.CheckDisposed();
byte[] data = this.Encoding.GetBytes(value, 0, value.Length);
this.WriteInternal(data, data.Length);
}
/// <summary>
/// Writes a length-prefixed string to the stream, using the encoding for this writer.
/// </summary>
/// <param name="value">The value to write. Must not be null.</param>
/// <exception cref="ArgumentNullException">value is null</exception>
public void Write(string value)
{
Guard.NotNull(value, nameof(value));
this.CheckDisposed();
byte[] data = this.Encoding.GetBytes(value);
this.Write7BitEncodedInt(data.Length);
this.WriteInternal(data, data.Length);
}
/// <summary>
/// Writes a 7-bit encoded integer from the stream. This is stored with the least significant
/// information first, with 7 bits of information per byte of value, and the top
/// bit as a continuation flag.
/// </summary>
/// <param name="value">The 7-bit encoded integer to write to the stream</param>
public void Write7BitEncodedInt(int value)
{
this.CheckDisposed();
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "Value must be greater than or equal to 0.");
}
int index = 0;
while (value >= 128)
{
this.buffer[index++] = (byte)((value & 0x7f) | 0x80);
value = value >> 7;
index++;
}
this.buffer[index++] = (byte)value;
this.BaseStream.Write(this.buffer, 0, index);
}
/// <summary> /// <summary>
/// Disposes of the underlying stream. /// Disposes of the underlying stream.
/// </summary> /// </summary>

61
src/ImageSharp/IO/EndianBitConverter.Conversion.cs

@ -1,61 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
/// </summary>
internal abstract partial class EndianBitConverter
{
/// <summary>
/// Converts the specified double-precision floating point number to a
/// 64-bit signed integer. Note: the endianness of this converter does not
/// affect the returned value.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A 64-bit signed integer whose value is equivalent to value.</returns>
public unsafe long DoubleToInt64Bits(double value)
{
return *((long*)&value);
}
/// <summary>
/// Converts the specified 64-bit signed integer to a double-precision
/// floating point number. Note: the endianness of this converter does not
/// affect the returned value.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A double-precision floating point number whose value is equivalent to value.</returns>
public unsafe double Int64BitsToDouble(long value)
{
return *((double*)&value);
}
/// <summary>
/// Converts the specified single-precision floating point number to a
/// 32-bit signed integer. Note: the endianness of this converter does not
/// affect the returned value.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A 32-bit signed integer whose value is equivalent to value.</returns>
public unsafe int SingleToInt32Bits(float value)
{
return *((int*)&value);
}
/// <summary>
/// Converts the specified 32-bit signed integer to a single-precision floating point
/// number. Note: the endianness of this converter does not
/// affect the returned value.
/// </summary>
/// <param name="value">The number to convert. </param>
/// <returns>A single-precision floating point number whose value is equivalent to value.</returns>
public unsafe float Int32BitsToSingle(int value)
{
return *((float*)&value);
}
}
}

143
src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs

@ -1,143 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
/// </summary>
internal abstract partial class EndianBitConverter
{
/// <summary>
/// Copies the specified 16-bit signed integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public abstract void CopyBytes(short value, byte[] buffer, int index);
/// <summary>
/// Copies the specified 32-bit signed integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public abstract void CopyBytes(int value, byte[] buffer, int index);
/// <summary>
/// Copies the specified 64-bit signed integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public abstract void CopyBytes(long value, byte[] buffer, int index);
/// <summary>
/// Copies the specified 16-bit unsigned integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(ushort value, byte[] buffer, int index)
{
this.CopyBytes(unchecked((short)value), buffer, index);
}
/// <summary>
/// Copies the specified 32-bit unsigned integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(uint value, byte[] buffer, int index)
{
this.CopyBytes(unchecked((int)value), buffer, index);
}
/// <summary>
/// Copies the specified 64-bit unsigned integer value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(ulong value, byte[] buffer, int index)
{
this.CopyBytes(unchecked((long)value), buffer, index);
}
/// <summary>
/// Copies the specified Boolean value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">A Boolean value.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(bool value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 1);
buffer[index] = value ? (byte)1 : (byte)0;
}
/// <summary>
/// Copies the specified Unicode character value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">A character to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public void CopyBytes(char value, byte[] buffer, int index)
{
this.CopyBytes(unchecked((short)value), buffer, index);
}
/// <summary>
/// Copies the specified double-precision floating point value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public unsafe void CopyBytes(double value, byte[] buffer, int index)
{
this.CopyBytes(*((long*)&value), buffer, index);
}
/// <summary>
/// Copies the specified single-precision floating point value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public unsafe void CopyBytes(float value, byte[] buffer, int index)
{
this.CopyBytes(*((int*)&value), buffer, index);
}
/// <summary>
/// Copies the specified decimal value into the specified byte array,
/// beginning at the specified index.
/// </summary>
/// <param name="value">A character to convert.</param>
/// <param name="buffer">The byte array to copy the bytes into</param>
/// <param name="index">The first index into the array to copy the bytes into</param>
public unsafe void CopyBytes(decimal value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 16);
int* pvalue = (int*)&value;
this.CopyBytes(pvalue[0], buffer, index);
this.CopyBytes(pvalue[1], buffer, index + 4);
this.CopyBytes(pvalue[2], buffer, index + 8);
this.CopyBytes(pvalue[3], buffer, index + 12);
}
}
}

137
src/ImageSharp/IO/EndianBitConverter.GetBytes.cs

@ -1,137 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
/// </summary>
internal abstract partial class EndianBitConverter
{
/// <summary>
/// Returns the specified 16-bit signed integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public byte[] GetBytes(short value)
{
byte[] result = new byte[2];
this.CopyBytes(value, result, 0);
return result;
}
/// <summary>
/// Returns the specified 32-bit signed integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public byte[] GetBytes(int value)
{
byte[] result = new byte[4];
this.CopyBytes(value, result, 0);
return result;
}
/// <summary>
/// Returns the specified 64-bit signed integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public byte[] GetBytes(long value)
{
byte[] result = new byte[8];
this.CopyBytes(value, result, 0);
return result;
}
/// <summary>
/// Returns the specified 16-bit unsigned integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
public byte[] GetBytes(ushort value)
{
return this.GetBytes(unchecked((short)value));
}
/// <summary>
/// Returns the specified 32-bit unsigned integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public byte[] GetBytes(uint value)
{
return this.GetBytes(unchecked((int)value));
}
/// <summary>
/// Returns the specified 64-bit unsigned integer value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public byte[] GetBytes(ulong value)
{
return this.GetBytes(unchecked((long)value));
}
/// <summary>
/// Returns the specified Boolean value as an array of bytes.
/// </summary>
/// <param name="value">A Boolean value.</param>
/// <returns>An array of bytes with length 1.</returns>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
public byte[] GetBytes(bool value)
{
return new byte[1] { value ? (byte)1 : (byte)0 };
}
/// <summary>
/// Returns the specified Unicode character value as an array of bytes.
/// </summary>
/// <param name="value">A character to convert.</param>
/// <returns>An array of bytes with length 2.</returns>
/// <returns>
/// The <see cref="T:byte[]"/>.
/// </returns>
public byte[] GetBytes(char value)
{
return this.GetBytes((short)value);
}
/// <summary>
/// Returns the specified double-precision floating point value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 8.</returns>
public unsafe byte[] GetBytes(double value)
{
return this.GetBytes(*((long*)&value));
}
/// <summary>
/// Returns the specified single-precision floating point value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 4.</returns>
public unsafe byte[] GetBytes(float value)
{
return this.GetBytes(*((int*)&value));
}
/// <summary>
/// Returns the specified decimal value as an array of bytes.
/// </summary>
/// <param name="value">The number to convert.</param>
/// <returns>An array of bytes with length 16.</returns>
public byte[] GetBytes(decimal value)
{
byte[] result = new byte[16];
this.CopyBytes(value, result, 0);
return result;
}
}
}

139
src/ImageSharp/IO/EndianBitConverter.ToType.cs

@ -1,139 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
/// </summary>
internal abstract partial class EndianBitConverter
{
/// <summary>
/// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit signed integer formed by two bytes beginning at startIndex.</returns>
public abstract short ToInt16(byte[] value, int startIndex);
/// <summary>
/// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit signed integer formed by four bytes beginning at startIndex.</returns>
public abstract int ToInt32(byte[] value, int startIndex);
/// <summary>
/// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit signed integer formed by eight bytes beginning at startIndex.</returns>
public abstract long ToInt64(byte[] value, int startIndex);
/// <summary>
/// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 16-bit unsigned integer formed by two bytes beginning at startIndex.</returns>
public ushort ToUInt16(byte[] value, int startIndex)
{
return unchecked((ushort)this.ToInt16(value, startIndex));
}
/// <summary>
/// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 32-bit unsigned integer formed by four bytes beginning at startIndex.</returns>
public uint ToUInt32(byte[] value, int startIndex)
{
return unchecked((uint)this.ToInt32(value, startIndex));
}
/// <summary>
/// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A 64-bit unsigned integer formed by eight bytes beginning at startIndex.</returns>
public ulong ToUInt64(byte[] value, int startIndex)
{
return unchecked((ulong)this.ToInt64(value, startIndex));
}
/// <summary>
/// Returns a Boolean value converted from one byte at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>true if the byte at startIndex in value is nonzero; otherwise, false.</returns>
public bool ToBoolean(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 1);
return value[startIndex] != 0;
}
/// <summary>
/// Returns a Unicode character converted from two bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A character formed by two bytes beginning at startIndex.</returns>
public char ToChar(byte[] value, int startIndex)
{
return unchecked((char)this.ToInt16(value, startIndex));
}
/// <summary>
/// Returns a double-precision floating point number converted from eight bytes
/// at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A double precision floating point number formed by eight bytes beginning at startIndex.</returns>
public unsafe double ToDouble(byte[] value, int startIndex)
{
long intValue = this.ToInt64(value, startIndex);
return *((double*)&intValue);
}
/// <summary>
/// Returns a single-precision floating point number converted from four bytes
/// at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A single precision floating point number formed by four bytes beginning at startIndex.</returns>
public unsafe float ToSingle(byte[] value, int startIndex)
{
int intValue = this.ToInt32(value, startIndex);
return *((float*)&intValue);
}
/// <summary>
/// Returns a decimal value converted from sixteen bytes
/// at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <returns>A decimal formed by sixteen bytes beginning at startIndex.</returns>
public unsafe decimal ToDecimal(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 16);
decimal result = 0m;
int* presult = (int*)&result;
presult[0] = this.ToInt32(value, startIndex);
presult[1] = this.ToInt32(value, startIndex + 4);
presult[2] = this.ToInt32(value, startIndex + 8);
presult[3] = this.ToInt32(value, startIndex + 12);
return result;
}
}
}

127
src/ImageSharp/IO/EndianBitConverter.cs

@ -1,127 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Equivalent of <see cref="BitConverter"/>, but with either endianness.
/// </summary>
internal abstract partial class EndianBitConverter
{
/// <summary>
/// The little-endian bit converter.
/// </summary>
public static readonly LittleEndianBitConverter LittleEndianConverter = new LittleEndianBitConverter();
/// <summary>
/// The big-endian bit converter.
/// </summary>
public static readonly BigEndianBitConverter BigEndianConverter = new BigEndianBitConverter();
/// <summary>
/// Gets the byte order ("endianness") in which data is converted using this class.
/// </summary>
public abstract Endianness Endianness { get; }
/// <summary>
/// Gets a value indicating whether the byte order ("endianness") in which data is converted is little endian.
/// </summary>
/// <remarks>
/// Different computer architectures store data using different byte orders. "Big-endian"
/// means the most significant byte is on the left end of a word. "Little-endian" means the
/// most significant byte is on the right end of a word.
/// </remarks>
public abstract bool IsLittleEndian { get; }
/// <summary>
/// Gets the converter.
/// </summary>
/// <param name="endianness">The endianness.</param>
/// <returns>an <see cref="EndianBitConverter"/></returns>
/// <exception cref="ArgumentException">Not a valid form of Endianness - endianness</exception>
public static EndianBitConverter GetConverter(Endianness endianness)
{
switch (endianness)
{
case Endianness.LittleEndian:
return LittleEndianConverter;
case Endianness.BigEndian:
return BigEndianConverter;
default:
throw new ArgumentException("Not a valid form of Endianness", nameof(endianness));
}
}
/// <summary>
/// Returns a String converted from the elements of a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <remarks>All the elements of value are converted.</remarks>
/// <returns>
/// A String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
/// </returns>
public static string ToString(byte[] value)
{
return BitConverter.ToString(value);
}
/// <summary>
/// Returns a String converted from the elements of a byte array starting at a specified array position.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <remarks>The elements from array position startIndex to the end of the array are converted.</remarks>
/// <returns>
/// A String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
/// </returns>
public static string ToString(byte[] value, int startIndex)
{
return BitConverter.ToString(value, startIndex);
}
/// <summary>
/// Returns a String converted from a specified number of bytes at a specified position in a byte array.
/// </summary>
/// <param name="value">An array of bytes.</param>
/// <param name="startIndex">The starting position within value.</param>
/// <param name="length">The number of bytes to convert.</param>
/// <remarks>The length elements from array position startIndex are converted.</remarks>
/// <returns>
/// A String of hexadecimal pairs separated by hyphens, where each pair
/// represents the corresponding element in value; for example, "7F-2C-4A".
/// </returns>
public static string ToString(byte[] value, int startIndex, int length)
{
return BitConverter.ToString(value, startIndex, length);
}
/// <summary>
/// Checks the given argument for validity.
/// </summary>
/// <param name="value">The byte array passed in</param>
/// <param name="startIndex">The start index passed in</param>
/// <param name="bytesRequired">The number of bytes required</param>
/// <exception cref="ArgumentNullException">value is a null reference</exception>
/// <exception cref="ArgumentOutOfRangeException">
/// startIndex is less than zero or greater than the length of value minus bytesRequired.
/// </exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void CheckByteArgument(byte[] value, int startIndex, int bytesRequired)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
if (startIndex < 0 || startIndex > value.Length - bytesRequired)
{
throw new ArgumentOutOfRangeException(nameof(startIndex));
}
}
}
}

81
src/ImageSharp/IO/LittleEndianBitConverter.cs

@ -1,81 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.IO
{
/// <summary>
/// Implementation of EndianBitConverter which converts to/from little-endian byte arrays.
/// </summary>
internal sealed class LittleEndianBitConverter : EndianBitConverter
{
/// <inheritdoc/>
public override Endianness Endianness
{
get { return Endianness.LittleEndian; }
}
/// <inheritdoc/>
public override bool IsLittleEndian
{
get { return true; }
}
/// <inheritdoc/>
public override void CopyBytes(short value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 2);
buffer[index + 1] = (byte)(value >> 8);
buffer[index] = (byte)value;
}
/// <inheritdoc/>
public override void CopyBytes(int value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 4);
buffer[index + 3] = (byte)(value >> 24);
buffer[index + 2] = (byte)(value >> 16);
buffer[index + 1] = (byte)(value >> 8);
buffer[index] = (byte)value;
}
/// <inheritdoc/>
public override void CopyBytes(long value, byte[] buffer, int index)
{
CheckByteArgument(buffer, index, 8);
buffer[index + 7] = (byte)(value >> 56);
buffer[index + 6] = (byte)(value >> 48);
buffer[index + 5] = (byte)(value >> 40);
buffer[index + 4] = (byte)(value >> 32);
buffer[index + 3] = (byte)(value >> 24);
buffer[index + 2] = (byte)(value >> 16);
buffer[index + 1] = (byte)(value >> 8);
buffer[index] = (byte)value;
}
/// <inheritdoc/>
public unsafe override short ToInt16(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 2);
return (short)((value[startIndex + 1] << 8) | value[startIndex]);
}
/// <inheritdoc/>
public unsafe override int ToInt32(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 4);
return (value[startIndex + 3] << 24) | (value[startIndex + 2] << 16) | (value[startIndex + 1] << 8) | value[startIndex];
}
/// <inheritdoc/>
public unsafe override long ToInt64(byte[] value, int startIndex)
{
CheckByteArgument(value, startIndex, 8);
long p1 = (value[startIndex + 7] << 24) | (value[startIndex + 6] << 16) | (value[startIndex + 5] << 8) | value[startIndex + 4];
long p2 = (value[startIndex + 3] << 24) | (value[startIndex + 2] << 16) | (value[startIndex + 1] << 8) | value[startIndex];
return (p2 & 0xFFFFFFFF) | (p1 << 32);
}
}
}

16
src/ImageSharp/Image.LoadPixelData.cs

@ -2,12 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
@ -103,13 +98,7 @@ namespace SixLabors.ImageSharp
public static Image<TPixel> LoadPixelData<TPixel>(Configuration config, TPixel[] data, int width, int height) public static Image<TPixel> LoadPixelData<TPixel>(Configuration config, TPixel[] data, int width, int height)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int count = width * height; return LoadPixelData(config, new Span<TPixel>(data), width, height);
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new Image<TPixel>(config, width, height);
SpanHelper.Copy(data, image.GetPixelSpan(), count);
return image;
} }
/// <summary> /// <summary>
@ -128,7 +117,8 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data)); Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new Image<TPixel>(config, width, height); var image = new Image<TPixel>(config, width, height);
SpanHelper.Copy(data, image.Frames.RootFrame.GetPixelSpan(), count);
data.Slice(0, count).CopyTo(image.Frames.RootFrame.GetPixelSpan());
return image; return image;
} }

7
src/ImageSharp/ImageFrame.LoadPixelData.cs

@ -2,11 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -46,7 +42,8 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data)); Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new ImageFrame<TPixel>(memoryManager, width, height); var image = new ImageFrame<TPixel>(memoryManager, width, height);
SpanHelper.Copy(data, image.GetPixelSpan(), count);
data.Slice(0, count).CopyTo(image.GetPixelSpan());
return image; return image;
} }

2
src/ImageSharp/ImageFrame{TPixel}.cs

@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp
throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target)); throw new ArgumentException("ImageFrame<TPixel>.CopyTo(): target must be of the same size!", nameof(target));
} }
SpanHelper.Copy(this.GetPixelSpan(), target.Span); this.GetPixelSpan().CopyTo(target.Span);
} }
/// <summary> /// <summary>

4
src/ImageSharp/ImageSharp.csproj

@ -11,7 +11,7 @@
<AssemblyName>SixLabors.ImageSharp</AssemblyName> <AssemblyName>SixLabors.ImageSharp</AssemblyName>
<PackageId>SixLabors.ImageSharp</PackageId> <PackageId>SixLabors.ImageSharp</PackageId>
<PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Core</PackageTags> <PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Core</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl> <PackageIconUrl>https://raw.githubusercontent.com/SixLabors/Branding/master/icons/imagesharp/sixlabors.imagesharp.128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl> <PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl> <PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
@ -35,7 +35,7 @@
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" /> <Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-ci0005" /> <PackageReference Include="SixLabors.Core" Version="1.0.0-beta0005" />
<AdditionalFiles Include="..\..\stylecop.json" /> <AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta006"> <PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta006">
<PrivateAssets>All</PrivateAssets> <PrivateAssets>All</PrivateAssets>

2
src/ImageSharp/Memory/BasicArrayBuffer.cs

@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Memory
public int Length { get; } public int Length { get; }
public Span<T> Span => this.Array.AsSpan().Slice(0, this.Length); public Span<T> Span => new Span<T>(this.Array, 0, this.Length);
/// <summary> /// <summary>
/// Returns a reference to specified element of the buffer. /// Returns a reference to specified element of the buffer.

40
src/ImageSharp/Memory/SpanHelper.cs

@ -2,9 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
{ {
@ -13,19 +11,6 @@ namespace SixLabors.ImageSharp.Memory
/// </summary> /// </summary>
internal static class SpanHelper internal static class SpanHelper
{ {
/// <summary>
/// Fetches a <see cref="Vector{T}"/> from the beginning of the span.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
/// <param name="span">The span to fetch the vector from</param>
/// <returns>A <see cref="Vector{T}"/> reference to the beginning of the span</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref Vector<T> FetchVector<T>(this Span<T> span)
where T : struct
{
return ref Unsafe.As<T, Vector<T>>(ref MemoryMarshal.GetReference(span));
}
/// <summary> /// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest' /// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary> /// </summary>
@ -34,29 +19,10 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="destination">The destination <see cref="Span{T}"/>.</param> /// <param name="destination">The destination <see cref="Span{T}"/>.</param>
/// <param name="count">The number of elements to copy</param> /// <param name="count">The number of elements to copy</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(Span<T> source, Span<T> destination, int count) public static unsafe void Copy<T>(ReadOnlySpan<T> source, Span<T> destination, int count)
where T : struct where T : struct
{ {
DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count)); source.Slice(0, count).CopyTo(destination);
DebugGuard.MustBeLessThanOrEqualTo(count, destination.Length, nameof(count));
ref byte srcRef = ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(source));
ref byte destRef = ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(destination));
int byteCount = Unsafe.SizeOf<T>() * count;
// TODO: Use unfixed Unsafe.CopyBlock(ref T, ref T, int) for small blocks, when it gets available!
// This is now available. Check with Anton re intent. Do we replace both ifdefs?
fixed (byte* pSrc = &srcRef)
fixed (byte* pDest = &destRef)
{
#if NETSTANDARD1_1
Unsafe.CopyBlock(pDest, pSrc, (uint)byteCount);
#else
int destLength = destination.Length * Unsafe.SizeOf<T>();
Buffer.MemoryCopy(pSrc, pDest, destLength, byteCount);
#endif
}
} }
/// <summary> /// <summary>
@ -66,7 +32,7 @@ namespace SixLabors.ImageSharp.Memory
/// <param name="source">The <see cref="Span{T}"/> to copy elements from.</param> /// <param name="source">The <see cref="Span{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="Span{T}"/>.</param> /// <param name="destination">The destination <see cref="Span{T}"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy<T>(Span<T> source, Span<T> destination) public static void Copy<T>(ReadOnlySpan<T> source, Span<T> destination)
where T : struct where T : struct
{ {
Copy(source, destination, Math.Min(source.Length, destination.Length)); Copy(source, destination, Math.Min(source.Length, destination.Length));

25
src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers.Binary;
using System.Text; using System.Text;
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
@ -17,7 +18,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>the value</returns> /// <returns>the value</returns>
public ushort ReadUInt16() public ushort ReadUInt16()
{ {
return this.converter.ToUInt16(this.data, this.AddIndex(2)); return BinaryPrimitives.ReadUInt16BigEndian(new Span<byte>(this.data, this.AddIndex(2), 2));
} }
/// <summary> /// <summary>
@ -26,7 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>the value</returns> /// <returns>the value</returns>
public short ReadInt16() public short ReadInt16()
{ {
return this.converter.ToInt16(this.data, this.AddIndex(2)); return BinaryPrimitives.ReadInt16BigEndian(new Span<byte>(this.data, this.AddIndex(2), 2));
} }
/// <summary> /// <summary>
@ -35,7 +36,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>the value</returns> /// <returns>the value</returns>
public uint ReadUInt32() public uint ReadUInt32()
{ {
return this.converter.ToUInt32(this.data, this.AddIndex(4)); return BinaryPrimitives.ReadUInt32BigEndian(new Span<byte>(this.data, this.AddIndex(4), 4));
} }
/// <summary> /// <summary>
@ -44,7 +45,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>the value</returns> /// <returns>the value</returns>
public int ReadInt32() public int ReadInt32()
{ {
return this.converter.ToInt32(this.data, this.AddIndex(4)); return BinaryPrimitives.ReadInt32BigEndian(new Span<byte>(this.data, this.AddIndex(4), 4));
} }
/// <summary> /// <summary>
@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>the value</returns> /// <returns>the value</returns>
public ulong ReadUInt64() public ulong ReadUInt64()
{ {
return this.converter.ToUInt64(this.data, this.AddIndex(8)); return BinaryPrimitives.ReadUInt64BigEndian(new Span<byte>(this.data, this.AddIndex(8), 8));
} }
/// <summary> /// <summary>
@ -62,25 +63,29 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>the value</returns> /// <returns>the value</returns>
public long ReadInt64() public long ReadInt64()
{ {
return this.converter.ToInt64(this.data, this.AddIndex(8)); return BinaryPrimitives.ReadInt64BigEndian(new Span<byte>(this.data, this.AddIndex(8), 8));
} }
/// <summary> /// <summary>
/// Reads a float /// Reads a float
/// </summary> /// </summary>
/// <returns>the value</returns> /// <returns>the value</returns>
public float ReadSingle() public unsafe float ReadSingle()
{ {
return this.converter.ToSingle(this.data, this.AddIndex(4)); int intValue = this.ReadInt32();
return *((float*)&intValue);
} }
/// <summary> /// <summary>
/// Reads a double /// Reads a double
/// </summary> /// </summary>
/// <returns>the value</returns> /// <returns>the value</returns>
public double ReadDouble() public unsafe double ReadDouble()
{ {
return this.converter.ToDouble(this.data, this.AddIndex(8)); long intValue = this.ReadInt64();
return *((double*)&intValue);
} }
/// <summary> /// <summary>

6
src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs

@ -3,7 +3,6 @@
using System; using System;
using System.Text; using System.Text;
using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{ {
@ -20,11 +19,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// </summary> /// </summary>
private readonly byte[] data; private readonly byte[] data;
/// <summary>
/// The bit converter
/// </summary>
private readonly EndianBitConverter converter = new BigEndianBitConverter();
/// <summary> /// <summary>
/// The current reading position /// The current reading position
/// </summary> /// </summary>

2
src/ImageSharp/PixelAccessor{TPixel}.cs

@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp
/// <param name="target">The target pixel buffer accessor.</param> /// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TPixel> target) internal void CopyTo(PixelAccessor<TPixel> target)
{ {
SpanHelper.Copy(this.PixelBuffer.Span, target.PixelBuffer.Span); this.PixelBuffer.Span.CopyTo(target.PixelBuffer.Span);
} }
/// <summary> /// <summary>

56
src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba32(Span<Rgba32> source, Span<TPixel> destPixels, int count) internal virtual void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -35,14 +35,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromRgba32(Span{Rgba32}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromRgba32(ReadOnlySpan{Rgba32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba32Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromRgba32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromRgba32(sourceBytes.NonPortableCast<byte, Rgba32>(), destPixels, count); this.PackFromRgba32(sourceBytes.NonPortableCast<byte, Rgba32>(), destPixels, count);
} }
@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgba32"/> data.</param> /// <param name="dest">The destination span of <see cref="Rgba32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba32(Span<TPixel> sourcePixels, Span<Rgba32> dest, int count) internal virtual void ToRgba32(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -70,14 +70,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToRgba32(Span{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToRgba32(ReadOnlySpan{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba32Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToRgba32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
{ {
this.ToRgba32(sourceColors, destBytes.NonPortableCast<byte, Rgba32>(), count); this.ToRgba32(sourceColors, destBytes.NonPortableCast<byte, Rgba32>(), count);
} }
@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromBgra32(Span<Bgra32> source, Span<TPixel> destPixels, int count) internal virtual void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -106,14 +106,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromBgra32(Span{Bgra32}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromBgra32(ReadOnlySpan{Bgra32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromBgra32Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromBgra32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromBgra32(sourceBytes.NonPortableCast<byte, Bgra32>(), destPixels, count); this.PackFromBgra32(sourceBytes.NonPortableCast<byte, Bgra32>(), destPixels, count);
} }
@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Bgra32"/> data.</param> /// <param name="dest">The destination span of <see cref="Bgra32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToBgra32(Span<TPixel> sourcePixels, Span<Bgra32> dest, int count) internal virtual void ToBgra32(ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -141,14 +141,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToBgra32(Span{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToBgra32(ReadOnlySpan{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgra32Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToBgra32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
{ {
this.ToBgra32(sourceColors, destBytes.NonPortableCast<byte, Bgra32>(), count); this.ToBgra32(sourceColors, destBytes.NonPortableCast<byte, Bgra32>(), count);
} }
@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgb24(Span<Rgb24> source, Span<TPixel> destPixels, int count) internal virtual void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -177,14 +177,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromRgb24(Span{Rgb24}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromRgb24(ReadOnlySpan{Rgb24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgb24Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromRgb24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromRgb24(sourceBytes.NonPortableCast<byte, Rgb24>(), destPixels, count); this.PackFromRgb24(sourceBytes.NonPortableCast<byte, Rgb24>(), destPixels, count);
} }
@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgb24"/> data.</param> /// <param name="dest">The destination span of <see cref="Rgb24"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgb24(Span<TPixel> sourcePixels, Span<Rgb24> dest, int count) internal virtual void ToRgb24(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -212,14 +212,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToRgb24(Span{TPixel}, Span{Rgb24}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToRgb24(ReadOnlySpan{TPixel}, Span{Rgb24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb24Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToRgb24Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
{ {
this.ToRgb24(sourceColors, destBytes.NonPortableCast<byte, Rgb24>(), count); this.ToRgb24(sourceColors, destBytes.NonPortableCast<byte, Rgb24>(), count);
} }
@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromBgr24(Span<Bgr24> source, Span<TPixel> destPixels, int count) internal virtual void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -248,14 +248,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromBgr24(Span{Bgr24}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromBgr24(ReadOnlySpan{Bgr24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromBgr24Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromBgr24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromBgr24(sourceBytes.NonPortableCast<byte, Bgr24>(), destPixels, count); this.PackFromBgr24(sourceBytes.NonPortableCast<byte, Bgr24>(), destPixels, count);
} }
@ -267,7 +267,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Bgr24"/> data.</param> /// <param name="dest">The destination span of <see cref="Bgr24"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToBgr24(Span<TPixel> sourcePixels, Span<Bgr24> dest, int count) internal virtual void ToBgr24(ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -283,14 +283,14 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToBgr24(Span{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToBgr24(ReadOnlySpan{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgr24Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToBgr24Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
{ {
this.ToBgr24(sourceColors, destBytes.NonPortableCast<byte, Bgr24>(), count); this.ToBgr24(sourceColors, destBytes.NonPortableCast<byte, Bgr24>(), count);
} }

14
src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt

@ -21,7 +21,7 @@
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="<#=pixelType#>"/> data.</param> /// <param name="dest">The destination span of <see cref="<#=pixelType#>"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void To<#=pixelType#>(Span<TPixel> sourcePixels, Span<<#=pixelType#>> dest, int count) internal virtual void To<#=pixelType#>(ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -37,14 +37,14 @@
} }
/// <summary> /// <summary>
/// A helper for <see cref="To<#=pixelType#>(Span{TPixel}, Span{<#=pixelType#>}, int)"/> that expects a byte span as destination. /// A helper for <see cref="To<#=pixelType#>(ReadOnlySpan{TPixel}, Span{<#=pixelType#>}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void To<#=pixelType#>Bytes(Span<TPixel> sourceColors, Span<byte> destBytes, int count) internal void To<#=pixelType#>Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
{ {
this.To<#=pixelType#>(sourceColors, destBytes.NonPortableCast<byte, <#=pixelType#>>(), count); this.To<#=pixelType#>(sourceColors, destBytes.NonPortableCast<byte, <#=pixelType#>>(), count);
} }
@ -61,7 +61,7 @@
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span<TPixel> destPixels, int count) internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -79,14 +79,14 @@
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFrom<#=pixelType#>(Span{<#=pixelType#>}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFrom<#=pixelType#>(ReadOnlySpan{<#=pixelType#>}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="Span{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFrom<#=pixelType#>Bytes(Span<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFrom<#=pixelType#>(sourceBytes.NonPortableCast<byte, <#=pixelType#>>(), destPixels, count); this.PackFrom<#=pixelType#>(sourceBytes.NonPortableCast<byte, <#=pixelType#>>(), destPixels, count);
} }

12
src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs

@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromRgb24(Span<Rgb24> source, Span<Rgba32> destPixels, int count) internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgba32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToRgb24(Span<Rgba32> sourcePixels, Span<Rgb24> dest, int count) internal override void ToRgb24(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromBgr24(Span<Bgr24> source, Span<Rgba32> destPixels, int count) internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Rgba32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToBgr24(Span<Rgba32> sourcePixels, Span<Bgr24> dest, int count) internal override void ToBgr24(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromBgra32(Span<Bgra32> source, Span<Rgba32> destPixels, int count) internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Rgba32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToBgra32(Span<Rgba32> sourcePixels, Span<Bgra32> dest, int count) internal override void ToBgra32(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);

4
src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt

@ -14,7 +14,7 @@
#> #>
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFrom<#=pixelType#>(Span<<#=pixelType#>> source, Span<Rgba32> destPixels, int count) internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<Rgba32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
@ -36,7 +36,7 @@
#> #>
/// <inheritdoc /> /// <inheritdoc />
internal override void To<#=pixelType#>(Span<Rgba32> sourcePixels, Span<<#=pixelType#>> dest, int count) internal override void To<#=pixelType#>(ReadOnlySpan<Rgba32> sourcePixels, Span<<#=pixelType#>> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);

30
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -25,14 +25,14 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Bulk version of <see cref="IPixel.PackFromVector4(Vector4)"/> /// Bulk version of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// </summary> /// </summary>
/// <param name="sourceVectors">The <see cref="Span{T}"/> to the source vectors.</param> /// <param name="sourceVectors">The <see cref="Span{T}"/> to the source vectors.</param>
/// <param name="destColors">The <see cref="Span{T}"/> to the destination colors.</param> /// <param name="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromVector4(Span<Vector4> sourceVectors, Span<TPixel> destColors, int count) internal virtual void PackFromVector4(ReadOnlySpan<Vector4> sourceVectors, Span<TPixel> destinationColors, int count)
{ {
GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count); GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count);
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
ref TPixel destRef = ref MemoryMarshal.GetReference(destColors); ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
@ -46,14 +46,14 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Bulk version of <see cref="IPixel.ToVector4()"/>. /// Bulk version of <see cref="IPixel.ToVector4()"/>.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="Span{T}"/> to the destination vectors.</param> /// <param name="destinationVectors">The <see cref="Span{T}"/> to the destination vectors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToVector4(Span<TPixel> sourceColors, Span<Vector4> destVectors, int count) internal virtual void ToVector4(ReadOnlySpan<TPixel> sourceColors, Span<Vector4> destinationVectors, int count)
{ {
GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count);
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors); ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
@ -64,25 +64,25 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <summary> /// <summary>
/// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size.
/// Throwing an <see cref="ArgumentException"/> if the condition is not met. /// Throwing an <see cref="ArgumentException"/> if the condition is not met.
/// </summary> /// </summary>
/// <typeparam name="TSource">The source element type</typeparam> /// <typeparam name="TSource">The source element type</typeparam>
/// <typeparam name="TDest">The destination element type</typeparam> /// <typeparam name="TDest">The destination element type</typeparam>
/// <param name="source">The source span</param> /// <param name="source">The source span</param>
/// <param name="sourceParamName">The source parameter name</param> /// <param name="sourceParamName">The source parameter name</param>
/// <param name="dest">The destination span</param> /// <param name="destination">The destination span</param>
/// <param name="destParamName">The destination parameter name</param> /// <param name="destinationParamName">The destination parameter name</param>
/// <param name="minLength">The minimum length</param> /// <param name="minLength">The minimum length</param>
protected internal static void GuardSpans<TSource, TDest>( protected internal static void GuardSpans<TSource, TDest>(
Span<TSource> source, ReadOnlySpan<TSource> source,
string sourceParamName, string sourceParamName,
Span<TDest> dest, Span<TDest> destination,
string destParamName, string destinationParamName,
int minLength) int minLength)
{ {
Guard.MustBeSizedAtLeast(source, minLength, sourceParamName); Guard.MustBeSizedAtLeast(source, minLength, sourceParamName);
Guard.MustBeSizedAtLeast(dest, minLength, destParamName); Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName);
} }
} }
} }

16
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref> /// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see> /// </see>
/// </remarks> /// </remarks>
internal static void ToVector4SimdAligned(Span<Rgba32> sourceColors, Span<Vector4> destVectors, int count) internal static void ToVector4SimdAligned(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destVectors, int count)
{ {
if (!Vector.IsHardwareAccelerated) if (!Vector.IsHardwareAccelerated)
{ {
@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToVector4(Span<Rgba32> sourceColors, Span<Vector4> destVectors, int count) internal override void ToVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destVectors, int count)
{ {
Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
Guard.MustBeSizedAtLeast(destVectors, count, nameof(destVectors)); Guard.MustBeSizedAtLeast(destVectors, count, nameof(destVectors));
@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
} }
internal override void PackFromVector4(Span<Vector4> sourceVectors, Span<Rgba32> destColors, int count) internal override void PackFromVector4(ReadOnlySpan<Vector4> sourceVectors, Span<Rgba32> destColors, int count)
{ {
GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count); GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count);
@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
if (alignedCount > 0) if (alignedCount > 0)
{ {
Span<float> flatSrc = sourceVectors.Slice(0, alignedCount).NonPortableCast<Vector4, float>(); ReadOnlySpan<float> flatSrc = sourceVectors.Slice(0, alignedCount).NonPortableCast<Vector4, float>();
Span<byte> flatDest = destColors.NonPortableCast<Rgba32, byte>(); Span<byte> flatDest = destColors.NonPortableCast<Rgba32, byte>();
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest);
@ -145,19 +145,19 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromRgba32(Span<Rgba32> source, Span<Rgba32> destPixels, int count) internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
SpanHelper.Copy(source, destPixels, count); source.Slice(0, count).CopyTo(destPixels);
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToRgba32(Span<Rgba32> sourcePixels, Span<Rgba32> dest, int count) internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> dest, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
SpanHelper.Copy(sourcePixels, dest, count); sourcePixels.Slice(0, count).CopyTo(dest);
} }
/// <summary> /// <summary>

4
src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs

@ -18,11 +18,11 @@ namespace SixLabors.ImageSharp.PixelFormats
internal class PixelOperations : PixelOperations<RgbaVector> internal class PixelOperations : PixelOperations<RgbaVector>
{ {
/// <inheritdoc /> /// <inheritdoc />
internal override unsafe void ToVector4(Span<RgbaVector> sourceColors, Span<Vector4> destVectors, int count) internal override unsafe void ToVector4(ReadOnlySpan<RgbaVector> sourceColors, Span<Vector4> destVectors, int count)
{ {
GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count); GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count);
SpanHelper.Copy(sourceColors.NonPortableCast<RgbaVector, Vector4>(), destVectors, count); sourceColors.NonPortableCast<RgbaVector, Vector4>().Slice(0, count).CopyTo(destVectors);
} }
} }
} }

2
src/ImageSharp/Processing/Transforms/Processors/CropProcessor.cs

@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Transforms.Processors
{ {
Span<TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(minX); Span<TPixel> sourceRow = source.GetPixelRowSpan(y).Slice(minX);
Span<TPixel> targetRow = destination.GetPixelRowSpan(y - minY); Span<TPixel> targetRow = destination.GetPixelRowSpan(y - minY);
SpanHelper.Copy(sourceRow, targetRow, maxX - minX); sourceRow.Slice(0, maxX - minX).CopyTo(targetRow);
}); });
} }
} }

2
tests/ImageSharp.Benchmarks/Image/CopyPixels.cs → tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs

@ -5,7 +5,7 @@
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;

57
tests/ImageSharp.Benchmarks/Codecs/DecodeBmp.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using CoreSize = SixLabors.Primitives.Size;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class DecodeBmp : BenchmarkBase
{
private byte[] bmpBytes;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[GlobalSetup]
public void ReadImages()
{
if (this.bmpBytes == null)
{
this.bmpBytes = File.ReadAllBytes(this.TestImageFullPath);
}
}
[Params(TestImages.Bmp.Car)]
public string TestImage { get; set; }
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public Size BmpSystemDrawing()
{
using (var memoryStream = new MemoryStream(this.bmpBytes))
{
using (var image = SDImage.FromStream(memoryStream))
{
return image.Size;
}
}
}
[Benchmark(Description = "ImageSharp Bmp")]
public CoreSize BmpCore()
{
using (var memoryStream = new MemoryStream(this.bmpBytes))
{
using (var image = Image.Load<Rgba32>(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}
}

75
tests/ImageSharp.Benchmarks/Codecs/DecodeFilteredPng.cs

@ -0,0 +1,75 @@
// <copyright file="DecodePng.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using System.IO;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using CoreSize = SixLabors.Primitives.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class DecodeFilteredPng : BenchmarkBase
{
private byte[] filter0;
private byte[] filter1;
private byte[] filter2;
private byte[] filter3;
private byte[] filter4;
[GlobalSetup]
public void ReadImages()
{
this.filter0 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter0));
this.filter1 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter1));
this.filter2 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter2));
this.filter3 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter3));
this.filter4 = File.ReadAllBytes(TestImageFullPath(TestImages.Png.Filter4));
}
[Benchmark(Baseline = true, Description = "None-filtered PNG file")]
public CoreSize PngFilter0()
{
return LoadPng(this.filter0);
}
[Benchmark(Description = "Sub-filtered PNG file")]
public CoreSize PngFilter1()
{
return LoadPng(this.filter1);
}
[Benchmark(Description = "Up-filtered PNG file")]
public CoreSize PngFilter2()
{
return LoadPng(this.filter2);
}
[Benchmark(Description = "Average-filtered PNG file")]
public CoreSize PngFilter3()
{
return LoadPng(this.filter3);
}
[Benchmark(Description = "Paeth-filtered PNG file")]
public CoreSize PngFilter4()
{
return LoadPng(this.filter4);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static CoreSize LoadPng(byte[] bytes)
{
using (var image = Image.Load<Rgba32>(bytes))
{
return image.Size();
}
}
private static string TestImageFullPath(string path) => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, path);
}
}

57
tests/ImageSharp.Benchmarks/Codecs/DecodeGif.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using CoreSize = SixLabors.Primitives.Size;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class DecodeGif : BenchmarkBase
{
private byte[] gifBytes;
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[GlobalSetup]
public void ReadImages()
{
if (this.gifBytes == null)
{
this.gifBytes = File.ReadAllBytes(this.TestImageFullPath);
}
}
[Params(TestImages.Gif.Rings)]
public string TestImage { get; set; }
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public Size GifSystemDrawing()
{
using (var memoryStream = new MemoryStream(this.gifBytes))
{
using (var image = SDImage.FromStream(memoryStream))
{
return image.Size;
}
}
}
[Benchmark(Description = "ImageSharp Gif")]
public CoreSize GifCore()
{
using (var memoryStream = new MemoryStream(this.gifBytes))
{
using (var image = Image.Load<Rgba32>(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}
}

32
tests/ImageSharp.Benchmarks/Image/DecodePng.cs → tests/ImageSharp.Benchmarks/Codecs/DecodePng.cs

@ -1,31 +1,23 @@
// <copyright file="DecodePng.cs" company="James Jackson-South"> // Copyright (c) Six Labors and contributors.
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using CoreSize = SixLabors.Primitives.Size;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Tests;
using CoreImage = ImageSharp.Image;
using CoreSize = SixLabors.Primitives.Size;
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortClr))]
public class DecodePng : BenchmarkBase public class DecodePng : BenchmarkBase
{ {
private byte[] pngBytes; private byte[] pngBytes;
private string TestImageFullPath => Path.Combine( private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
TestEnvironment.InputImagesDirectoryFullPath,
this.TestImage);
[Params(TestImages.Png.Splash)] [Params(TestImages.Png.Splash)]
public string TestImage { get; set; } public string TestImage { get; set; }
@ -44,7 +36,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using (var memoryStream = new MemoryStream(this.pngBytes)) using (var memoryStream = new MemoryStream(this.pngBytes))
{ {
using (var image = Image.FromStream(memoryStream)) using (var image = SDImage.FromStream(memoryStream))
{ {
return image.Size; return image.Size;
} }
@ -56,9 +48,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using (var memoryStream = new MemoryStream(this.pngBytes)) using (var memoryStream = new MemoryStream(this.pngBytes))
{ {
using (var image = CoreImage.Load<Rgba32>(memoryStream)) using (var image = Image.Load<Rgba32>(memoryStream))
{ {
return new CoreSize(image.Width, image.Height); return image.Size();
} }
} }
} }

35
tests/ImageSharp.Benchmarks/Image/EncodeBmp.cs → tests/ImageSharp.Benchmarks/Codecs/EncodeBmp.cs

@ -1,25 +1,20 @@
// <copyright file="EncodeBmp.cs" company="James Jackson-South"> // Copyright (c) Six Labors and contributors.
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
using System.Drawing; [Config(typeof(Config.ShortClr))]
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using CoreImage = ImageSharp.Image;
public class EncodeBmp : BenchmarkBase public class EncodeBmp : BenchmarkBase
{ {
// System.Drawing needs this.
private Stream bmpStream; private Stream bmpStream;
private Image bmpDrawing; private SDImage bmpDrawing;
private Image<Rgba32> bmpCore; private Image<Rgba32> bmpCore;
[GlobalSetup] [GlobalSetup]
@ -27,10 +22,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
if (this.bmpStream == null) if (this.bmpStream == null)
{ {
this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp"); this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car));
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream); this.bmpCore = Image.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0; this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream); this.bmpDrawing = SDImage.FromStream(this.bmpStream);
} }
} }
@ -45,7 +40,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")] [Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public void BmpSystemDrawing() public void BmpSystemDrawing()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
this.bmpDrawing.Save(memoryStream, ImageFormat.Bmp); this.bmpDrawing.Save(memoryStream, ImageFormat.Bmp);
} }
@ -54,10 +49,10 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp Bmp")] [Benchmark(Description = "ImageSharp Bmp")]
public void BmpCore() public void BmpCore()
{ {
using (MemoryStream memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
this.bmpCore.SaveAsBmp(memoryStream); this.bmpCore.SaveAsBmp(memoryStream);
} }
} }
} }
} }

28
tests/ImageSharp.Benchmarks/Codecs/EncodeBmpMultiple.cs

@ -0,0 +1,28 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Bmp;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
[Benchmark(Description = "EncodeBmpMultiple - ImageSharp")]
public void EncodeBmpImageSharp()
{
this.ForEachImageSharpImage((img, ms) => { img.Save(ms, new BmpEncoder()); return null; });
}
[Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")]
public void EncodeBmpSystemDrawing()
{
this.ForEachSystemDrawingImage((img, ms) => { img.Save(ms, ImageFormat.Bmp); return null; });
}
}
}

63
tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.ImageSharp.Tests;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class EncodeGif : BenchmarkBase
{
// System.Drawing needs this.
private Stream bmpStream;
private SDImage bmpDrawing;
private Image<Rgba32> bmpCore;
[GlobalSetup]
public void ReadImages()
{
if (this.bmpStream == null)
{
this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car));
this.bmpCore = Image.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = SDImage.FromStream(this.bmpStream);
}
}
[GlobalCleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public void GifSystemDrawing()
{
using (var memoryStream = new MemoryStream())
{
this.bmpDrawing.Save(memoryStream, ImageFormat.Gif);
}
}
[Benchmark(Description = "ImageSharp Gif")]
public void GifCore()
{
// Try to get as close to System.Drawing's output as possible
var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) };
using (var memoryStream = new MemoryStream())
{
this.bmpCore.SaveAsGif(memoryStream, options);
}
}
}
}

37
tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs

@ -0,0 +1,37 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Processing.Quantization;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
[Params(InputImageCategory.AllImages)]
public override InputImageCategory InputCategory { get; set; }
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Gif/" };
[Benchmark(Description = "EncodeGifMultiple - ImageSharp")]
public void EncodeGifImageSharp()
{
this.ForEachImageSharpImage((img, ms) =>
{
// Try to get as close to System.Drawing's output as possible
var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) };
img.Save(ms, options); return null;
});
}
[Benchmark(Baseline = true, Description = "EncodeGifMultiple - System.Drawing")]
public void EncodeGifSystemDrawing()
{
this.ForEachSystemDrawingImage((img, ms) => { img.Save(ms, ImageFormat.Gif); return null; });
}
}
}

31
tests/ImageSharp.Benchmarks/Image/EncodeIndexedPng.cs → tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs

@ -1,39 +1,32 @@
// <copyright file="EncodeIndexedPng.cs" company="James Jackson-South"> // Copyright (c) Six Labors and contributors.
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>
using System.IO; using System.IO;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Quantization; using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.ImageSharp.Tests;
using CoreImage = SixLabors.ImageSharp.Image; using CoreImage = SixLabors.ImageSharp.Image;
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
/// <summary> /// <summary>
/// Benchmarks saving png files using different quantizers. System.Drawing cannot save indexed png files so we cannot compare. /// Benchmarks saving png files using different quantizers. System.Drawing cannot save indexed png files so we cannot compare.
/// </summary> /// </summary>
[Config(typeof(Config.ShortClr))]
public class EncodeIndexedPng : BenchmarkBase public class EncodeIndexedPng : BenchmarkBase
{ {
// System.Drawing needs this. // System.Drawing needs this.
private Stream bmpStream; private Stream bmpStream;
private Image<Rgba32> bmpCore; private Image<Rgba32> bmpCore;
[Params(false)]
public bool LargeImage { get; set; }
[GlobalSetup] [GlobalSetup]
public void ReadImages() public void ReadImages()
{ {
if (this.bmpStream == null) if (this.bmpStream == null)
{ {
string path = this.LargeImage this.bmpStream = File.OpenRead(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Bmp.Car));
? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg"
: "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp";
this.bmpStream = File.OpenRead(path);
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream); this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0; this.bmpStream.Position = 0;
} }
@ -51,9 +44,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
var encoder = new PngEncoder { Quantizer = new OctreeQuantizer() }; var options = new PngEncoder { Quantizer = KnownQuantizers.Octree };
this.bmpCore.SaveAsPng(memoryStream, options);
this.bmpCore.SaveAsPng(memoryStream, encoder);
} }
} }
@ -63,7 +55,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
var options = new PngEncoder { Quantizer = new OctreeQuantizer(false) }; var options = new PngEncoder { Quantizer = new OctreeQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
} }
@ -73,8 +64,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
var options = new PngEncoder { Quantizer = new PaletteQuantizer() }; var options = new PngEncoder { Quantizer = KnownQuantizers.Palette };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
} }
@ -85,7 +75,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) }; var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
} }
@ -95,8 +84,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
{ {
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
var options = new PngEncoder { Quantizer = new WuQuantizer() }; var options = new PngEncoder { Quantizer = KnownQuantizers.Wu };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
} }
@ -107,7 +95,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
var options = new PngEncoder { Quantizer = new WuQuantizer(false) }; var options = new PngEncoder { Quantizer = new WuQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options); this.bmpCore.SaveAsPng(memoryStream, options);
} }
} }

63
tests/ImageSharp.Benchmarks/Codecs/EncodePng.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[Config(typeof(Config.ShortClr))]
public class EncodePng : BenchmarkBase
{
// System.Drawing needs this.
private Stream bmpStream;
private SDImage bmpDrawing;
private Image<Rgba32> bmpCore;
[Params(false)]
public bool LargeImage { get; set; }
[GlobalSetup]
public void ReadImages()
{
if (this.bmpStream == null)
{
string path = Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.LargeImage ? TestImages.Jpeg.Baseline.Jpeg420Exif : TestImages.Bmp.Car);
this.bmpStream = File.OpenRead(path);
this.bmpCore = Image.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = SDImage.FromStream(this.bmpStream);
}
}
[GlobalCleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public void PngSystemDrawing()
{
using (var memoryStream = new MemoryStream())
{
this.bmpDrawing.Save(memoryStream, ImageFormat.Png);
}
}
[Benchmark(Description = "ImageSharp Png")]
public void PngCore()
{
using (var memoryStream = new MemoryStream())
{
this.bmpCore.SaveAsPng(memoryStream);
}
}
}
}

32
tests/ImageSharp.Benchmarks/Codecs/GetSetPixel.cs

@ -0,0 +1,32 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Drawing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
public class GetSetPixel : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")]
public Color ResizeSystemDrawing()
{
using (var source = new Bitmap(400, 400))
{
source.SetPixel(200, 200, Color.White);
return source.GetPixel(200, 200);
}
}
[Benchmark(Description = "ImageSharp GetSet pixel")]
public Rgba32 ResizeCore()
{
using (var image = new Image<Rgba32>(400, 400))
{
image[200, 200] = Rgba32.White;
return image[200, 200];
}
}
}
}

2
tests/ImageSharp.Benchmarks/Image/ImageBenchmarkTests.cs → tests/ImageSharp.Benchmarks/Codecs/ImageBenchmarkTests.cs

@ -12,7 +12,7 @@
#if TEST #if TEST
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

43
tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpeg.cs → tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg.cs

@ -1,33 +1,24 @@
// <copyright file="DecodeJpeg.cs" company="James Jackson-South"> // Copyright (c) Six Labors and contributors.
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
using CoreSize = SixLabors.Primitives.Size;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort;
using SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort;
using SixLabors.ImageSharp.Tests;
using CoreImage = SixLabors.ImageSharp.Image;
using CoreSize = SixLabors.Primitives.Size;
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortClr))]
public class DecodeJpeg : BenchmarkBase public class DecodeJpeg : BenchmarkBase
{ {
private byte[] jpegBytes; private byte[] jpegBytes;
private string TestImageFullPath => Path.Combine( private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
TestEnvironment.InputImagesDirectoryFullPath,
this.TestImage);
[Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)] [Params(TestImages.Jpeg.Baseline.Jpeg420Exif, TestImages.Jpeg.Baseline.Calliphora)]
public string TestImage { get; set; } public string TestImage { get; set; }
@ -44,9 +35,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
[Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")] [Benchmark(Baseline = true, Description = "Decode Jpeg - System.Drawing")]
public Size JpegSystemDrawing() public Size JpegSystemDrawing()
{ {
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes)) using (var memoryStream = new MemoryStream(this.jpegBytes))
{ {
using (Image image = Image.FromStream(memoryStream)) using (var image = SDImage.FromStream(memoryStream))
{ {
return image.Size; return image.Size;
} }
@ -56,9 +47,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
[Benchmark(Description = "Decode Jpeg - ImageSharp")] [Benchmark(Description = "Decode Jpeg - ImageSharp")]
public CoreSize JpegImageSharpOrig() public CoreSize JpegImageSharpOrig()
{ {
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes)) using (var memoryStream = new MemoryStream(this.jpegBytes))
{ {
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(memoryStream, new OrigJpegDecoder())) using (var image = Image.Load<Rgba32>(memoryStream, new OrigJpegDecoder()))
{ {
return new CoreSize(image.Width, image.Height); return new CoreSize(image.Width, image.Height);
} }
@ -68,9 +59,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
[Benchmark(Description = "Decode Jpeg - ImageSharp PdfJs")] [Benchmark(Description = "Decode Jpeg - ImageSharp PdfJs")]
public CoreSize JpegImageSharpPdfJs() public CoreSize JpegImageSharpPdfJs()
{ {
using (MemoryStream memoryStream = new MemoryStream(this.jpegBytes)) using (var memoryStream = new MemoryStream(this.jpegBytes))
{ {
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(memoryStream, new PdfJsJpegDecoder())) using (var image = Image.Load<Rgba32>(memoryStream, new PdfJsJpegDecoder()))
{ {
return new CoreSize(image.Width, image.Height); return new CoreSize(image.Width, image.Height);
} }

25
tests/ImageSharp.Benchmarks/Image/Jpeg/DecodeJpegMultiple.cs → tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegMultiple.cs

@ -1,18 +1,13 @@
// <copyright file="DecodeJpegMultiple.cs" company="James Jackson-South"> // Copyright (c) Six Labors and contributors.
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright>
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using CoreImage = SixLabors.ImageSharp.Image;
[Config(typeof(Config.ShortClr))] [Config(typeof(Config.ShortClr))]
public class DecodeJpegMultiple : MultiImageBenchmarkBase public class DecodeJpegMultiple : MultiImageBenchmarkBase
{ {
@ -27,17 +22,13 @@ namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
[Benchmark(Description = "DecodeJpegMultiple - ImageSharp")] [Benchmark(Description = "DecodeJpegMultiple - ImageSharp")]
public void DecodeJpegImageSharpNwq() public void DecodeJpegImageSharpNwq()
{ {
this.ForEachStream( this.ForEachStream(ms => Image.Load<Rgba32>(ms));
ms => CoreImage.Load<Rgba32>(ms)
);
} }
[Benchmark(Baseline = true, Description = "DecodeJpegMultiple - System.Drawing")] [Benchmark(Baseline = true, Description = "DecodeJpegMultiple - System.Drawing")]
public void DecodeJpegSystemDrawing() public void DecodeJpegSystemDrawing()
{ {
this.ForEachStream( this.ForEachStream(SDImage.FromStream);
System.Drawing.Image.FromStream
);
} }
} }
} }

2
tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpeg.cs → tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpeg.cs

@ -5,7 +5,7 @@
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;

30
tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegMultiple.cs

@ -0,0 +1,30 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Collections.Generic;
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{
[Config(typeof(Config.ShortClr))] // It's long enough to iterate through multiple files
public class EncodeJpegMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
protected override IEnumerable<string> SearchPatterns => new[] { "*.bmp", "*.jpg" };
[Benchmark(Description = "EncodeJpegMultiple - ImageSharp")]
public void EncodeJpegImageSharp()
{
this.ForEachImageSharpImage((img, ms) => { img.Save(ms, new JpegEncoder()); return null; });
}
[Benchmark(Baseline = true, Description = "EncodeJpegMultiple - System.Drawing")]
public void EncodeJpegSystemDrawing()
{
this.ForEachSystemDrawingImage((img, ms) => { img.Save(ms, ImageFormat.Jpeg); return null; });
}
}
}

2
tests/ImageSharp.Benchmarks/Image/Jpeg/YCbCrColorConversion.cs → tests/ImageSharp.Benchmarks/Codecs/Jpeg/YCbCrColorConversion.cs

@ -1,4 +1,4 @@
namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg
{ {
using System; using System;
using System.Numerics; using System.Numerics;

2
tests/ImageSharp.Benchmarks/Image/MultiImageBenchmarkBase.cs → tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs

@ -5,7 +5,7 @@
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image namespace SixLabors.ImageSharp.Benchmarks.Codecs
{ {
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

2
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs

@ -1,5 +1,5 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;

2
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs

@ -1,5 +1,5 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
using System; using System;

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -1,5 +1,5 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
using System; using System;
using System.Numerics; using System.Numerics;

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -1,5 +1,5 @@
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
using System; using System;
using System.Numerics; using System.Numerics;

2
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -4,7 +4,7 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

2
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs

@ -1,4 +1,4 @@
namespace SixLabors.ImageSharp.Benchmarks.Color namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

2
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs

@ -1,4 +1,4 @@
namespace SixLabors.ImageSharp.Benchmarks.Color namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

2
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs

@ -1,4 +1,4 @@
namespace SixLabors.ImageSharp.Benchmarks.Color namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

2
tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs

@ -1,4 +1,4 @@
namespace SixLabors.ImageSharp.Benchmarks.Color namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

2
tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs

@ -1,4 +1,4 @@
namespace SixLabors.ImageSharp.Benchmarks.Color namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces
{ {
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;

5
tests/ImageSharp.Benchmarks/Config.cs

@ -22,9 +22,8 @@ namespace SixLabors.ImageSharp.Benchmarks
public ShortClr() public ShortClr()
{ {
this.Add( this.Add(
Job.Clr.WithLaunchCount(1) Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3),
.WithWarmupCount(3) Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithTargetCount(3)
.WithTargetCount(3)
); );
} }
} }

10
tests/ImageSharp.Benchmarks/General/Vectorization/VectorFetching.cs

@ -3,7 +3,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -90,13 +90,13 @@ namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
} }
[Benchmark] [Benchmark]
public void FetchWithSpanUtility() public void FetchWithUnsafeCastFromReference()
{ {
Vector<float> v = new Vector<float>(this.testValue); var v = new Vector<float>(this.testValue);
Span<float> span = new Span<float>(this.data); var span = new Span<float>(this.data);
ref Vector<float> start = ref span.FetchVector(); ref Vector<float> start = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(span));
int n = this.InputSize / Vector<uint>.Count; int n = this.InputSize / Vector<uint>.Count;

56
tests/ImageSharp.Benchmarks/Image/DecodeBmp.cs

@ -1,56 +0,0 @@
// <copyright file="DecodeBmp.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using CoreImage = ImageSharp.Image;
using CoreSize = SixLabors.Primitives.Size;
public class DecodeBmp : BenchmarkBase
{
private byte[] bmpBytes;
[GlobalSetup]
public void ReadImages()
{
if (this.bmpBytes == null)
{
this.bmpBytes = File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp");
}
}
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public Size BmpSystemDrawing()
{
using (MemoryStream memoryStream = new MemoryStream(this.bmpBytes))
{
using (Image image = Image.FromStream(memoryStream))
{
return image.Size;
}
}
}
[Benchmark(Description = "ImageSharp Bmp")]
public CoreSize BmpCore()
{
using (MemoryStream memoryStream = new MemoryStream(this.bmpBytes))
{
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}
}

74
tests/ImageSharp.Benchmarks/Image/DecodeFilteredPng.cs

@ -1,74 +0,0 @@
// <copyright file="DecodePng.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp;
using SixLabors.Primitives;
using CoreImage = ImageSharp.Image;
public class DecodeFilteredPng : BenchmarkBase
{
private MemoryStream filter0;
private MemoryStream filter1;
private MemoryStream filter2;
private MemoryStream filter3;
private MemoryStream filter4;
[GlobalSetup]
public void ReadImages()
{
this.filter0 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter0.png"));
this.filter1 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter1.png"));
this.filter2 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter2.png"));
this.filter3 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter3.png"));
this.filter4 = new MemoryStream(File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/filter4.png"));
}
private SixLabors.Primitives.Size LoadPng(MemoryStream stream)
{
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(stream))
{
return new SixLabors.Primitives.Size(image.Width, image.Height);
}
}
[Benchmark(Baseline = true, Description = "None-filtered PNG file")]
public Size PngFilter0()
{
return LoadPng(filter0);
}
[Benchmark(Description = "Sub-filtered PNG file")]
public Size PngFilter1()
{
return LoadPng(filter1);
}
[Benchmark(Description = "Up-filtered PNG file")]
public Size PngFilter2()
{
return LoadPng(filter2);
}
[Benchmark(Description = "Average-filtered PNG file")]
public Size PngFilter3()
{
return LoadPng(filter3);
}
[Benchmark(Description = "Paeth-filtered PNG file")]
public Size PngFilter4()
{
return LoadPng(filter4);
}
}
}

56
tests/ImageSharp.Benchmarks/Image/DecodeGif.cs

@ -1,56 +0,0 @@
// <copyright file="DecodeGif.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Drawing;
using System.IO;
using BenchmarkDotNet.Attributes;
using CoreImage = ImageSharp.Image;
using CoreSize = SixLabors.Primitives.Size;
public class DecodeGif : BenchmarkBase
{
private byte[] gifBytes;
[GlobalSetup]
public void ReadImages()
{
if (this.gifBytes == null)
{
this.gifBytes = File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Gif/rings.gif");
}
}
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public Size GifSystemDrawing()
{
using (MemoryStream memoryStream = new MemoryStream(this.gifBytes))
{
using (Image image = Image.FromStream(memoryStream))
{
return image.Size;
}
}
}
[Benchmark(Description = "ImageSharp Gif")]
public CoreSize GifCore()
{
using (MemoryStream memoryStream = new MemoryStream(this.gifBytes))
{
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}
}
}
}
}

43
tests/ImageSharp.Benchmarks/Image/EncodeBmpMultiple.cs

@ -1,43 +0,0 @@
// <copyright file="EncodeBmpMultiple.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Collections.Generic;
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
[Config(typeof(Config.ShortClr))]
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
[Benchmark(Description = "EncodeBmpMultiple - ImageSharp")]
public void EncodeBmpImageSharp()
{
this.ForEachImageSharpImage(
(img, ms) =>
{
img.Save(ms, new BmpEncoder());
return null;
});
}
[Benchmark(Baseline = true, Description = "EncodeBmpMultiple - System.Drawing")]
public void EncodeBmpSystemDrawing()
{
this.ForEachSystemDrawingImage(
(img, ms) =>
{
img.Save(ms, ImageFormat.Bmp);
return null;
});
}
}
}

63
tests/ImageSharp.Benchmarks/Image/EncodeGif.cs

@ -1,63 +0,0 @@
// <copyright file="EncodeGif.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using CoreImage = ImageSharp.Image;
public class EncodeGif : BenchmarkBase
{
// System.Drawing needs this.
private Stream bmpStream;
private Image bmpDrawing;
private Image<Rgba32> bmpCore;
[GlobalSetup]
public void ReadImages()
{
if (this.bmpStream == null)
{
this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp");
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
}
}
[GlobalCleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public void GifSystemDrawing()
{
using (MemoryStream memoryStream = new MemoryStream())
{
this.bmpDrawing.Save(memoryStream, ImageFormat.Gif);
}
}
[Benchmark(Description = "ImageSharp Gif")]
public void GifCore()
{
using (MemoryStream memoryStream = new MemoryStream())
{
this.bmpCore.SaveAsGif(memoryStream);
}
}
}
}

54
tests/ImageSharp.Benchmarks/Image/EncodeGifMultiple.cs

@ -1,54 +0,0 @@
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Collections.Generic;
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
[Config(typeof(SingleRunConfig))]
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
public class SingleRunConfig : Config
{
public SingleRunConfig()
{
this.Add(
Job.Default.WithLaunchCount(1)
.WithWarmupCount(1)
.WithTargetCount(1)
);
}
}
[Params(InputImageCategory.AllImages)]
public override InputImageCategory InputCategory { get; set; }
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Gif/" };
[Benchmark(Description = "EncodeGifMultiple - ImageSharp")]
public void EncodeGifImageSharp()
{
this.ForEachImageSharpImage(
(img, ms) =>
{
img.Save(ms, new GifEncoder());
return null;
});
}
[Benchmark(Baseline = true, Description = "EncodeGifMultiple - System.Drawing")]
public void EncodeGifSystemDrawing()
{
this.ForEachSystemDrawingImage(
(img, ms) =>
{
img.Save(ms, ImageFormat.Gif);
return null;
});
}
}
}

83
tests/ImageSharp.Benchmarks/Image/EncodePng.cs

@ -1,83 +0,0 @@
// <copyright file="EncodePng.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Processing.Quantization;
using SixLabors.ImageSharp.Tests;
using CoreImage = ImageSharp.Image;
public class EncodePng : BenchmarkBase
{
// System.Drawing needs this.
private Stream bmpStream;
private Image bmpDrawing;
private Image<Rgba32> bmpCore;
[Params(false)]
public bool LargeImage { get; set; }
[Params(false)]
public bool UseOctreeQuantizer { get; set; }
[GlobalSetup]
public void ReadImages()
{
if (this.bmpStream == null)
{
string path = Path.Combine(
TestEnvironment.InputImagesDirectoryFullPath,
this.LargeImage ? TestImages.Jpeg.Baseline.Jpeg420Exif : TestImages.Bmp.Car);
this.bmpStream = File.OpenRead(path);
this.bmpCore = CoreImage.Load<Rgba32>(this.bmpStream);
this.bmpStream.Position = 0;
this.bmpDrawing = Image.FromStream(this.bmpStream);
}
}
[GlobalCleanup]
public void Cleanup()
{
this.bmpStream.Dispose();
this.bmpCore.Dispose();
this.bmpDrawing.Dispose();
}
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public void PngSystemDrawing()
{
using (var memoryStream = new MemoryStream())
{
this.bmpDrawing.Save(memoryStream, ImageFormat.Png);
}
}
[Benchmark(Description = "ImageSharp Png")]
public void PngCore()
{
using (var memoryStream = new MemoryStream())
{
IQuantizer quantizer = this.UseOctreeQuantizer
?
(IQuantizer)new OctreeQuantizer()
: new PaletteQuantizer();
var options = new PngEncoder { Quantizer = quantizer };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}
}
}

41
tests/ImageSharp.Benchmarks/Image/GetSetPixel.cs

@ -1,41 +0,0 @@
// <copyright file="GetSetPixel.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks.Image
{
using System.Drawing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SystemColor = System.Drawing.Color;
public class GetSetPixel : BenchmarkBase
{
[Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")]
public SystemColor ResizeSystemDrawing()
{
using (Bitmap source = new Bitmap(400, 400))
{
source.SetPixel(200, 200, SystemColor.White);
return source.GetPixel(200, 200);
}
}
[Benchmark(Description = "ImageSharp GetSet pixel")]
public Rgba32 ResizeCore()
{
using (Image<Rgba32> image = new Image<Rgba32>(400, 400))
{
using (PixelAccessor<Rgba32> imagePixels = image.Lock())
{
imagePixels[200, 200] = Rgba32.White;
return imagePixels[200, 200];
}
}
}
}
}

44
tests/ImageSharp.Benchmarks/Image/Jpeg/EncodeJpegMultiple.cs

@ -1,44 +0,0 @@
// <copyright file="EncodeJpegMultiple.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks.Image.Jpeg
{
using System.Collections.Generic;
using System.Drawing.Imaging;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Formats.Jpeg;
[Config(typeof(Config.ShortClr))] // It's long enough to iterate through multiple files
public class EncodeJpegMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };
protected override IEnumerable<string> SearchPatterns => new[] { "*.bmp", "*.jpg" };
[Benchmark(Description = "EncodeJpegMultiple - ImageSharp")]
public void EncodeJpegImageSharp()
{
this.ForEachImageSharpImage(
(img, ms) =>
{
img.Save(ms, new JpegEncoder());
return null;
});
}
[Benchmark(Baseline = true, Description = "EncodeJpegMultiple - System.Drawing")]
public void EncodeJpegSystemDrawing()
{
this.ForEachSystemDrawingImage(
(img, ms) =>
{
img.Save(ms, ImageFormat.Jpeg);
return null;
});
}
}
}

8
tests/ImageSharp.Tests/Drawing/Paths/FillRectangle.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.Equal(GraphicsOptions.Default, processor.Options); Assert.Equal(GraphicsOptions.Default, processor.Options);
ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region); ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region);
Shapes.RectangularePolygon rect = Assert.IsType<Shapes.RectangularePolygon>(region.Shape); Shapes.RectangularPolygon rect = Assert.IsType<Shapes.RectangularPolygon>(region.Shape);
Assert.Equal(rect.Location.X, this.rectangle.X); Assert.Equal(rect.Location.X, this.rectangle.X);
Assert.Equal(rect.Location.Y, this.rectangle.Y); Assert.Equal(rect.Location.Y, this.rectangle.Y);
Assert.Equal(rect.Size.Width, this.rectangle.Width); Assert.Equal(rect.Size.Width, this.rectangle.Width);
@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.Equal(this.noneDefault, processor.Options); Assert.Equal(this.noneDefault, processor.Options);
ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region); ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region);
Shapes.RectangularePolygon rect = Assert.IsType<Shapes.RectangularePolygon>(region.Shape); Shapes.RectangularPolygon rect = Assert.IsType<Shapes.RectangularPolygon>(region.Shape);
Assert.Equal(rect.Location.X, this.rectangle.X); Assert.Equal(rect.Location.X, this.rectangle.X);
Assert.Equal(rect.Location.Y, this.rectangle.Y); Assert.Equal(rect.Location.Y, this.rectangle.Y);
Assert.Equal(rect.Size.Width, this.rectangle.Width); Assert.Equal(rect.Size.Width, this.rectangle.Width);
@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.Equal(GraphicsOptions.Default, processor.Options); Assert.Equal(GraphicsOptions.Default, processor.Options);
ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region); ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region);
Shapes.RectangularePolygon rect = Assert.IsType<Shapes.RectangularePolygon>(region.Shape); Shapes.RectangularPolygon rect = Assert.IsType<Shapes.RectangularPolygon>(region.Shape);
Assert.Equal(rect.Location.X, this.rectangle.X); Assert.Equal(rect.Location.X, this.rectangle.X);
Assert.Equal(rect.Location.Y, this.rectangle.Y); Assert.Equal(rect.Location.Y, this.rectangle.Y);
Assert.Equal(rect.Size.Width, this.rectangle.Width); Assert.Equal(rect.Size.Width, this.rectangle.Width);
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing.Paths
Assert.Equal(this.noneDefault, processor.Options); Assert.Equal(this.noneDefault, processor.Options);
ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region); ShapeRegion region = Assert.IsType<ShapeRegion>(processor.Region);
Shapes.RectangularePolygon rect = Assert.IsType<Shapes.RectangularePolygon>(region.Shape); Shapes.RectangularPolygon rect = Assert.IsType<Shapes.RectangularPolygon>(region.Shape);
Assert.Equal(rect.Location.X, this.rectangle.X); Assert.Equal(rect.Location.X, this.rectangle.X);
Assert.Equal(rect.Location.Y, this.rectangle.Y); Assert.Equal(rect.Location.Y, this.rectangle.Y);
Assert.Equal(rect.Size.Width, this.rectangle.Width); Assert.Equal(rect.Size.Width, this.rectangle.Width);

2
tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs

@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing
{ {
image.Mutate(x => x image.Mutate(x => x
.BackgroundColor(Rgba32.Blue) .BackgroundColor(Rgba32.Blue)
.Fill(Rgba32.HotPink, new SixLabors.Shapes.RectangularePolygon(10, 10, 190, 140))); .Fill(Rgba32.HotPink, new SixLabors.Shapes.RectangularPolygon(10, 10, 190, 140)));
image.Save($"{path}/Rectangle.png"); image.Save($"{path}/Rectangle.png");
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) using (PixelAccessor<Rgba32> sourcePixels = image.Lock())

228
tests/ImageSharp.Tests/IO/BigEndianBitConverter.CopyBytesTests.cs

@ -1,228 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The <see cref="BigEndianBitConverter"/> tests.
/// </summary>
public class BigEndianBitConverterCopyBytesTests
{
[Fact]
public void CopyToWithNullBufferThrowsException()
{
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(false, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((short)42, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((ushort)42, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42u, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42L, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((ulong)42L, null, 0));
}
[Fact]
public void CopyToWithIndexTooBigThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(false, new byte[1], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((short)42, new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((ushort)42, new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42, new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42u, new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42L, new byte[8], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((ulong)42L, new byte[8], 1));
}
[Fact]
public void CopyToWithBufferTooSmallThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(false, new byte[0], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((short)42, new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((ushort)42, new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42, new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42u, new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes(42L, new byte[7], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.CopyBytes((ulong)42L, new byte[7], 0));
}
/// <summary>
/// Tests that passing a <see cref="bool"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesBoolean()
{
byte[] buffer = new byte[1];
EndianBitConverter.BigEndianConverter.CopyBytes(false, buffer, 0);
this.CheckBytes(new byte[] { 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(true, buffer, 0);
this.CheckBytes(new byte[] { 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="short"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesShort()
{
byte[] buffer = new byte[2];
EndianBitConverter.BigEndianConverter.CopyBytes((short)0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((short)1, buffer, 0);
this.CheckBytes(new byte[] { 0, 1 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((short)256, buffer, 0);
this.CheckBytes(new byte[] { 1, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((short)-1, buffer, 0);
this.CheckBytes(new byte[] { 255, 255 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((short)257, buffer, 0);
this.CheckBytes(new byte[] { 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="ushort"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesUShort()
{
byte[] buffer = new byte[2];
EndianBitConverter.BigEndianConverter.CopyBytes((ushort)0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((ushort)1, buffer, 0);
this.CheckBytes(new byte[] { 0, 1 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((ushort)256, buffer, 0);
this.CheckBytes(new byte[] { 1, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(ushort.MaxValue, buffer, 0);
this.CheckBytes(new byte[] { 255, 255 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((ushort)257, buffer, 0);
this.CheckBytes(new byte[] { 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="int"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesInt()
{
byte[] buffer = new byte[4];
EndianBitConverter.BigEndianConverter.CopyBytes(0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(256, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(65536, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(16777216, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(-1, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(257, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="uint"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesUInt()
{
byte[] buffer = new byte[4];
EndianBitConverter.BigEndianConverter.CopyBytes((uint)0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((uint)1, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((uint)256, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((uint)65536, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((uint)16777216, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(uint.MaxValue, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes((uint)257, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="long"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesLong()
{
byte[] buffer = new byte[8];
EndianBitConverter.BigEndianConverter.CopyBytes(0L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(256L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(65536L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(16777216L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(4294967296L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1099511627776L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1099511627776L * 256, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1099511627776L * 256 * 256, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(-1L, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(257L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="ulong"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesULong()
{
byte[] buffer = new byte[8];
EndianBitConverter.BigEndianConverter.CopyBytes(0UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(256UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(65536UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(16777216UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(4294967296UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1099511627776UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1099511627776UL * 256, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(1099511627776UL * 256 * 256, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(ulong.MaxValue, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, buffer);
EndianBitConverter.BigEndianConverter.CopyBytes(257UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, buffer);
}
/// <summary>
/// Tests the two byte arrays for equality.
/// </summary>
/// <param name="expected">The expected bytes.</param>
/// <param name="actual">The actual bytes.</param>
private void CheckBytes(byte[] expected, byte[] actual)
{
Assert.Equal(expected.Length, actual.Length);
Assert.Equal(expected, actual);
}
}
}

129
tests/ImageSharp.Tests/IO/BigEndianBitConverter.GetBytesTests.cs

@ -1,129 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The <see cref="BigEndianBitConverter"/> tests.
/// </summary>
public class BigEndianBitConverterGetBytesTests
{
/// <summary>
/// Tests that passing a <see cref="bool"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesBoolean()
{
this.CheckBytes(new byte[] { 0 }, EndianBitConverter.BigEndianConverter.GetBytes(false));
this.CheckBytes(new byte[] { 1 }, EndianBitConverter.BigEndianConverter.GetBytes(true));
}
/// <summary>
/// Tests that passing a <see cref="short"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesShort()
{
this.CheckBytes(new byte[] { 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((short)0));
this.CheckBytes(new byte[] { 0, 1 }, EndianBitConverter.BigEndianConverter.GetBytes((short)1));
this.CheckBytes(new byte[] { 1, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((short)256));
this.CheckBytes(new byte[] { 255, 255 }, EndianBitConverter.BigEndianConverter.GetBytes((short)-1));
this.CheckBytes(new byte[] { 1, 1 }, EndianBitConverter.BigEndianConverter.GetBytes((short)257));
}
/// <summary>
/// Tests that passing a <see cref="ushort"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesUShort()
{
this.CheckBytes(new byte[] { 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((ushort)0));
this.CheckBytes(new byte[] { 0, 1 }, EndianBitConverter.BigEndianConverter.GetBytes((ushort)1));
this.CheckBytes(new byte[] { 1, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((ushort)256));
this.CheckBytes(new byte[] { 255, 255 }, EndianBitConverter.BigEndianConverter.GetBytes(ushort.MaxValue));
this.CheckBytes(new byte[] { 1, 1 }, EndianBitConverter.BigEndianConverter.GetBytes((ushort)257));
}
/// <summary>
/// Tests that passing a <see cref="int"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesInt()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(0));
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.BigEndianConverter.GetBytes(1));
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(256));
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(65536));
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(16777216));
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.BigEndianConverter.GetBytes(-1));
this.CheckBytes(new byte[] { 0, 0, 1, 1 }, EndianBitConverter.BigEndianConverter.GetBytes(257));
}
/// <summary>
/// Tests that passing a <see cref="uint"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesUInt()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((uint)0));
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.BigEndianConverter.GetBytes((uint)1));
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((uint)256));
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((uint)65536));
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes((uint)16777216));
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.BigEndianConverter.GetBytes(uint.MaxValue));
this.CheckBytes(new byte[] { 0, 0, 1, 1 }, EndianBitConverter.BigEndianConverter.GetBytes((uint)257));
}
/// <summary>
/// Tests that passing a <see cref="long"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesLong()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(0L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.BigEndianConverter.GetBytes(1L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(256L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(65536L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(16777216L));
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(4294967296L));
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(1099511627776L));
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(1099511627776L * 256));
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(1099511627776L * 256 * 256));
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.BigEndianConverter.GetBytes(-1L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, EndianBitConverter.BigEndianConverter.GetBytes(257L));
}
/// <summary>
/// Tests that passing a <see cref="ulong"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesULong()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(0UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.BigEndianConverter.GetBytes(1UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(256UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(65536UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(16777216UL));
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(4294967296UL));
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(1099511627776UL));
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(1099511627776UL * 256));
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.BigEndianConverter.GetBytes(1099511627776UL * 256 * 256));
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.BigEndianConverter.GetBytes(ulong.MaxValue));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, EndianBitConverter.BigEndianConverter.GetBytes(257UL));
}
/// <summary>
/// Tests the two byte arrays for equality.
/// </summary>
/// <param name="expected">The expected bytes.</param>
/// <param name="actual">The actual bytes.</param>
private void CheckBytes(byte[] expected, byte[] actual)
{
Assert.Equal(expected.Length, actual.Length);
Assert.Equal(expected, actual);
}
}
}

216
tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs

@ -1,216 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The <see cref="BigEndianBitConverter"/> tests.
/// </summary>
public class BigEndianBitConverterTests
{
[Fact]
public void CopyToWithNullBufferThrowsException()
{
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToBoolean(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToInt16(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToUInt16(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToInt32(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToUInt32(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToInt64(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.BigEndianConverter.ToUInt64(null, 0));
}
[Fact]
public void CopyToWithIndexTooBigThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToBoolean(new byte[1], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToInt16(new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToUInt16(new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToInt32(new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToUInt32(new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToInt64(new byte[8], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToUInt64(new byte[8], 1));
}
[Fact]
public void CopyToWithBufferTooSmallThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToBoolean(new byte[0], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToInt16(new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToUInt16(new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToInt32(new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToUInt32(new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToInt64(new byte[7], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.BigEndianConverter.ToUInt64(new byte[7], 0));
}
/// <summary>
/// Tests that passing a <see cref="bool"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToBoolean()
{
Assert.False(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0 }, 0));
Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1 }, 0));
Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 42 }, 0));
Assert.False(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1));
Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1));
Assert.True(EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 42 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="short"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToInt16()
{
Assert.Equal((short)0, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 0, 0 }, 0));
Assert.Equal((short)1, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 0, 1 }, 0));
Assert.Equal((short)256, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 1, 0 }, 0));
Assert.Equal((short)-1, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 255, 255 }, 0));
Assert.Equal((short)257, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 1, 1 }, 0));
Assert.Equal((short)0, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 1, 0, 0 }, 1));
Assert.Equal((short)1, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 1, 0, 1 }, 1));
Assert.Equal((short)256, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 0, 1, 0 }, 1));
Assert.Equal((short)-1, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 0, 255, 255 }, 1));
Assert.Equal((short)257, EndianBitConverter.BigEndianConverter.ToInt16(new byte[] { 0, 1, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="ushort"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToUInt16()
{
Assert.Equal((ushort)0, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 0, 0 }, 0));
Assert.Equal((ushort)1, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 0, 1 }, 0));
Assert.Equal((ushort)256, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 1, 0 }, 0));
Assert.Equal(ushort.MaxValue, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 255, 255 }, 0));
Assert.Equal((ushort)257, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 1, 1 }, 0));
Assert.Equal((ushort)0, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 1, 0, 0 }, 1));
Assert.Equal((ushort)1, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 1, 0, 1 }, 1));
Assert.Equal((ushort)256, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 0, 1, 0 }, 1));
Assert.Equal(ushort.MaxValue, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 0, 255, 255 }, 1));
Assert.Equal((ushort)257, EndianBitConverter.BigEndianConverter.ToUInt16(new byte[] { 0, 1, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="int"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToInt32()
{
Assert.Equal(0, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 0, 0, 0 }, 0));
Assert.Equal(1, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 0, 0, 1 }, 0));
Assert.Equal(256, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 0, 1, 0 }, 0));
Assert.Equal(65536, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 1, 0, 0 }, 0));
Assert.Equal(16777216, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 1, 0, 0, 0 }, 0));
Assert.Equal(-1, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 255, 255, 255, 255 }, 0));
Assert.Equal(257, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 0, 1, 1 }, 0));
Assert.Equal(0, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 1, 0, 0, 0, 0 }, 1));
Assert.Equal(1, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 1, 0, 0, 0, 1 }, 1));
Assert.Equal(256, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 1, 0, 0, 1, 0 }, 1));
Assert.Equal(65536, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 1, 0, 1, 0, 0 }, 1));
Assert.Equal(16777216, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 1, 0, 0, 0 }, 1));
Assert.Equal(-1, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 0, 255, 255, 255, 255 }, 1));
Assert.Equal(257, EndianBitConverter.BigEndianConverter.ToInt32(new byte[] { 1, 0, 0, 1, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="uint"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToUInt32()
{
Assert.Equal((uint)0, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 0, 0, 0 }, 0));
Assert.Equal((uint)1, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 0, 0, 1 }, 0));
Assert.Equal((uint)256, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 0, 1, 0 }, 0));
Assert.Equal((uint)65536, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 1, 0, 0 }, 0));
Assert.Equal((uint)16777216, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 0 }, 0));
Assert.Equal(uint.MaxValue, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 255, 255, 255, 255 }, 0));
Assert.Equal((uint)257, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 0, 1, 1 }, 0));
Assert.Equal((uint)0, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 0, 0 }, 1));
Assert.Equal((uint)1, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 0, 1 }, 1));
Assert.Equal((uint)256, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 1, 0 }, 1));
Assert.Equal((uint)65536, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 1, 0, 1, 0, 0 }, 1));
Assert.Equal((uint)16777216, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 1, 0, 0, 0 }, 1));
Assert.Equal(uint.MaxValue, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 0, 255, 255, 255, 255 }, 1));
Assert.Equal((uint)257, EndianBitConverter.BigEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 1, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="long"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToInt64()
{
Assert.Equal(0L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, 0));
Assert.Equal(256L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, 0));
Assert.Equal(65536L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, 0));
Assert.Equal(16777216L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, 0));
Assert.Equal(4294967296L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, 0));
Assert.Equal(1099511627776L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1099511627776L * 256, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1099511627776L * 256 * 256, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(-1L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, 0));
Assert.Equal(257L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, 0));
Assert.Equal(4294967295L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 255, 255, 255, 255 }, 0));
Assert.Equal(-4294967296L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 255, 255, 255, 255, 0, 0, 0, 0 }, 0));
Assert.Equal(0L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 1 }, 1));
Assert.Equal(256L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 0 }, 1));
Assert.Equal(65536L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 1, 0, 0 }, 1));
Assert.Equal(16777216L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 1, 0, 0, 0 }, 1));
Assert.Equal(4294967296L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0, 0 }, 1));
Assert.Equal(1099511627776L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 1, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1099511627776L * 256, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 1, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1099511627776L * 256 * 256, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(-1L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 0, 255, 255, 255, 255, 255, 255, 255, 255 }, 1));
Assert.Equal(257L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 1 }, 1));
Assert.Equal(4294967295L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 255, 255, 255, 255 }, 1));
Assert.Equal(-4294967296L, EndianBitConverter.BigEndianConverter.ToInt64(new byte[] { 1, 255, 255, 255, 255, 0, 0, 0, 0 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="ulong"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToUInt64()
{
Assert.Equal(0UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, 0));
Assert.Equal(256UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, 0));
Assert.Equal(65536UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, 0));
Assert.Equal(16777216UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, 0));
Assert.Equal(4294967296UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, 0));
Assert.Equal(1099511627776UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1099511627776UL * 256, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1099511627776UL * 256 * 256, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(ulong.MaxValue, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, 0));
Assert.Equal(257UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, 0));
Assert.Equal(0UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 1 }, 1));
Assert.Equal(256UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 0 }, 1));
Assert.Equal(65536UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 1, 0, 0 }, 1));
Assert.Equal(16777216UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 1, 0, 0, 0 }, 1));
Assert.Equal(4294967296UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0, 0 }, 1));
Assert.Equal(1099511627776UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 1, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1099511627776UL * 256, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 1, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1099511627776UL * 256 * 256, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(ulong.MaxValue, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 0, 255, 255, 255, 255, 255, 255, 255, 255 }, 1));
Assert.Equal(257UL, EndianBitConverter.BigEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 1 }, 1));
}
}
}

61
tests/ImageSharp.Tests/IO/EndianBinaryReaderTests.cs

@ -1,61 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using System.Text;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The endian binary reader tests.
/// </summary>
public class EndianBinaryReaderTests
{
/// <summary>
/// The test string.
/// </summary>
private const string TestString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmopqrstuvwxyz";
/// <summary>
/// The test bytes.
/// </summary>
private static readonly byte[] TestBytes = Encoding.ASCII.GetBytes(TestString);
/// <summary>
/// Tests to ensure that the reader can read beyond internal buffer size.
/// </summary>
[Fact]
public void ReadCharsBeyondInternalBufferSize()
{
MemoryStream stream = new MemoryStream(TestBytes);
using (EndianBinaryReader subject = new EndianBinaryReader(Endianness.LittleEndian, stream))
{
char[] chars = new char[TestString.Length];
subject.Read(chars, 0, chars.Length);
Assert.Equal(TestString, new string(chars));
}
}
/// <summary>
/// Tests to ensure that the reader cannot read beyond the provided buffer size.
/// </summary>
[Fact]
public void ReadCharsBeyondProvidedBufferSize()
{
Assert.Throws<ArgumentException>(
() =>
{
MemoryStream stream = new MemoryStream(TestBytes);
using (EndianBinaryReader subject = new EndianBinaryReader(Endianness.LittleEndian, stream))
{
char[] chars = new char[TestString.Length - 1];
subject.Read(chars, 0, TestString.Length);
}
});
}
}
}

97
tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs

@ -0,0 +1,97 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.IO;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
public class EndianBinaryReaderWriterTests
{
[Fact]
public void RoundtripSingles()
{
foreach ((Endianness endianness, byte[] bytes) in new[] {
(Endianness.BigEndian, new byte[] { 64, 73, 15, 219 }),
(Endianness.LittleEndian, new byte[] { 219, 15, 73, 64 })
})
{
var stream = new MemoryStream();
using (var writer = new EndianBinaryWriter(endianness, stream))
{
writer.Write((float)Math.PI);
Assert.Equal(bytes, stream.ToArray());
}
}
}
[Fact]
public void RoundtripDoubles()
{
foreach ((Endianness endianness, byte[] bytes) in new[] {
(Endianness.BigEndian, new byte[] { 64, 9, 33, 251, 84, 68, 45, 24 }),
(Endianness.LittleEndian, new byte[] { 24, 45, 68, 84, 251, 33, 9, 64 })
})
{
var stream = new MemoryStream();
using (var writer = new EndianBinaryWriter(endianness, stream))
{
writer.Write(Math.PI);
Assert.Equal(bytes, stream.ToArray());
}
}
}
/// <summary>
/// Ensures that the data written through a binary writer can be read back through the reader
/// </summary>
[Fact]
public void RoundtripValues()
{
foreach (Endianness endianness in new[] { Endianness.BigEndian, Endianness.LittleEndian })
{
var stream = new MemoryStream();
var writer = new EndianBinaryWriter(endianness, stream);
writer.Write(true); // Bool
writer.Write((byte)1); // Byte
writer.Write((short)1); // Int16
writer.Write(1); // Int32
writer.Write(1L); // Int64
writer.Write(1f); // Single
writer.Write(1d); // Double
writer.Write((sbyte)1); // SByte
writer.Write((ushort)1); // UInt16
writer.Write((uint)1); // UInt32
writer.Write(1UL); // ULong
Assert.Equal(43, stream.Length);
stream.Position = 0;
var reader = new EndianBinaryReader(endianness, stream);
Assert.True(reader.ReadBoolean()); // Bool
Assert.Equal((byte)1, reader.ReadByte()); // Byte
Assert.Equal((short)1, reader.ReadInt16()); // Int16
Assert.Equal(1, reader.ReadInt32()); // Int32
Assert.Equal(1L, reader.ReadInt64()); // Int64
Assert.Equal(1f, reader.ReadSingle()); // Single
Assert.Equal(1d, reader.ReadDouble()); // Double
Assert.Equal((sbyte)1, reader.ReadSByte()); // SByte
Assert.Equal((ushort)1, reader.ReadUInt16()); // UInt16
Assert.Equal((uint)1, reader.ReadUInt32()); // UInt32
Assert.Equal(1UL, reader.ReadUInt64()); // ULong
stream.Dispose();
}
}
}
}

228
tests/ImageSharp.Tests/IO/LittleEndianBitConverter.CopyBytesTests.cs

@ -1,228 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The <see cref="LittleEndianBitConverter"/> tests.
/// </summary>
public class LittleEndianBitConverterCopyBytesTests
{
[Fact]
public void CopyToWithNullBufferThrowsException()
{
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(false, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((short)42, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)42, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42u, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42L, null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ulong)42L, null, 0));
}
[Fact]
public void CopyToWithIndexTooBigThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(false, new byte[1], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((short)42, new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)42, new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42, new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42u, new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42L, new byte[8], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ulong)42L, new byte[8], 1));
}
[Fact]
public void CopyToWithBufferTooSmallThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(false, new byte[0], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((short)42, new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)42, new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42, new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42u, new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42L, new byte[7], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ulong)42L, new byte[7], 0));
}
/// <summary>
/// Tests that passing a <see cref="bool"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesBoolean()
{
byte[] buffer = new byte[1];
EndianBitConverter.LittleEndianConverter.CopyBytes(false, buffer, 0);
this.CheckBytes(new byte[] { 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(true, buffer, 0);
this.CheckBytes(new byte[] { 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="short"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesShort()
{
byte[] buffer = new byte[2];
EndianBitConverter.LittleEndianConverter.CopyBytes((short)0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((short)1, buffer, 0);
this.CheckBytes(new byte[] { 1, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((short)256, buffer, 0);
this.CheckBytes(new byte[] { 0, 1 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((short)-1, buffer, 0);
this.CheckBytes(new byte[] { 255, 255 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((short)257, buffer, 0);
this.CheckBytes(new byte[] { 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="ushort"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesUShort()
{
byte[] buffer = new byte[2];
EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)1, buffer, 0);
this.CheckBytes(new byte[] { 1, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)256, buffer, 0);
this.CheckBytes(new byte[] { 0, 1 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(ushort.MaxValue, buffer, 0);
this.CheckBytes(new byte[] { 255, 255 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)257, buffer, 0);
this.CheckBytes(new byte[] { 1, 1 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="int"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesInt()
{
byte[] buffer = new byte[4];
EndianBitConverter.LittleEndianConverter.CopyBytes(0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(256, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(65536, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(16777216, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(-1, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(257, buffer, 0);
this.CheckBytes(new byte[] { 1, 1, 0, 0 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="uint"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesUInt()
{
byte[] buffer = new byte[4];
EndianBitConverter.LittleEndianConverter.CopyBytes((uint)0, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((uint)1, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((uint)256, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((uint)65536, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((uint)16777216, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(uint.MaxValue, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes((uint)257, buffer, 0);
this.CheckBytes(new byte[] { 1, 1, 0, 0 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="long"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesLong()
{
byte[] buffer = new byte[8];
EndianBitConverter.LittleEndianConverter.CopyBytes(0L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1L, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(256L, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(65536L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(16777216L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(4294967296L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1099511627776L, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1099511627776L * 256, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1099511627776L * 256 * 256, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(-1L, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(257L, buffer, 0);
this.CheckBytes(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, buffer);
}
/// <summary>
/// Tests that passing a <see cref="ulong"/> returns the correct bytes.
/// </summary>
[Fact]
public void CopyBytesULong()
{
byte[] buffer = new byte[8];
EndianBitConverter.LittleEndianConverter.CopyBytes(0UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1UL, buffer, 0);
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(256UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(65536UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(16777216UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(4294967296UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1099511627776UL, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1099511627776UL * 256, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(1099511627776UL * 256 * 256, buffer, 0);
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(ulong.MaxValue, buffer, 0);
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, buffer);
EndianBitConverter.LittleEndianConverter.CopyBytes(257UL, buffer, 0);
this.CheckBytes(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, buffer);
}
/// <summary>
/// Tests the two byte arrays for equality.
/// </summary>
/// <param name="expected">The expected bytes.</param>
/// <param name="actual">The actual bytes.</param>
private void CheckBytes(byte[] expected, byte[] actual)
{
Assert.Equal(expected.Length, actual.Length);
Assert.Equal(expected, actual);
}
}
}

129
tests/ImageSharp.Tests/IO/LittleEndianBitConverter.GetBytesTests.cs

@ -1,129 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The <see cref="LittleEndianBitConverter"/> tests.
/// </summary>
public class LittleEndianBitConverterGetBytesTests
{
/// <summary>
/// Tests that passing a <see cref="bool"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesBoolean()
{
this.CheckBytes(new byte[] { 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(false));
this.CheckBytes(new byte[] { 1 }, EndianBitConverter.LittleEndianConverter.GetBytes(true));
}
/// <summary>
/// Tests that passing a <see cref="short"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesShort()
{
this.CheckBytes(new byte[] { 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((short)0));
this.CheckBytes(new byte[] { 1, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((short)1));
this.CheckBytes(new byte[] { 0, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes((short)256));
this.CheckBytes(new byte[] { 255, 255 }, EndianBitConverter.LittleEndianConverter.GetBytes((short)-1));
this.CheckBytes(new byte[] { 1, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes((short)257));
}
/// <summary>
/// Tests that passing a <see cref="ushort"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesUShort()
{
this.CheckBytes(new byte[] { 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((ushort)0));
this.CheckBytes(new byte[] { 1, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((ushort)1));
this.CheckBytes(new byte[] { 0, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes((ushort)256));
this.CheckBytes(new byte[] { 255, 255 }, EndianBitConverter.LittleEndianConverter.GetBytes(ushort.MaxValue));
this.CheckBytes(new byte[] { 1, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes((ushort)257));
}
/// <summary>
/// Tests that passing a <see cref="int"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesInt()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(0));
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1));
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(256));
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(65536));
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes(16777216));
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.LittleEndianConverter.GetBytes(-1));
this.CheckBytes(new byte[] { 1, 1, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(257));
}
/// <summary>
/// Tests that passing a <see cref="uint"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesUInt()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((uint)0));
this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((uint)1));
this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((uint)256));
this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((uint)65536));
this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes((uint)16777216));
this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.LittleEndianConverter.GetBytes(uint.MaxValue));
this.CheckBytes(new byte[] { 1, 1, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes((uint)257));
}
/// <summary>
/// Tests that passing a <see cref="long"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesLong()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(0L));
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1L));
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(256L));
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(65536L));
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(16777216L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(4294967296L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1099511627776L));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1099511627776L * 256));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes(1099511627776L * 256 * 256));
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.LittleEndianConverter.GetBytes(-1L));
this.CheckBytes(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(257L));
}
/// <summary>
/// Tests that passing a <see cref="ulong"/> returns the correct bytes.
/// </summary>
[Fact]
public void GetBytesULong()
{
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(0UL));
this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1UL));
this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(256UL));
this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(65536UL));
this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(16777216UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(4294967296UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1099511627776UL));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(1099511627776UL * 256));
this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.LittleEndianConverter.GetBytes(1099511627776UL * 256 * 256));
this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.LittleEndianConverter.GetBytes(ulong.MaxValue));
this.CheckBytes(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(257UL));
}
/// <summary>
/// Tests the two byte arrays for equality.
/// </summary>
/// <param name="expected">The expected bytes.</param>
/// <param name="actual">The actual bytes.</param>
private void CheckBytes(byte[] expected, byte[] actual)
{
Assert.Equal(expected.Length, actual.Length);
Assert.Equal(expected, actual);
}
}
}

214
tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs

@ -1,214 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.IO;
using Xunit;
namespace SixLabors.ImageSharp.Tests.IO
{
/// <summary>
/// The <see cref="LittleEndianBitConverter"/> tests.
/// </summary>
public class LittleEndianBitConverterToTypeTests
{
[Fact]
public void CopyToWithNullBufferThrowsException()
{
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToBoolean(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToInt16(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToUInt16(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToInt32(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToUInt32(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToInt64(null, 0));
Assert.Throws<ArgumentNullException>(() => EndianBitConverter.LittleEndianConverter.ToUInt64(null, 0));
}
[Fact]
public void CopyToWithIndexTooBigThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[1], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToInt16(new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[2], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToInt32(new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[4], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToInt64(new byte[8], 1));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[8], 1));
}
[Fact]
public void CopyToWithBufferTooSmallThrowsException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[0], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToInt16(new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[1], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToInt32(new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[3], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToInt64(new byte[7], 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[7], 0));
}
/// <summary>
/// Tests that passing a <see cref="bool"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToBoolean()
{
Assert.False(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0 }, 0));
Assert.True(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1 }, 0));
Assert.False(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1));
Assert.True(EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="short"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToInt16()
{
Assert.Equal((short)0, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 0, 0 }, 0));
Assert.Equal((short)1, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 1, 0 }, 0));
Assert.Equal((short)256, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 0, 1 }, 0));
Assert.Equal((short)-1, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 255, 255 }, 0));
Assert.Equal((short)257, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 1, 1 }, 0));
Assert.Equal((short)0, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 1, 0, 0 }, 1));
Assert.Equal((short)1, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 0, 1, 0 }, 1));
Assert.Equal((short)256, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 1, 0, 1 }, 1));
Assert.Equal((short)-1, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 0, 255, 255 }, 1));
Assert.Equal((short)257, EndianBitConverter.LittleEndianConverter.ToInt16(new byte[] { 0, 1, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="ushort"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToUInt16()
{
Assert.Equal((ushort)0, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 0, 0 }, 0));
Assert.Equal((ushort)1, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 1, 0 }, 0));
Assert.Equal((ushort)256, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 0, 1 }, 0));
Assert.Equal(ushort.MaxValue, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 255, 255 }, 0));
Assert.Equal((ushort)257, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 1, 1 }, 0));
Assert.Equal((ushort)0, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 1, 0, 0 }, 1));
Assert.Equal((ushort)1, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 0, 1, 0 }, 1));
Assert.Equal((ushort)256, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 1, 0, 1 }, 1));
Assert.Equal(ushort.MaxValue, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 0, 255, 255 }, 1));
Assert.Equal((ushort)257, EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[] { 0, 1, 1 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="int"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToInt32()
{
Assert.Equal(0, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 0, 0, 0 }, 0));
Assert.Equal(1, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 1, 0, 0, 0 }, 0));
Assert.Equal(256, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 1, 0, 0 }, 0));
Assert.Equal(65536, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 0, 1, 0 }, 0));
Assert.Equal(16777216, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 0, 0, 1 }, 0));
Assert.Equal(-1, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 255, 255, 255, 255 }, 0));
Assert.Equal(257, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 1, 1, 0, 0 }, 0));
Assert.Equal(0, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 1, 0, 0, 0, 0 }, 1));
Assert.Equal(1, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 1, 0, 0, 0 }, 1));
Assert.Equal(256, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 1, 0, 1, 0, 0 }, 1));
Assert.Equal(65536, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 1, 0, 0, 1, 0 }, 1));
Assert.Equal(16777216, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 1, 0, 0, 0, 1 }, 1));
Assert.Equal(-1, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 255, 255, 255, 255 }, 1));
Assert.Equal(257, EndianBitConverter.LittleEndianConverter.ToInt32(new byte[] { 0, 1, 1, 0, 0 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="uint"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToUInt32()
{
Assert.Equal((uint)0, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 0, 0, 0 }, 0));
Assert.Equal((uint)1, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 0 }, 0));
Assert.Equal((uint)256, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 1, 0, 0 }, 0));
Assert.Equal((uint)65536, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 0, 1, 0 }, 0));
Assert.Equal((uint)16777216, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 0, 0, 1 }, 0));
Assert.Equal(uint.MaxValue, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 255, 255, 255, 255 }, 0));
Assert.Equal((uint)257, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 1, 1, 0, 0 }, 0));
Assert.Equal((uint)0, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 0, 0 }, 1));
Assert.Equal((uint)1, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 1, 0, 0, 0 }, 1));
Assert.Equal((uint)256, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 1, 0, 1, 0, 0 }, 1));
Assert.Equal((uint)65536, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 1, 0 }, 1));
Assert.Equal((uint)16777216, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 1, 0, 0, 0, 1 }, 1));
Assert.Equal(uint.MaxValue, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 255, 255, 255, 255 }, 1));
Assert.Equal((uint)257, EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[] { 0, 1, 1, 0, 0 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="long"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToInt64()
{
Assert.Equal(0L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(256L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(65536L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(16777216L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, 0));
Assert.Equal(4294967296L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, 0));
Assert.Equal(1099511627776L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, 0));
Assert.Equal(1099511627776L * 256, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, 0));
Assert.Equal(1099511627776L * 256 * 256, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, 0));
Assert.Equal(-1L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, 0));
Assert.Equal(257L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(4294967295L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 255, 255, 255, 255, 0, 0, 0, 0 }, 0));
Assert.Equal(-4294967296L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 255, 255, 255, 255 }, 0));
Assert.Equal(0L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(256L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 1, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(65536L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 1, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(16777216L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0, 0 }, 1));
Assert.Equal(4294967296L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 1, 0, 0, 0 }, 1));
Assert.Equal(1099511627776L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 1, 0, 0 }, 1));
Assert.Equal(1099511627776L * 256, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 0 }, 1));
Assert.Equal(1099511627776L * 256 * 256, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 1 }, 1));
Assert.Equal(-1L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 255, 255, 255, 255, 255, 255, 255, 255 }, 1));
Assert.Equal(257L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 1, 1, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(4294967295L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 255, 255, 255, 255, 0, 0, 0, 0 }, 1));
Assert.Equal(-4294967296L, EndianBitConverter.LittleEndianConverter.ToInt64(new byte[] { 0, 0, 0, 0, 0, 255, 255, 255, 255 }, 1));
}
/// <summary>
/// Tests that passing a <see cref="ulong"/> returns the correct bytes.
/// </summary>
[Fact]
public void ToUInt64()
{
Assert.Equal(0UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(1UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(256UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(65536UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(16777216UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, 0));
Assert.Equal(4294967296UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, 0));
Assert.Equal(1099511627776UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, 0));
Assert.Equal(1099511627776UL * 256, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, 0));
Assert.Equal(1099511627776UL * 256 * 256, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, 0));
Assert.Equal(ulong.MaxValue, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, 0));
Assert.Equal(257UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, 0));
Assert.Equal(0UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(1UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(256UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 1, 0, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(65536UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 1, 0, 0, 0, 0, 0 }, 1));
Assert.Equal(16777216UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 1, 0, 0, 0, 0 }, 1));
Assert.Equal(4294967296UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 1, 0, 0, 0 }, 1));
Assert.Equal(1099511627776UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 1, 0, 0 }, 1));
Assert.Equal(1099511627776UL * 256, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 1, 0 }, 1));
Assert.Equal(1099511627776UL * 256 * 256, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0, 1 }, 1));
Assert.Equal(ulong.MaxValue, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 255, 255, 255, 255, 255, 255, 255, 255 }, 1));
Assert.Equal(257UL, EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[] { 0, 1, 1, 0, 0, 0, 0, 0, 0 }, 1));
}
}
}

15
tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs

@ -26,21 +26,6 @@ namespace SixLabors.ImageSharp.Tests.Memory
Assert.True(Unsafe.AreSame(ref a, ref bb), "References are not same!"); Assert.True(Unsafe.AreSame(ref a, ref bb), "References are not same!");
} }
} }
[Fact]
public void FetchVector()
{
float[] stuff = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
var span = new Span<float>(stuff);
ref Vector<float> v = ref span.FetchVector();
Assert.Equal(0, v[0]);
Assert.Equal(1, v[1]);
Assert.Equal(2, v[2]);
Assert.Equal(3, v[3]);
}
public class SpanHelper_Copy public class SpanHelper_Copy
{ {

2
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffCompositorTests.cs

@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
using (Image<Rgba32> src = srcFile.CreateImage()) using (Image<Rgba32> src = srcFile.CreateImage())
using (Image<Rgba32> dest = provider.GetImage()) using (Image<Rgba32> dest = provider.GetImage())
{ {
using (Image<Rgba32> res = dest.Clone(x => x.Blend(new GraphicsOptions { BlenderMode = mode }, src))) using (Image<Rgba32> res = dest.Clone(x => x.DrawImage(new GraphicsOptions { BlenderMode = mode }, src)))
{ {
res.DebugSave(provider, mode.ToString()); res.DebugSave(provider, mode.ToString());
res.CompareToReferenceOutput(provider, mode.ToString()); res.CompareToReferenceOutput(provider, mode.ToString());

Loading…
Cancel
Save