diff --git a/README.md b/README.md index 86ce5ddd4..6d37dd5e7 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,13 @@ -# ImageSharp +# ImageSharp ImageSharp -**ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. +**ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. -> **ImageSharp is still in early stages (alpha) but progress has been pretty quick. As such, please do not use on production environments until the library reaches release candidate status. Pre-release downloads are available from the [MyGet package repository](https://www.myget.org/gallery/imagesharp).** +Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and embedded/IoT scenarios. + +> **ImageSharp** has made excellent progress and contains many great features but is still considered by us to be still in early stages (alpha). As such, we cannot support its use on production environments until the library reaches release candidate status. +> +> Pre-release downloads are available from the [MyGet package repository](https://www.myget.org/gallery/imagesharp). [![GitHub license](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/APACHE-2.0-LICENSE.txt) [![GitHub issues](https://img.shields.io/github/issues/JimBobSquarePants/ImageSharp.svg)](https://github.com/JimBobSquarePants/ImageSharp/issues) @@ -11,6 +15,9 @@ [![GitHub forks](https://img.shields.io/github/forks/JimBobSquarePants/ImageSharp.svg)](https://github.com/JimBobSquarePants/ImageSharp/network) [![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/https/github.com/JimBobSquarePants/ImageSharp.svg?style=social)](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%2fJimBobSquarePants%2fImageSharp&via=james_m_south) +[![OpenCollective](https://opencollective.com/imagesharp/backers/badge.svg)](#backers) +[![OpenCollective](https://opencollective.com/imagesharp/sponsors/badge.svg)](#sponsors) + | |Build Status|Code Coverage| @@ -66,7 +73,9 @@ There's plenty there and more coming. Check out the [current features](features. ### API -Without the constraints of `System.Drawing` We have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks. Images and processors are thread safe usable in parallel processing utilizing all the availables cores. +Without the constraints of `System.Drawing` We have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. + +Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments. Many `Image` methods are also fluent. @@ -126,3 +135,73 @@ Core Team - [Anton Firsov](https://github.com/antonfirsov) - [Olivia Ifrim](https://github.com/olivif) - [Scott Williams](https://github.com/tocsoft) + +### Backers + +Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/imagesharp#backer)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +### Sponsors + +Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/imagesharp#sponsor)] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/icons/imagesharp-logo-128.png b/build/icons/imagesharp-logo-128.png index 6d05c222c..3fd4963dd 100644 Binary files a/build/icons/imagesharp-logo-128.png and b/build/icons/imagesharp-logo-128.png differ diff --git a/build/icons/imagesharp-logo-256.png b/build/icons/imagesharp-logo-256.png index fc59b03e1..d40880a63 100644 Binary files a/build/icons/imagesharp-logo-256.png and b/build/icons/imagesharp-logo-256.png differ diff --git a/build/icons/imagesharp-logo-32.png b/build/icons/imagesharp-logo-32.png index 0fd4411ce..8fcae249d 100644 Binary files a/build/icons/imagesharp-logo-32.png and b/build/icons/imagesharp-logo-32.png differ diff --git a/build/icons/imagesharp-logo-512.png b/build/icons/imagesharp-logo-512.png index 5d5fb854e..fcde03ec4 100644 Binary files a/build/icons/imagesharp-logo-512.png and b/build/icons/imagesharp-logo-512.png differ diff --git a/build/icons/imagesharp-logo-64.png b/build/icons/imagesharp-logo-64.png index 4e97906e5..b43538a6f 100644 Binary files a/build/icons/imagesharp-logo-64.png and b/build/icons/imagesharp-logo-64.png differ diff --git a/build/icons/imagesharp-logo-heading.png b/build/icons/imagesharp-logo-heading.png index b10d367bf..35a945930 100644 Binary files a/build/icons/imagesharp-logo-heading.png and b/build/icons/imagesharp-logo-heading.png differ diff --git a/build/icons/imagesharp-logo.png b/build/icons/imagesharp-logo.png index ed1c36c5e..fcde03ec4 100644 Binary files a/build/icons/imagesharp-logo.png and b/build/icons/imagesharp-logo.png differ diff --git a/build/icons/imagesharp-logo.svg b/build/icons/imagesharp-logo.svg index 2df3cc80c..cd4dfa117 100644 --- a/build/icons/imagesharp-logo.svg +++ b/build/icons/imagesharp-logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs index 718705b39..ace929bd6 100644 --- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs +++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs @@ -80,7 +80,7 @@ namespace ImageSharp.Drawing.Brushes this.source = image.Lock(); this.xLength = image.Width; this.yLength = image.Height; - this.offset = new Vector2((float)Math.Max(Math.Floor(region.Top), 0), (float)Math.Max(Math.Floor(region.Left), 0)); + this.offset = new Vector2(MathF.Max(MathF.Floor(region.Top), 0), MathF.Max(MathF.Floor(region.Left), 0)); } /// diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 351764bb9..259ae4b0f 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -40,7 +40,7 @@ All - + ..\..\ImageSharp.ruleset diff --git a/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs b/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs index 2fa5fe43f..1b5df7574 100644 --- a/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs +++ b/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs @@ -19,10 +19,10 @@ namespace ImageSharp.Drawing /// A representation of this public static Rectangle Convert(this SixLabors.Shapes.Rectangle source) { - int left = (int)Math.Floor(source.Left); - int right = (int)Math.Ceiling(source.Right); - int top = (int)Math.Floor(source.Top); - int bottom = (int)Math.Ceiling(source.Bottom); + int left = (int)MathF.Floor(source.Left); + int right = (int)MathF.Ceiling(source.Right); + int top = (int)MathF.Floor(source.Top); + int bottom = (int)MathF.Ceiling(source.Bottom); return new Rectangle(left, top, right - left, bottom - top); } } diff --git a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs index ffcc5ee75..e3716124e 100644 --- a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs +++ b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs @@ -241,7 +241,7 @@ namespace ImageSharp.Drawing.Pens float distanceFromStart = length - start; float distanceFromEnd = end - length; - float closestEdge = Math.Min(distanceFromStart, distanceFromEnd); + float closestEdge = MathF.Min(distanceFromStart, distanceFromEnd); float distanceAcross = closestEdge; diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 9a616d408..80a3e6793 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -128,8 +128,8 @@ namespace ImageSharp.Drawing.Processors // points will be paired up float scanStart = buffer[point] - minX; float scanEnd = buffer[point + 1] - minX; - int startX = (int)Math.Floor(scanStart); - int endX = (int)Math.Floor(scanEnd); + int startX = (int)MathF.Floor(scanStart); + int endX = (int)MathF.Floor(scanEnd); if (startX >= 0 && startX < scanline.Length) { diff --git a/src/ImageSharp/Colors/ColorspaceTransforms.cs b/src/ImageSharp/Colors/ColorspaceTransforms.cs index cda702270..74f5cb717 100644 --- a/src/ImageSharp/Colors/ColorspaceTransforms.cs +++ b/src/ImageSharp/Colors/ColorspaceTransforms.cs @@ -105,12 +105,12 @@ namespace ImageSharp float s = color.S; float v = color.V; - if (Math.Abs(s) < Constants.Epsilon) + if (MathF.Abs(s) < Constants.Epsilon) { return new Color(v, v, v, 1); } - float h = (Math.Abs(color.H - 360) < Constants.Epsilon) ? 0 : color.H / 60; + float h = (MathF.Abs(color.H - 360) < Constants.Epsilon) ? 0 : color.H / 60; int i = (int)Math.Truncate(h); float f = h - i; @@ -178,9 +178,9 @@ namespace ImageSharp float s = color.S; float l = color.L; - if (Math.Abs(l) > Constants.Epsilon) + if (MathF.Abs(l) > Constants.Epsilon) { - if (Math.Abs(s) < Constants.Epsilon) + if (MathF.Abs(s) < Constants.Epsilon) { r = g = b = l; } diff --git a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs index 77d943478..2975d4ad9 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs @@ -110,9 +110,9 @@ namespace ImageSharp public void ToXyzBytes(byte[] bytes, int startIndex) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); } /// @@ -120,10 +120,10 @@ namespace ImageSharp public void ToXyzwBytes(byte[] bytes, int startIndex) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// @@ -131,9 +131,9 @@ namespace ImageSharp public void ToZyxBytes(byte[] bytes, int startIndex) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -141,10 +141,10 @@ namespace ImageSharp public void ToZyxwBytes(byte[] bytes, int startIndex) { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs index b34c1e88b..46c24be6f 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs @@ -127,8 +127,8 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); bytes[startIndex + 2] = 0; } @@ -143,8 +143,8 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); bytes[startIndex + 2] = 0; bytes[startIndex + 3] = 255; } @@ -161,8 +161,8 @@ namespace ImageSharp vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -177,8 +177,8 @@ namespace ImageSharp vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); bytes[startIndex + 3] = 255; } @@ -237,8 +237,8 @@ namespace ImageSharp // Clamp the value between min and max values // Round rather than truncate. - uint word2 = (uint)((int)(float)Math.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); - uint word1 = (uint)(((int)(float)Math.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); + uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); + uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); return word2 | word1; } diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs index f33ac25a6..74229a914 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs @@ -135,9 +135,9 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); } /// @@ -151,10 +151,10 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// @@ -168,9 +168,9 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -184,10 +184,10 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// @@ -231,10 +231,10 @@ namespace ImageSharp const float MinNeg = -MaxPos; // Clamp the value between min and max values - ulong word4 = ((ulong)(float)Math.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; - ulong word3 = ((ulong)(float)Math.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; - ulong word2 = ((ulong)(float)Math.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; - ulong word1 = ((ulong)(float)Math.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; + ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; + ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; + ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; + ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; return word4 | word3 | word2 | word1; } diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs index 56f304070..65a5e7a5f 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs @@ -109,9 +109,9 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); } /// @@ -120,10 +120,10 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// @@ -132,9 +132,9 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -143,10 +143,10 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs index 816401d4e..becc4d072 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs @@ -108,9 +108,9 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); } /// @@ -119,10 +119,10 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// @@ -131,9 +131,9 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -142,10 +142,10 @@ namespace ImageSharp { Vector4 vector = this.ToVector4() * 255F; - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/Colors/PackedPixel/Short2.cs b/src/ImageSharp/Colors/PackedPixel/Short2.cs index 802df7c1d..167a1e786 100644 --- a/src/ImageSharp/Colors/PackedPixel/Short2.cs +++ b/src/ImageSharp/Colors/PackedPixel/Short2.cs @@ -125,8 +125,8 @@ namespace ImageSharp vector += Round; vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); bytes[startIndex + 2] = 0; } @@ -141,8 +141,8 @@ namespace ImageSharp vector += Round; vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); bytes[startIndex + 2] = 0; bytes[startIndex + 3] = 255; } @@ -159,8 +159,8 @@ namespace ImageSharp vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -175,8 +175,8 @@ namespace ImageSharp vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); bytes[startIndex] = 0; - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); bytes[startIndex + 3] = 255; } diff --git a/src/ImageSharp/Colors/PackedPixel/Short4.cs b/src/ImageSharp/Colors/PackedPixel/Short4.cs index 2517ef7a8..e1a559c32 100644 --- a/src/ImageSharp/Colors/PackedPixel/Short4.cs +++ b/src/ImageSharp/Colors/PackedPixel/Short4.cs @@ -131,9 +131,9 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); } /// @@ -147,10 +147,10 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.X); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// @@ -164,9 +164,9 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); } /// @@ -180,10 +180,10 @@ namespace ImageSharp vector += Round; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); - bytes[startIndex] = (byte)(float)Math.Round(vector.Z); - bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); - bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); - bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); + bytes[startIndex] = (byte)MathF.Round(vector.Z); + bytes[startIndex + 1] = (byte)MathF.Round(vector.Y); + bytes[startIndex + 2] = (byte)MathF.Round(vector.X); + bytes[startIndex + 3] = (byte)MathF.Round(vector.W); } /// diff --git a/src/ImageSharp/Colors/Spaces/CieLab.cs b/src/ImageSharp/Colors/Spaces/CieLab.cs index ecc1bca5a..921158174 100644 --- a/src/ImageSharp/Colors/Spaces/CieLab.cs +++ b/src/ImageSharp/Colors/Spaces/CieLab.cs @@ -95,11 +95,11 @@ namespace ImageSharp.Colors.Spaces // y /= 1F; z /= 1.08883F; - x = x > 0.008856F ? (float)Math.Pow(x, 0.3333333F) : ((903.3F * x) + 16F) / 116F; - y = y > 0.008856F ? (float)Math.Pow(y, 0.3333333F) : ((903.3F * y) + 16F) / 116F; - z = z > 0.008856F ? (float)Math.Pow(z, 0.3333333F) : ((903.3F * z) + 16F) / 116F; + x = x > 0.008856F ? MathF.Pow(x, 0.3333333F) : ((903.3F * x) + 16F) / 116F; + y = y > 0.008856F ? MathF.Pow(y, 0.3333333F) : ((903.3F * y) + 16F) / 116F; + z = z > 0.008856F ? MathF.Pow(z, 0.3333333F) : ((903.3F * z) + 16F) / 116F; - float l = Math.Max(0, (116F * y) - 16F); + float l = MathF.Max(0, (116F * y) - 16F); float a = 500F * (x - y); float b = 200F * (y - z); diff --git a/src/ImageSharp/Colors/Spaces/Cmyk.cs b/src/ImageSharp/Colors/Spaces/Cmyk.cs index 53618312c..c81a55c0b 100644 --- a/src/ImageSharp/Colors/Spaces/Cmyk.cs +++ b/src/ImageSharp/Colors/Spaces/Cmyk.cs @@ -93,9 +93,9 @@ namespace ImageSharp.Colors.Spaces float m = 1f - (color.G / 255F); float y = 1f - (color.B / 255F); - float k = Math.Min(c, Math.Min(m, y)); + float k = MathF.Min(c, MathF.Min(m, y)); - if (Math.Abs(k - 1.0f) <= Constants.Epsilon) + if (MathF.Abs(k - 1.0f) <= Constants.Epsilon) { return new Cmyk(0, 0, 0, 1); } diff --git a/src/ImageSharp/Colors/Spaces/Hsl.cs b/src/ImageSharp/Colors/Spaces/Hsl.cs index 66f4a52bc..1d655ec32 100644 --- a/src/ImageSharp/Colors/Spaces/Hsl.cs +++ b/src/ImageSharp/Colors/Spaces/Hsl.cs @@ -83,27 +83,27 @@ namespace ImageSharp.Colors.Spaces float g = color.G / 255F; float b = color.B / 255F; - float max = Math.Max(r, Math.Max(g, b)); - float min = Math.Min(r, Math.Min(g, b)); + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); float chroma = max - min; float h = 0; float s = 0; float l = (max + min) / 2; - if (Math.Abs(chroma) < Constants.Epsilon) + if (MathF.Abs(chroma) < Constants.Epsilon) { return new Hsl(0, s, l); } - if (Math.Abs(r - max) < Constants.Epsilon) + if (MathF.Abs(r - max) < Constants.Epsilon) { h = (g - b) / chroma; } - else if (Math.Abs(g - max) < Constants.Epsilon) + else if (MathF.Abs(g - max) < Constants.Epsilon) { h = 2 + ((b - r) / chroma); } - else if (Math.Abs(b - max) < Constants.Epsilon) + else if (MathF.Abs(b - max) < Constants.Epsilon) { h = 4 + ((r - g) / chroma); } diff --git a/src/ImageSharp/Colors/Spaces/Hsv.cs b/src/ImageSharp/Colors/Spaces/Hsv.cs index b34977e2d..e171c9528 100644 --- a/src/ImageSharp/Colors/Spaces/Hsv.cs +++ b/src/ImageSharp/Colors/Spaces/Hsv.cs @@ -83,27 +83,27 @@ namespace ImageSharp.Colors.Spaces float g = color.G / 255F; float b = color.B / 255F; - float max = Math.Max(r, Math.Max(g, b)); - float min = Math.Min(r, Math.Min(g, b)); + float max = MathF.Max(r, MathF.Max(g, b)); + float min = MathF.Min(r, MathF.Min(g, b)); float chroma = max - min; float h = 0; float s = 0; float v = max; - if (Math.Abs(chroma) < Constants.Epsilon) + if (MathF.Abs(chroma) < Constants.Epsilon) { return new Hsv(0, s, v); } - if (Math.Abs(r - max) < Constants.Epsilon) + if (MathF.Abs(r - max) < Constants.Epsilon) { h = (g - b) / chroma; } - else if (Math.Abs(g - max) < Constants.Epsilon) + else if (MathF.Abs(g - max) < Constants.Epsilon) { h = 2 + ((b - r) / chroma); } - else if (Math.Abs(b - max) < Constants.Epsilon) + else if (MathF.Abs(b - max) < Constants.Epsilon) { h = 4 + ((r - g) / chroma); } diff --git a/src/ImageSharp/Colors/Vector4BlendTransforms.cs b/src/ImageSharp/Colors/Vector4BlendTransforms.cs index 2fa6aad4b..a7e2e0e91 100644 --- a/src/ImageSharp/Colors/Vector4BlendTransforms.cs +++ b/src/ImageSharp/Colors/Vector4BlendTransforms.cs @@ -5,7 +5,6 @@ namespace ImageSharp { - using System; using System.Numerics; /// @@ -198,13 +197,13 @@ namespace ImageSharp amount = amount.Clamp(0, 1); // Santize on zero alpha - if (Math.Abs(backdrop.W) < Constants.Epsilon) + if (MathF.Abs(backdrop.W) < Constants.Epsilon) { source.W *= amount; return source; } - if (Math.Abs(source.W) < Constants.Epsilon) + if (MathF.Abs(source.W) < Constants.Epsilon) { return backdrop; } @@ -248,7 +247,7 @@ namespace ImageSharp /// private static float BlendSoftLight(float b, float s) { - return s <= .5F ? ((2F * b * s) + (b * b * (1F - (2F * s)))) : (float)((Math.Sqrt(b) * ((2F * s) - 1F)) + (2F * b * (1F - s))); + return s <= .5F ? ((2F * b * s) + (b * b * (1F - (2F * s)))) : (MathF.Sqrt(b) * ((2F * s) - 1F)) + (2F * b * (1F - s)); } /// @@ -261,7 +260,7 @@ namespace ImageSharp /// private static float BlendDodge(float b, float s) { - return Math.Abs(s - 1F) < Constants.Epsilon ? s : Math.Min(b / (1F - s), 1F); + return MathF.Abs(s - 1F) < Constants.Epsilon ? s : MathF.Min(b / (1F - s), 1F); } /// @@ -274,7 +273,7 @@ namespace ImageSharp /// private static float BlendBurn(float b, float s) { - return Math.Abs(s) < Constants.Epsilon ? s : Math.Max(1F - ((1F - b) / s), 0F); + return MathF.Abs(s) < Constants.Epsilon ? s : MathF.Max(1F - ((1F - b) / s), 0F); } /// diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs index 23fce0173..9f3aa405e 100644 --- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs +++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs @@ -57,7 +57,7 @@ namespace ImageSharp return signal * 12.92F; } - return (1.055F * (float)Math.Pow(signal, 0.41666666F)) - 0.055F; + return (1.055F * MathF.Pow(signal, 0.41666666F)) - 0.055F; } /// @@ -77,7 +77,7 @@ namespace ImageSharp return signal / 12.92F; } - return (float)Math.Pow((signal + 0.055F) / 1.055F, 2.4F); + return MathF.Pow((signal + 0.055F) / 1.055F, 2.4F); } } } diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index b59cf54f5..224b267e4 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -53,13 +53,13 @@ namespace ImageSharp public static float Gaussian(float x, float sigma) { const float Numerator = 1.0f; - float denominator = (float)(Math.Sqrt(2 * Math.PI) * sigma); + float denominator = MathF.Sqrt(2 * MathF.PI) * sigma; float exponentNumerator = -x * x; float exponentDenominator = (float)(2 * Math.Pow(sigma, 2)); float left = Numerator / denominator; - float right = (float)Math.Exp(exponentNumerator / exponentDenominator); + float right = MathF.Exp(exponentNumerator / exponentDenominator); return left * right; } @@ -110,10 +110,10 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float SinC(float x) { - if (Math.Abs(x) > Constants.Epsilon) + if (MathF.Abs(x) > Constants.Epsilon) { - x *= (float)Math.PI; - return Clean((float)Math.Sin(x) / x); + x *= MathF.PI; + return Clean(MathF.Sin(x) / x); } return 1.0f; @@ -129,7 +129,7 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DegreesToRadians(float degrees) { - return degrees * (float)(Math.PI / 180); + return degrees * (MathF.PI / 180); } /// @@ -196,19 +196,19 @@ namespace ImageSharp switch (channel) { case RgbaComponent.R: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon; + delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon; break; case RgbaComponent.G: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon; + delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon; break; case RgbaComponent.B: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon; + delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon; break; default: - delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon; + delegateFunc = (pixels, x, y, b) => MathF.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon; break; } @@ -297,7 +297,7 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float Clean(float x) { - if (Math.Abs(x) < Constants.Epsilon) + if (MathF.Abs(x) < Constants.Epsilon) { return 0F; } diff --git a/src/ImageSharp/Common/Helpers/MathF.cs b/src/ImageSharp/Common/Helpers/MathF.cs new file mode 100644 index 000000000..2ee700789 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/MathF.cs @@ -0,0 +1,144 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Runtime.CompilerServices; + + /// + /// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions. + /// + // ReSharper disable InconsistentNaming + internal static class MathF + { + /// + /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π. + /// + public const float PI = (float)Math.PI; + + /// Returns the absolute value of a single-precision floating-point number. + /// A number that is greater than or equal to , but less than or equal to . + /// A single-precision floating-point number, x, such that 0 ≤ x ≤. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Abs(float f) + { + return Math.Abs(f); + } + + /// Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number. + /// A single-precision floating-point number. + /// The smallest integral value that is greater than or equal to . + /// If is equal to , , + /// or , that value is returned. + /// Note that this method returns a instead of an integral type. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Ceiling(float f) + { + return (float)Math.Ceiling(f); + } + + /// Returns e raised to the specified power. + /// A number specifying a power. + /// + /// The number e raised to the power . + /// If equals or , that value is returned. + /// If equals , 0 is returned. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Exp(float f) + { + return (float)Math.Exp(f); + } + + /// Returns the largest integer less than or equal to the specified single-precision floating-point number. + /// A single-precision floating-point number. + /// The largest integer less than or equal to . + /// If is equal to , , + /// or , that value is returned. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Floor(float f) + { + return (float)Math.Floor(f); + } + + /// Returns the larger of two single-precision floating-point numbers. + /// The first of two single-precision floating-point numbers to compare. + /// The second of two single-precision floating-point numbers to compare. + /// Parameter or , whichever is larger. + /// If , or , or both and are + /// equal to , is returned. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Max(float val1, float val2) + { + return Math.Max(val1, val2); + } + + /// Returns the smaller of two single-precision floating-point numbers. + /// The first of two single-precision floating-point numbers to compare. + /// The second of two single-precision floating-point numbers to compare. + /// Parameter or , whichever is smaller. + /// If , , or both and are equal + /// to , is returned. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Min(float val1, float val2) + { + return Math.Min(val1, val2); + } + + /// Returns a specified number raised to the specified power. + /// A single-precision floating-point number to be raised to a power. + /// A single-precision floating-point number that specifies a power. + /// The number raised to the power . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Pow(float x, float y) + { + return (float)Math.Pow(x, y); + } + + /// Rounds a single-precision floating-point value to the nearest integral value. + /// A single-precision floating-point number to be rounded. + /// + /// The integer nearest . + /// If the fractional component of is halfway between two integers, one of which is even and the other odd, then the even number is returned. + /// Note that this method returns a instead of an integral type. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Round(float f) + { + return (float)Math.Round(f); + } + + /// Returns the sine of the specified angle. + /// An angle, measured in radians. + /// + /// The sine of . + /// If is equal to , , + /// or , this method returns . + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Sin(float f) + { + return (float)Math.Sin(f); + } + + /// Returns the square root of a specified number. + /// The number whose square root is to be found. + /// + /// One of the values in the following table. + /// parameter Return value Zero or positive The positive square root of . + /// Negative Equals + /// Equals + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Sqrt(float f) + { + return (float)Math.Sqrt(f); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d6529940e..5ce9b5eb0 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -579,7 +579,7 @@ namespace ImageSharp.Formats // channel and we should try to read it. for (int x = 0; x < this.header.Width; x++) { - int index = newScanline[x]; + int index = newScanline[x + 1]; int pixelOffset = index * 3; byte a = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; @@ -603,7 +603,7 @@ namespace ImageSharp.Formats { for (int x = 0; x < this.header.Width; x++) { - int index = newScanline[x]; + int index = newScanline[x + 1]; int pixelOffset = index * 3; byte r = this.palette[pixelOffset]; @@ -982,4 +982,4 @@ namespace ImageSharp.Formats } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7950d260c..552673179 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -516,9 +516,14 @@ namespace ImageSharp.Formats colorTable[offset + 1] = bytes[1]; colorTable[offset + 2] = bytes[2]; - if (alpha <= this.options.Threshold) + if (alpha < 255 && alpha <= this.options.Threshold) { - transparentPixels.Add((byte)offset); + // Ensure the index is actually being used in our array. + // I'd like to find a faster way of doing this. + if (quantized.Pixels.Contains((byte)i)) + { + transparentPixels.Add((byte)i); + } } } @@ -544,12 +549,11 @@ namespace ImageSharp.Formats /// /// The pixel format. /// The containing image data. - /// The image base. - private void WritePhysicalChunk(Stream stream, ImageBase imageBase) + /// The image. + private void WritePhysicalChunk(Stream stream, Image image) where TColor : struct, IPixel { - Image image = imageBase as Image; - if (image != null && image.MetaData.HorizontalResolution > 0 && image.MetaData.VerticalResolution > 0) + if (image.MetaData.HorizontalResolution > 0 && image.MetaData.VerticalResolution > 0) { // 39.3700787 = inches in a meter. int dpmX = (int)Math.Round(image.MetaData.HorizontalResolution * 39.3700787D); diff --git a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs index e32e808c1..ec3b8ebe7 100644 --- a/src/ImageSharp/Formats/Png/PngInterlaceMode.cs +++ b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs @@ -13,11 +13,11 @@ namespace ImageSharp.Formats /// /// Non interlaced /// - None, + None = 0, /// /// Adam 7 interlacing. /// - Adam7 + Adam7 = 1 } } \ No newline at end of file diff --git a/src/ImageSharp/IO/BigEndianBitConverter.cs b/src/ImageSharp/IO/BigEndianBitConverter.cs index 084102728..debe1706c 100644 --- a/src/ImageSharp/IO/BigEndianBitConverter.cs +++ b/src/ImageSharp/IO/BigEndianBitConverter.cs @@ -6,43 +6,81 @@ namespace ImageSharp.IO { /// - /// Implementation of EndianBitConverter which converts to/from big-endian - /// byte arrays. - /// - /// Adapted from Miscellaneous Utility Library - /// This product includes software developed by Jon Skeet and Marc Gravell. Contact , or see - /// . - /// + /// Implementation of EndianBitConverter which converts to/from big-endian byte arrays. /// internal sealed class BigEndianBitConverter : EndianBitConverter { /// - public override Endianness Endianness => Endianness.BigEndian; + public override Endianness Endianness + { + get { return Endianness.BigEndian; } + } /// - public override bool IsLittleEndian() => false; + public override bool IsLittleEndian + { + get { return false; } + } /// - protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index) + public override void CopyBytes(short value, byte[] buffer, int index) { - int endOffset = index + bytes - 1; - for (int i = 0; i < bytes; i++) - { - buffer[endOffset - i] = unchecked((byte)(value & 0xff)); - value = value >> 8; - } + CheckByteArgument(buffer, index, 2); + + buffer[index] = (byte)(value >> 8); + buffer[index + 1] = (byte)value; + } + + /// + 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; + } + + /// + 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; + } + + /// + public override short ToInt16(byte[] value, int startIndex) + { + CheckByteArgument(value, startIndex, 2); + + return (short)((value[startIndex] << 8) | value[startIndex + 1]); + } + + /// + 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]; } /// - protected internal override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert) + public override long ToInt64(byte[] value, int startIndex) { - long ret = 0; - for (int i = 0; i < bytesToConvert; i++) - { - ret = unchecked((ret << 8) | buffer[startIndex + i]); - } + CheckByteArgument(value, startIndex, 8); - return ret; + 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 | (p1 << 32); } } } \ No newline at end of file diff --git a/src/ImageSharp/IO/EndianBinaryReader.cs b/src/ImageSharp/IO/EndianBinaryReader.cs index d12d0b976..e21d3d3db 100644 --- a/src/ImageSharp/IO/EndianBinaryReader.cs +++ b/src/ImageSharp/IO/EndianBinaryReader.cs @@ -68,7 +68,7 @@ namespace ImageSharp.IO { 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.BitConverter = EndianBitConverter.GetConverter(endianness); @@ -510,7 +510,7 @@ namespace ImageSharp.IO { if (this.disposed) { - throw new ObjectDisposedException("EndianBinaryReader"); + throw new ObjectDisposedException(nameof(EndianBinaryReader)); } } diff --git a/src/ImageSharp/IO/EndianBinaryWriter.cs b/src/ImageSharp/IO/EndianBinaryWriter.cs index 3b2028afd..ef026f00c 100644 --- a/src/ImageSharp/IO/EndianBinaryWriter.cs +++ b/src/ImageSharp/IO/EndianBinaryWriter.cs @@ -52,31 +52,12 @@ namespace ImageSharp.IO /// public EndianBinaryWriter(Endianness endianness, Stream stream, Encoding encoding) { - EndianBitConverter bitConverter = EndianBitConverter.GetConverter(endianness); - - // TODO: Use Guard - if (bitConverter == null) - { - throw new ArgumentNullException("bitConverter"); - } - - if (stream == null) - { - throw new ArgumentNullException("stream"); - } - - if (encoding == null) - { - throw new ArgumentNullException("encoding"); - } - - if (!stream.CanWrite) - { - throw new ArgumentException("Stream isn't writable", "stream"); - } + Guard.NotNull(stream, nameof(stream)); + Guard.NotNull(stream, nameof(encoding)); + Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable"); this.BaseStream = stream; - this.BitConverter = bitConverter; + this.BitConverter = EndianBitConverter.GetConverter(endianness); this.Encoding = encoding; } @@ -256,13 +237,10 @@ namespace ImageSharp.IO /// Writes an array of bytes to the stream. /// /// The values to write + /// value is null public void Write(byte[] value) { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - + Guard.NotNull(value, nameof(value)); this.WriteInternal(value, value.Length); } @@ -272,6 +250,7 @@ namespace ImageSharp.IO /// An array containing the bytes to write /// The index of the first byte to write within the array /// The number of bytes to write + /// value is null public void Write(byte[] value, int offset, int count) { this.CheckDisposed(); @@ -292,12 +271,10 @@ namespace ImageSharp.IO /// Writes an array of characters to the stream, using the encoding for this writer. /// /// An array containing the characters to write + /// value is null public void Write(char[] value) { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } + Guard.NotNull(value, nameof(value)); this.CheckDisposed(); byte[] data = this.Encoding.GetBytes(value, 0, value.Length); @@ -305,16 +282,13 @@ namespace ImageSharp.IO } /// - /// Writes a string to the stream, using the encoding for this writer. + /// Writes a length-prefixed string to the stream, using the encoding for this writer. /// /// The value to write. Must not be null. - /// value is null + /// value is null public void Write(string value) { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } + Guard.NotNull(value, nameof(value)); this.CheckDisposed(); byte[] data = this.Encoding.GetBytes(value); @@ -368,7 +342,7 @@ namespace ImageSharp.IO { if (this.disposed) { - throw new ObjectDisposedException("EndianBinaryWriter"); + throw new ObjectDisposedException(nameof(EndianBinaryWriter)); } } diff --git a/src/ImageSharp/IO/EndianBitConverter.Conversion.cs b/src/ImageSharp/IO/EndianBitConverter.Conversion.cs new file mode 100644 index 000000000..0858acfed --- /dev/null +++ b/src/ImageSharp/IO/EndianBitConverter.Conversion.cs @@ -0,0 +1,63 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.IO +{ + using System; + + /// + /// Equivalent of , but with either endianness. + /// + internal abstract partial class EndianBitConverter + { + /// + /// 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. + /// + /// The number to convert. + /// A 64-bit signed integer whose value is equivalent to value. + public unsafe long DoubleToInt64Bits(double value) + { + return *((long*)&value); + } + + /// + /// 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. + /// + /// The number to convert. + /// A double-precision floating point number whose value is equivalent to value. + public unsafe double Int64BitsToDouble(long value) + { + return *((double*)&value); + } + + /// + /// 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. + /// + /// The number to convert. + /// A 32-bit signed integer whose value is equivalent to value. + public unsafe int SingleToInt32Bits(float value) + { + return *((int*)&value); + } + + /// + /// 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. + /// + /// The number to convert. + /// A single-precision floating point number whose value is equivalent to value. + public unsafe float Int32BitsToSingle(int value) + { + return *((float*)&value); + } + } +} diff --git a/src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs b/src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs new file mode 100644 index 000000000..b46a453a4 --- /dev/null +++ b/src/ImageSharp/IO/EndianBitConverter.CopyBytes.cs @@ -0,0 +1,145 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.IO +{ + using System; + + /// + /// Equivalent of , but with either endianness. + /// + internal abstract partial class EndianBitConverter + { + /// + /// Copies the specified 16-bit signed integer value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public abstract void CopyBytes(short value, byte[] buffer, int index); + + /// + /// Copies the specified 32-bit signed integer value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public abstract void CopyBytes(int value, byte[] buffer, int index); + + /// + /// Copies the specified 64-bit signed integer value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public abstract void CopyBytes(long value, byte[] buffer, int index); + + /// + /// Copies the specified 16-bit unsigned integer value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public void CopyBytes(ushort value, byte[] buffer, int index) + { + this.CopyBytes(unchecked((short)value), buffer, index); + } + + /// + /// Copies the specified 32-bit unsigned integer value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public void CopyBytes(uint value, byte[] buffer, int index) + { + this.CopyBytes(unchecked((int)value), buffer, index); + } + + /// + /// Copies the specified 64-bit unsigned integer value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public void CopyBytes(ulong value, byte[] buffer, int index) + { + this.CopyBytes(unchecked((long)value), buffer, index); + } + + /// + /// Copies the specified Boolean value into the specified byte array, + /// beginning at the specified index. + /// + /// A Boolean value. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public void CopyBytes(bool value, byte[] buffer, int index) + { + CheckByteArgument(buffer, index, 1); + buffer[index] = value ? (byte)1 : (byte)0; + } + + /// + /// Copies the specified Unicode character value into the specified byte array, + /// beginning at the specified index. + /// + /// A character to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public void CopyBytes(char value, byte[] buffer, int index) + { + this.CopyBytes(unchecked((short)value), buffer, index); + } + + /// + /// Copies the specified double-precision floating point value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public unsafe void CopyBytes(double value, byte[] buffer, int index) + { + this.CopyBytes(*((long*)&value), buffer, index); + } + + /// + /// Copies the specified single-precision floating point value into the specified byte array, + /// beginning at the specified index. + /// + /// The number to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + public unsafe void CopyBytes(float value, byte[] buffer, int index) + { + this.CopyBytes(*((int*)&value), buffer, index); + } + + /// + /// Copies the specified decimal value into the specified byte array, + /// beginning at the specified index. + /// + /// A character to convert. + /// The byte array to copy the bytes into + /// The first index into the array to copy the bytes into + 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); + } + } +} diff --git a/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs b/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs new file mode 100644 index 000000000..b3e0133e4 --- /dev/null +++ b/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs @@ -0,0 +1,139 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.IO +{ + using System; + + /// + /// Equivalent of , but with either endianness. + /// + internal abstract partial class EndianBitConverter + { + /// + /// Returns the specified 16-bit signed integer value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 2. + public byte[] GetBytes(short value) + { + byte[] result = new byte[2]; + this.CopyBytes(value, result, 0); + return result; + } + + /// + /// Returns the specified 32-bit signed integer value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 4. + public byte[] GetBytes(int value) + { + byte[] result = new byte[4]; + this.CopyBytes(value, result, 0); + return result; + } + + /// + /// Returns the specified 64-bit signed integer value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 8. + public byte[] GetBytes(long value) + { + byte[] result = new byte[8]; + this.CopyBytes(value, result, 0); + return result; + } + + /// + /// Returns the specified 16-bit unsigned integer value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 2. + public byte[] GetBytes(ushort value) + { + return this.GetBytes(unchecked((short)value)); + } + + /// + /// Returns the specified 32-bit unsigned integer value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 4. + public byte[] GetBytes(uint value) + { + return this.GetBytes(unchecked((int)value)); + } + + /// + /// Returns the specified 64-bit unsigned integer value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 8. + public byte[] GetBytes(ulong value) + { + return this.GetBytes(unchecked((long)value)); + } + + /// + /// Returns the specified Boolean value as an array of bytes. + /// + /// A Boolean value. + /// An array of bytes with length 1. + /// + /// The . + /// + public byte[] GetBytes(bool value) + { + return new byte[1] { value ? (byte)1 : (byte)0 }; + } + + /// + /// Returns the specified Unicode character value as an array of bytes. + /// + /// A character to convert. + /// An array of bytes with length 2. + /// + /// The . + /// + public byte[] GetBytes(char value) + { + return this.GetBytes((short)value); + } + + /// + /// Returns the specified double-precision floating point value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 8. + public unsafe byte[] GetBytes(double value) + { + return this.GetBytes(*((long*)&value)); + } + + /// + /// Returns the specified single-precision floating point value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 4. + public unsafe byte[] GetBytes(float value) + { + return this.GetBytes(*((int*)&value)); + } + + /// + /// Returns the specified decimal value as an array of bytes. + /// + /// The number to convert. + /// An array of bytes with length 16. + public byte[] GetBytes(decimal value) + { + byte[] result = new byte[16]; + this.CopyBytes(value, result, 0); + return result; + } + } +} diff --git a/src/ImageSharp/IO/EndianBitConverter.ToType.cs b/src/ImageSharp/IO/EndianBitConverter.ToType.cs new file mode 100644 index 000000000..93b49558a --- /dev/null +++ b/src/ImageSharp/IO/EndianBitConverter.ToType.cs @@ -0,0 +1,141 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.IO +{ + using System; + + /// + /// Equivalent of , but with either endianness. + /// + internal abstract partial class EndianBitConverter + { + /// + /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A 16-bit signed integer formed by two bytes beginning at startIndex. + public abstract short ToInt16(byte[] value, int startIndex); + + /// + /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A 32-bit signed integer formed by four bytes beginning at startIndex. + public abstract int ToInt32(byte[] value, int startIndex); + + /// + /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A 64-bit signed integer formed by eight bytes beginning at startIndex. + public abstract long ToInt64(byte[] value, int startIndex); + + /// + /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A 16-bit unsigned integer formed by two bytes beginning at startIndex. + public ushort ToUInt16(byte[] value, int startIndex) + { + return unchecked((ushort)this.ToInt16(value, startIndex)); + } + + /// + /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A 32-bit unsigned integer formed by four bytes beginning at startIndex. + public uint ToUInt32(byte[] value, int startIndex) + { + return unchecked((uint)this.ToInt32(value, startIndex)); + } + + /// + /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A 64-bit unsigned integer formed by eight bytes beginning at startIndex. + public ulong ToUInt64(byte[] value, int startIndex) + { + return unchecked((ulong)this.ToInt64(value, startIndex)); + } + + /// + /// Returns a Boolean value converted from one byte at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// true if the byte at startIndex in value is nonzero; otherwise, false. + public bool ToBoolean(byte[] value, int startIndex) + { + CheckByteArgument(value, startIndex, 1); + return value[startIndex] != 0; + } + + /// + /// Returns a Unicode character converted from two bytes at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A character formed by two bytes beginning at startIndex. + public char ToChar(byte[] value, int startIndex) + { + return unchecked((char)this.ToInt16(value, startIndex)); + } + + /// + /// Returns a double-precision floating point number converted from eight bytes + /// at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A double precision floating point number formed by eight bytes beginning at startIndex. + public unsafe double ToDouble(byte[] value, int startIndex) + { + long intValue = this.ToInt64(value, startIndex); + return *((double*)&intValue); + } + + /// + /// Returns a single-precision floating point number converted from four bytes + /// at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A single precision floating point number formed by four bytes beginning at startIndex. + public unsafe float ToSingle(byte[] value, int startIndex) + { + int intValue = this.ToInt32(value, startIndex); + return *((float*)&intValue); + } + + /// + /// Returns a decimal value converted from sixteen bytes + /// at a specified position in a byte array. + /// + /// An array of bytes. + /// The starting position within value. + /// A decimal formed by sixteen bytes beginning at startIndex. + 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; + } + } +} diff --git a/src/ImageSharp/IO/EndianBitConverter.cs b/src/ImageSharp/IO/EndianBitConverter.cs index 812823e7a..06b88dbc9 100644 --- a/src/ImageSharp/IO/EndianBitConverter.cs +++ b/src/ImageSharp/IO/EndianBitConverter.cs @@ -6,291 +6,56 @@ namespace ImageSharp.IO { using System; - using System.Diagnostics.CodeAnalysis; - using System.Runtime.InteropServices; + using System.Runtime.CompilerServices; /// - /// Equivalent of , but with either endianness. - /// - /// Adapted from Miscellaneous Utility Library - /// This product includes software developed by Jon Skeet and Marc Gravell. Contact , or see - /// . - /// + /// Equivalent of , but with either endianness. /// - [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1201:ElementsMustAppearInTheCorrectOrder", Justification = "Reviewed. Suppression is OK here. Better readability.")] - [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1202:ElementsMustBeOrderedByAccess", Justification = "Reviewed. Suppression is OK here. Better readability.")] - [SuppressMessage("StyleCop.CSharp.OrderingRules", "SA1204:StaticElementsMustAppearBeforeInstanceElements", Justification = "Reviewed. Suppression is OK here. Better readability.")] - [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1124:DoNotUseRegions", Justification = "Reviewed. Suppression is OK here. Better readability.")] - internal abstract class EndianBitConverter + internal abstract partial class EndianBitConverter { - #region Endianness of this converter - /// - /// Indicates the byte order ("endianness") in which data is converted using this class. + /// The little-endian bit converter. /// - /// - /// 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. - /// - /// true if this converter is little-endian, false otherwise. - public abstract bool IsLittleEndian(); + public static readonly LittleEndianBitConverter LittleEndianConverter = new LittleEndianBitConverter(); /// - /// Gets the byte order ("endianness") in which data is converted using this class. + /// The big-endian bit converter. /// - public abstract Endianness Endianness { get; } - #endregion - - #region Factory properties + public static readonly BigEndianBitConverter BigEndianConverter = new BigEndianBitConverter(); /// - /// The little-endian bit converter. + /// Gets the byte order ("endianness") in which data is converted using this class. /// - private static readonly LittleEndianBitConverter LittleConverter = new LittleEndianBitConverter(); + public abstract Endianness Endianness { get; } /// - /// The big-endian bit converter. + /// Gets a value indicating whether the byte order ("endianness") in which data is converted is little endian. /// - private static readonly BigEndianBitConverter BigConverter = new BigEndianBitConverter(); + /// + /// 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. + /// + public abstract bool IsLittleEndian { get; } /// /// Gets the converter. /// /// The endianness. /// an - /// Not a valid form of Endianness - endianness - internal static EndianBitConverter GetConverter(Endianness endianness) + /// Not a valid form of Endianness - endianness + public static EndianBitConverter GetConverter(Endianness endianness) { switch (endianness) { case Endianness.LittleEndian: - return LittleConverter; + return LittleEndianConverter; case Endianness.BigEndian: - return BigConverter; + return BigEndianConverter; default: throw new ArgumentException("Not a valid form of Endianness", nameof(endianness)); } } - #endregion - - #region Double/primitive conversions - - /// - /// 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. - /// - /// The number to convert. - /// A 64-bit signed integer whose value is equivalent to value. - public long DoubleToInt64Bits(double value) - { - return BitConverter.DoubleToInt64Bits(value); - } - - /// - /// 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. - /// - /// The number to convert. - /// A double-precision floating point number whose value is equivalent to value. - public double Int64BitsToDouble(long value) - { - return BitConverter.Int64BitsToDouble(value); - } - - /// - /// 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. - /// - /// The number to convert. - /// A 32-bit signed integer whose value is equivalent to value. - public int SingleToInt32Bits(float value) - { - return new Int32SingleUnion(value).AsInt32; - } - - /// - /// 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. - /// - /// The number to convert. - /// A single-precision floating point number whose value is equivalent to value. - public float Int32BitsToSingle(int value) - { - return new Int32SingleUnion(value).AsSingle; - } - #endregion - - #region To(PrimitiveType) conversions - - /// - /// Returns a Boolean value converted from one byte at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// true if the byte at startIndex in value is nonzero; otherwise, false. - public bool ToBoolean(byte[] value, int startIndex) - { - CheckByteArgument(value, startIndex, 1); - return BitConverter.ToBoolean(value, startIndex); - } - - /// - /// Returns a Unicode character converted from two bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A character formed by two bytes beginning at startIndex. - public char ToChar(byte[] value, int startIndex) - { - return unchecked((char)this.CheckedFromBytes(value, startIndex, 2)); - } - - /// - /// Returns a double-precision floating point number converted from eight bytes - /// at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A double precision floating point number formed by eight bytes beginning at startIndex. - public double ToDouble(byte[] value, int startIndex) - { - return this.Int64BitsToDouble(this.ToInt64(value, startIndex)); - } - - /// - /// Returns a single-precision floating point number converted from four bytes - /// at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A single precision floating point number formed by four bytes beginning at startIndex. - public float ToSingle(byte[] value, int startIndex) - { - return this.Int32BitsToSingle(this.ToInt32(value, startIndex)); - } - - /// - /// Returns a 16-bit signed integer converted from two bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A 16-bit signed integer formed by two bytes beginning at startIndex. - public short ToInt16(byte[] value, int startIndex) - { - return unchecked((short)this.CheckedFromBytes(value, startIndex, 2)); - } - - /// - /// Returns a 32-bit signed integer converted from four bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A 32-bit signed integer formed by four bytes beginning at startIndex. - public int ToInt32(byte[] value, int startIndex) - { - return unchecked((int)this.CheckedFromBytes(value, startIndex, 4)); - } - - /// - /// Returns a 64-bit signed integer converted from eight bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A 64-bit signed integer formed by eight bytes beginning at startIndex. - public long ToInt64(byte[] value, int startIndex) - { - return this.CheckedFromBytes(value, startIndex, 8); - } - - /// - /// Returns a 16-bit unsigned integer converted from two bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A 16-bit unsigned integer formed by two bytes beginning at startIndex. - public ushort ToUInt16(byte[] value, int startIndex) - { - return unchecked((ushort)this.CheckedFromBytes(value, startIndex, 2)); - } - - /// - /// Returns a 32-bit unsigned integer converted from four bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A 32-bit unsigned integer formed by four bytes beginning at startIndex. - public uint ToUInt32(byte[] value, int startIndex) - { - return unchecked((uint)this.CheckedFromBytes(value, startIndex, 4)); - } - - /// - /// Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A 64-bit unsigned integer formed by eight bytes beginning at startIndex. - public ulong ToUInt64(byte[] value, int startIndex) - { - return unchecked((ulong)this.CheckedFromBytes(value, startIndex, 8)); - } - - /// - /// Convert the given number of bytes from the given array, from the given start - /// position, into a long, using the bytes as the least significant part of the long. - /// By the time this is called, the arguments have been checked for validity. - /// - /// The bytes to convert - /// The index of the first byte to convert - /// The number of bytes to use in the conversion - /// The converted number - protected internal abstract long FromBytes(byte[] value, int startIndex, int bytesToConvert); - - /// - /// Checks the given argument for validity. - /// - /// The byte array passed in - /// The start index passed in - /// The number of bytes required - /// value is a null reference - /// - /// startIndex is less than zero or greater than the length of value minus bytesRequired. - /// - [SuppressMessage("ReSharper", "UnusedParameter.Local", Justification = "Keeps code DRY")] - private 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)); - } - } - - /// - /// Checks the arguments for validity before calling FromBytes - /// (which can therefore assume the arguments are valid). - /// - /// The bytes to convert after checking - /// The index of the first byte to convert - /// The number of bytes to convert - /// The - private long CheckedFromBytes(byte[] value, int startIndex, int bytesToConvert) - { - CheckByteArgument(value, startIndex, bytesToConvert); - return this.FromBytes(value, startIndex, bytesToConvert); - } - #endregion - - #region ToString conversions /// /// Returns a String converted from the elements of a byte array. @@ -336,406 +101,29 @@ namespace ImageSharp.IO { return BitConverter.ToString(value, startIndex, length); } - #endregion - - #region Decimal conversions /// - /// Returns a decimal value converted from sixteen bytes - /// at a specified position in a byte array. - /// - /// An array of bytes. - /// The starting position within value. - /// A decimal formed by sixteen bytes beginning at startIndex. - public decimal ToDecimal(byte[] value, int startIndex) - { - // HACK: This always assumes four parts, each in their own endianness, - // starting with the first part at the start of the byte array. - // On the other hand, there's no real format specified... - int[] parts = new int[4]; - for (int i = 0; i < 4; i++) - { - parts[i] = this.ToInt32(value, startIndex + (i * 4)); - } - - return new decimal(parts); - } - - /// - /// Returns the specified decimal value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 16. - public byte[] GetBytes(decimal value) - { - byte[] bytes = new byte[16]; - int[] parts = decimal.GetBits(value); - for (int i = 0; i < 4; i++) - { - this.CopyBytesImpl(parts[i], 4, bytes, i * 4); - } - - return bytes; - } - - /// - /// Copies the specified decimal value into the specified byte array, - /// beginning at the specified index. - /// - /// A character to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(decimal value, byte[] buffer, int index) - { - int[] parts = decimal.GetBits(value); - for (int i = 0; i < 4; i++) - { - this.CopyBytesImpl(parts[i], 4, buffer, (i * 4) + index); - } - } - #endregion - - #region GetBytes conversions - - /// - /// Returns an array with the given number of bytes formed - /// from the least significant bytes of the specified value. - /// This is used to implement the other GetBytes methods. - /// - /// The value to get bytes for - /// The number of significant bytes to return - /// - /// The . - /// - private byte[] GetBytes(long value, int bytes) - { - byte[] buffer = new byte[bytes]; - this.CopyBytes(value, bytes, buffer, 0); - return buffer; - } - - /// - /// Returns the specified Boolean value as an array of bytes. - /// - /// A Boolean value. - /// An array of bytes with length 1. - /// - /// The . - /// - public byte[] GetBytes(bool value) - { - return BitConverter.GetBytes(value); - } - - /// - /// Returns the specified Unicode character value as an array of bytes. - /// - /// A character to convert. - /// An array of bytes with length 2. - /// - /// The . - /// - public byte[] GetBytes(char value) - { - return this.GetBytes(value, 2); - } - - /// - /// Returns the specified double-precision floating point value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 8. - public byte[] GetBytes(double value) - { - return this.GetBytes(this.DoubleToInt64Bits(value), 8); - } - - /// - /// Returns the specified 16-bit signed integer value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 2. - public byte[] GetBytes(short value) - { - return this.GetBytes(value, 2); - } - - /// - /// Returns the specified 32-bit signed integer value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 4. - public byte[] GetBytes(int value) - { - return this.GetBytes(value, 4); - } - - /// - /// Returns the specified 64-bit signed integer value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 8. - public byte[] GetBytes(long value) - { - return this.GetBytes(value, 8); - } - - /// - /// Returns the specified single-precision floating point value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 4. - public byte[] GetBytes(float value) - { - return this.GetBytes(this.SingleToInt32Bits(value), 4); - } - - /// - /// Returns the specified 16-bit unsigned integer value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 2. - public byte[] GetBytes(ushort value) - { - return this.GetBytes(value, 2); - } - - /// - /// Returns the specified 32-bit unsigned integer value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 4. - public byte[] GetBytes(uint value) - { - return this.GetBytes(value, 4); - } - - /// - /// Returns the specified 64-bit unsigned integer value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 8. - public byte[] GetBytes(ulong value) - { - return this.GetBytes(unchecked((long)value), 8); - } - - #endregion - - #region CopyBytes conversions - - /// - /// Copies the given number of bytes from the least-specific - /// end of the specified value into the specified byte array, beginning - /// at the specified index. - /// This is used to implement the other CopyBytes methods. - /// - /// The value to copy bytes for - /// The number of significant bytes to copy - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - private void CopyBytes(long value, int bytes, byte[] buffer, int index) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer), "Byte array must not be null"); - } - - if (buffer.Length < index + bytes) - { - throw new ArgumentOutOfRangeException(nameof(buffer), "Buffer not big enough for value"); - } - - this.CopyBytesImpl(value, bytes, buffer, index); - } - - /// - /// Copies the given number of bytes from the least-specific - /// end of the specified value into the specified byte array, beginning - /// at the specified index. - /// This must be implemented in concrete derived classes, but the implementation - /// may assume that the value will fit into the buffer. - /// - /// The value to copy bytes for - /// The number of significant bytes to copy - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - protected internal abstract void CopyBytesImpl(long value, int bytes, byte[] buffer, int index); - - /// - /// Copies the specified Boolean value into the specified byte array, - /// beginning at the specified index. - /// - /// A Boolean value. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(bool value, byte[] buffer, int index) - { - this.CopyBytes(value ? 1 : 0, 1, buffer, index); - } - - /// - /// Copies the specified Unicode character value into the specified byte array, - /// beginning at the specified index. - /// - /// A character to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(char value, byte[] buffer, int index) - { - this.CopyBytes(value, 2, buffer, index); - } - - /// - /// Copies the specified double-precision floating point value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(double value, byte[] buffer, int index) - { - this.CopyBytes(this.DoubleToInt64Bits(value), 8, buffer, index); - } - - /// - /// Copies the specified 16-bit signed integer value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(short value, byte[] buffer, int index) - { - this.CopyBytes(value, 2, buffer, index); - } - - /// - /// Copies the specified 32-bit signed integer value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(int value, byte[] buffer, int index) - { - this.CopyBytes(value, 4, buffer, index); - } - - /// - /// Copies the specified 64-bit signed integer value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(long value, byte[] buffer, int index) - { - this.CopyBytes(value, 8, buffer, index); - } - - /// - /// Copies the specified single-precision floating point value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(float value, byte[] buffer, int index) - { - this.CopyBytes(this.SingleToInt32Bits(value), 4, buffer, index); - } - - /// - /// Copies the specified 16-bit unsigned integer value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(ushort value, byte[] buffer, int index) - { - this.CopyBytes(value, 2, buffer, index); - } - - /// - /// Copies the specified 32-bit unsigned integer value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(uint value, byte[] buffer, int index) - { - this.CopyBytes(value, 4, buffer, index); - } - - /// - /// Copies the specified 64-bit unsigned integer value into the specified byte array, - /// beginning at the specified index. - /// - /// The number to convert. - /// The byte array to copy the bytes into - /// The first index into the array to copy the bytes into - public void CopyBytes(ulong value, byte[] buffer, int index) - { - this.CopyBytes(unchecked((long)value), 8, buffer, index); - } - - #endregion - - #region Private struct used for Single/Int32 conversions - - /// - /// Union used solely for the equivalent of DoubleToInt64Bits and vice versa. + /// Checks the given argument for validity. /// - [StructLayout(LayoutKind.Explicit)] - private struct Int32SingleUnion + /// The byte array passed in + /// The start index passed in + /// The number of bytes required + /// value is a null reference + /// + /// startIndex is less than zero or greater than the length of value minus bytesRequired. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected static void CheckByteArgument(byte[] value, int startIndex, int bytesRequired) { - /// - /// Int32 version of the value. - /// - [FieldOffset(0)] - private readonly int i; - - /// - /// Single version of the value. - /// - [FieldOffset(0)] - private readonly float f; - - /// - /// Initializes a new instance of the struct. - /// - /// The integer value of the new instance. - internal Int32SingleUnion(int i) + if (value == null) { - this.f = 0; // Just to keep the compiler happy - this.i = i; + throw new ArgumentNullException(nameof(value)); } - /// - /// Initializes a new instance of the struct. - /// - /// - /// The floating point value of the new instance. - /// - internal Int32SingleUnion(float f) + if (startIndex < 0 || startIndex > value.Length - bytesRequired) { - this.i = 0; // Just to keep the compiler happy - this.f = f; + throw new ArgumentOutOfRangeException(nameof(startIndex)); } - - /// - /// Gets the value of the instance as an integer. - /// - internal int AsInt32 => this.i; - - /// - /// Gets the value of the instance as a floating point number. - /// - internal float AsSingle => this.f; } - #endregion } -} \ No newline at end of file +} diff --git a/src/ImageSharp/IO/LittleEndianBitConverter.cs b/src/ImageSharp/IO/LittleEndianBitConverter.cs index 63ebe18a3..81ed8d55c 100644 --- a/src/ImageSharp/IO/LittleEndianBitConverter.cs +++ b/src/ImageSharp/IO/LittleEndianBitConverter.cs @@ -6,42 +6,78 @@ namespace ImageSharp.IO { /// - /// Implementation of EndianBitConverter which converts to/from little-endian - /// byte arrays. - /// - /// Adapted from Miscellaneous Utility Library - /// This product includes software developed by Jon Skeet and Marc Gravell. Contact , or see - /// . - /// + /// Implementation of EndianBitConverter which converts to/from little-endian byte arrays. /// internal sealed class LittleEndianBitConverter : EndianBitConverter { /// - public override Endianness Endianness => Endianness.LittleEndian; + public override Endianness Endianness + { + get { return Endianness.LittleEndian; } + } + + /// + public override bool IsLittleEndian + { + get { return true; } + } + + /// + public override void CopyBytes(short value, byte[] buffer, int index) + { + CheckByteArgument(buffer, index, 2); + + buffer[index + 1] = (byte)(value >> 8); + buffer[index] = (byte)value; + } /// - public override bool IsLittleEndian() => true; + 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; + } /// - protected internal override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index) + public override void CopyBytes(long value, byte[] buffer, int index) { - for (int i = 0; i < bytes; i++) - { - buffer[i + index] = unchecked((byte)(value & 0xff)); - value = value >> 8; - } + 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; } /// - protected internal override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert) + public unsafe override short ToInt16(byte[] value, int startIndex) { - long ret = 0; - for (int i = 0; i < bytesToConvert; i++) - { - ret = unchecked((ret << 8) | buffer[startIndex + bytesToConvert - 1 - i]); - } + CheckByteArgument(value, startIndex, 2); + return (short)((value[startIndex + 1] << 8) | value[startIndex]); + } - return ret; + /// + 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]; + } + + /// + 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 | (p1 << 32); } } } \ No newline at end of file diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 41ac7757e..112b8a109 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -201,7 +201,7 @@ namespace ImageSharp { config = config ?? Configuration.Default; - Image img = WithSeekableStream(stream, s => Decode(stream, options, config)); + Image img = WithSeekableStream(stream, s => Decode(s, options, config)); if (img != null) { @@ -238,7 +238,7 @@ namespace ImageSharp stream.CopyTo(ms); ms.Position = 0; - return action(stream); + return action(ms); } } } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 0b845c491..58f32bdd8 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -319,6 +319,13 @@ namespace ImageSharp uint numberOfComponents = this.GetLong(); + // Issue #132: ExifDataType == Undefined is treated like a byte array. + // If numberOfComponents == 0 this value can only be handled as an inline value and must fallback to 4 (bytes) + if (dataType == ExifDataType.Undefined && numberOfComponents == 0) + { + numberOfComponents = 4; + } + uint size = numberOfComponents * ExifValue.GetSize(dataType); byte[] data = this.GetBytes(4); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 77608e02b..fa06a863e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -108,9 +108,9 @@ namespace ImageSharp.Processing.Processors } } - float red = (float)Math.Sqrt((rX * rX) + (rY * rY)); - float green = (float)Math.Sqrt((gX * gX) + (gY * gY)); - float blue = (float)Math.Sqrt((bX * bX) + (bY * bY)); + float red = MathF.Sqrt((rX * rX) + (rY * rY)); + float green = MathF.Sqrt((gX * gX) + (gY * gY)); + float blue = MathF.Sqrt((bX * bX) + (bY * bY)); TColor packed = default(TColor); packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W)); diff --git a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs index 3568afe41..d928eb1a4 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs @@ -77,7 +77,7 @@ namespace ImageSharp.Processing.Processors color = Vector4BlendTransforms.PremultipliedLerp(backgroundColor, color, .5F); } - if (Math.Abs(a) < Constants.Epsilon) + if (MathF.Abs(a) < Constants.Epsilon) { color = backgroundColor; } diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index c5302bad0..957955c6c 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -139,9 +139,9 @@ namespace ImageSharp.Processing.Processors } } - float red = Math.Abs(redBin[maxIndex] / maxIntensity); - float green = Math.Abs(greenBin[maxIndex] / maxIntensity); - float blue = Math.Abs(blueBin[maxIndex] / maxIntensity); + float red = MathF.Abs(redBin[maxIndex] / maxIntensity); + float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); + float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); TColor packed = default(TColor); packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W)); diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index bb54c1f98..6eeb7398a 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -44,7 +44,7 @@ namespace ImageSharp.Processing.Processors int endX = sourceRectangle.Right; TColor glowColor = this.GlowColor; Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2(); - float maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; + float maxDistance = this.Radius > 0 ? MathF.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; // Align start/end positions. int minX = Math.Max(0, startX); diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 6eda3e42a..40d6d94ac 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -49,9 +49,9 @@ namespace ImageSharp.Processing.Processors int endX = sourceRectangle.Right; TColor vignetteColor = this.VignetteColor; Vector2 centre = Rectangle.Center(sourceRectangle).ToVector2(); - float rX = this.RadiusX > 0 ? Math.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; - float rY = this.RadiusY > 0 ? Math.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F; - float maxDistance = (float)Math.Sqrt((rX * rX) + (rY * rY)); + float rX = this.RadiusX > 0 ? MathF.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F; + float rY = this.RadiusY > 0 ? MathF.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F; + float maxDistance = MathF.Sqrt((rX * rX) + (rY * rY)); // Align start/end positions. int minX = Math.Max(0, startX); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs index 24d898fee..99b143de6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs @@ -168,7 +168,7 @@ namespace ImageSharp.Processing.Processors /// The weights public WeightsWindow GetWeightsWindow(int destIdx, int leftIdx, int rightIdx) { - BufferSpan span = this.dataBuffer.GetRowSpan(destIdx).Slice(leftIdx, rightIdx - leftIdx); + BufferSpan span = this.dataBuffer.GetRowSpan(destIdx).Slice(leftIdx, rightIdx - leftIdx + 1); return new WeightsWindow(leftIdx, span); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs index 255124a75..1374e5815 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs @@ -86,7 +86,7 @@ namespace ImageSharp.Processing.Processors } IResampler sampler = this.Sampler; - float radius = (float)Math.Ceiling(scale * sampler.Radius); + float radius = MathF.Ceiling(scale * sampler.Radius); WeightsBuffer result = new WeightsBuffer(sourceSize, destinationSize); for (int i = 0; i < destinationSize; i++) diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index eb206380c..16e0b6635 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -71,7 +71,7 @@ namespace ImageSharp.Processing.Processors /// protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) { - if (Math.Abs(this.Angle) < Constants.Epsilon || Math.Abs(this.Angle - 90) < Constants.Epsilon || Math.Abs(this.Angle - 180) < Constants.Epsilon || Math.Abs(this.Angle - 270) < Constants.Epsilon) + if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon) { return; } @@ -90,25 +90,25 @@ namespace ImageSharp.Processing.Processors /// The private bool OptimizedApply(ImageBase source) { - if (Math.Abs(this.Angle) < Constants.Epsilon) + if (MathF.Abs(this.Angle) < Constants.Epsilon) { // No need to do anything so return. return true; } - if (Math.Abs(this.Angle - 90) < Constants.Epsilon) + if (MathF.Abs(this.Angle - 90) < Constants.Epsilon) { this.Rotate90(source); return true; } - if (Math.Abs(this.Angle - 180) < Constants.Epsilon) + if (MathF.Abs(this.Angle - 180) < Constants.Epsilon) { this.Rotate180(source); return true; } - if (Math.Abs(this.Angle - 270) < Constants.Epsilon) + if (MathF.Abs(this.Angle - 270) < Constants.Epsilon) { this.Rotate270(source); return true; diff --git a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs index 3dc37e52d..4be938c39 100644 --- a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs @@ -65,7 +65,7 @@ namespace ImageSharp.Processing return new Rectangle(0, 0, source.Width, source.Height); } - double ratio; + float ratio; int sourceWidth = source.Width; int sourceHeight = source.Height; @@ -75,8 +75,8 @@ namespace ImageSharp.Processing int destinationHeight = height; // Fractional variants for preserving aspect ratio. - double percentHeight = Math.Abs(height / (double)sourceHeight); - double percentWidth = Math.Abs(width / (double)sourceWidth); + float percentHeight = MathF.Abs(height / (float)sourceHeight); + float percentWidth = MathF.Abs(width / (float)sourceWidth); if (percentHeight < percentWidth) { @@ -84,7 +84,7 @@ namespace ImageSharp.Processing if (options.CenterCoordinates.Any()) { - double center = -(ratio * sourceHeight) * options.CenterCoordinates.First(); + float center = -(ratio * sourceHeight) * options.CenterCoordinates.First(); destinationY = (int)center + (height / 2); if (destinationY > 0) @@ -117,7 +117,7 @@ namespace ImageSharp.Processing } } - destinationHeight = (int)Math.Ceiling(sourceHeight * percentWidth); + destinationHeight = (int)MathF.Ceiling(sourceHeight * percentWidth); } else { @@ -125,7 +125,7 @@ namespace ImageSharp.Processing if (options.CenterCoordinates.Any()) { - double center = -(ratio * sourceWidth) * options.CenterCoordinates.ToArray()[1]; + float center = -(ratio * sourceWidth) * options.CenterCoordinates.ToArray()[1]; destinationX = (int)center + (width / 2); if (destinationX > 0) @@ -158,7 +158,7 @@ namespace ImageSharp.Processing } } - destinationWidth = (int)Math.Ceiling(sourceWidth * percentHeight); + destinationWidth = (int)MathF.Ceiling(sourceWidth * percentHeight); } return new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight); @@ -184,7 +184,7 @@ namespace ImageSharp.Processing return new Rectangle(0, 0, source.Width, source.Height); } - double ratio; + float ratio; int sourceWidth = source.Width; int sourceHeight = source.Height; @@ -194,8 +194,8 @@ namespace ImageSharp.Processing int destinationHeight = height; // Fractional variants for preserving aspect ratio. - double percentHeight = Math.Abs(height / (double)sourceHeight); - double percentWidth = Math.Abs(width / (double)sourceWidth); + float percentHeight = MathF.Abs(height / (float)sourceHeight); + float percentWidth = MathF.Abs(width / (float)sourceWidth); if (percentHeight < percentWidth) { @@ -269,8 +269,8 @@ namespace ImageSharp.Processing int sourceHeight = source.Height; // Fractional variants for preserving aspect ratio. - double percentHeight = Math.Abs(height / (double)sourceHeight); - double percentWidth = Math.Abs(width / (double)sourceWidth); + float percentHeight = MathF.Abs(height / (float)sourceHeight); + float percentWidth = MathF.Abs(width / (float)sourceWidth); int boxPadHeight = height > 0 ? height : Convert.ToInt32(sourceHeight * percentWidth); int boxPadWidth = width > 0 ? width : Convert.ToInt32(sourceWidth * percentHeight); @@ -350,12 +350,12 @@ namespace ImageSharp.Processing int destinationHeight = height; // Fractional variants for preserving aspect ratio. - double percentHeight = Math.Abs(height / (double)source.Height); - double percentWidth = Math.Abs(width / (double)source.Width); + float percentHeight = MathF.Abs(height / (float)source.Height); + float percentWidth = MathF.Abs(width / (float)source.Width); - // Integers must be cast to doubles to get needed precision - double ratio = (double)options.Size.Height / options.Size.Width; - double sourceRatio = (double)source.Height / source.Width; + // Integers must be cast to floats to get needed precision + float ratio = (float)options.Size.Height / options.Size.Width; + float sourceRatio = (float)source.Height / source.Width; if (sourceRatio < ratio) { @@ -397,7 +397,7 @@ namespace ImageSharp.Processing return new Rectangle(0, 0, source.Width, source.Height); } - double sourceRatio = (double)source.Height / source.Width; + float sourceRatio = (float)source.Height / source.Width; // Find the shortest distance to go. int widthDiff = source.Width - width; diff --git a/src/ImageSharp/Quantizers/Octree/Quantizer.cs b/src/ImageSharp/Quantizers/Octree/Quantizer.cs index 0e6540d42..ccf8da3df 100644 --- a/src/ImageSharp/Quantizers/Octree/Quantizer.cs +++ b/src/ImageSharp/Quantizers/Octree/Quantizer.cs @@ -171,7 +171,7 @@ namespace ImageSharp.Quantizers leastDistance = distance; // And if it's an exact match, exit the loop - if (Math.Abs(distance) < Constants.Epsilon) + if (MathF.Abs(distance) < Constants.Epsilon) { break; } diff --git a/src/ImageSharp/Quantizers/QuantizedImage.cs b/src/ImageSharp/Quantizers/QuantizedImage.cs index 528da7717..471abbae7 100644 --- a/src/ImageSharp/Quantizers/QuantizedImage.cs +++ b/src/ImageSharp/Quantizers/QuantizedImage.cs @@ -6,7 +6,6 @@ namespace ImageSharp.Quantizers { using System; - using System.Threading.Tasks; /// /// Represents a quantized image where the pixels indexed by a color palette. diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs index db9686f3d..03994bc94 100644 --- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs @@ -27,7 +27,7 @@ namespace ImageSharp.Tests.Drawing [InlineData(false, 16, 4)] // we always do 4 sub=pixels when antialising is off. public void MinimumAntialiasSubpixelDepth(bool antialias, int antialiasSubpixelDepth, int expectedAntialiasSubpixelDepth) { - var bounds = new ImageSharp.Rectangle(0, 0, 1, 1); + ImageSharp.Rectangle bounds = new ImageSharp.Rectangle(0, 0, 1, 1); Mock> brush = new Mock>(); Mock region = new Mock(); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 49be75139..51cb0cdc0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -8,47 +8,37 @@ using ImageSharp.Formats; namespace ImageSharp.Tests { using System.IO; + using System.Linq; using System.Threading.Tasks; - + using ImageSharp.IO; using Xunit; public class PngEncoderTests : FileTestBase { - [Fact] - public void ImageCanSaveIndexedPng() + [Theory] + [WithBlankImages(1, 1, PixelTypes.All)] + public void WritesFileMarker(TestImageProvider provider) + where TColor : struct, IPixel { - string path = CreateOutputDirectory("Png", "Indexed"); - - foreach (TestFile file in Files) + using (Image image = provider.GetImage()) + using (MemoryStream ms = new MemoryStream()) { - using (Image image = file.CreateImage()) - { - using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png")) - { - image.MetaData.Quality = 256; - image.Save(output, new PngFormat()); - } - } - } - } + image.Save(ms, new PngEncoder()); + + byte[] data = ms.ToArray().Take(8).ToArray(); + byte[] expected = { + 0x89, // Set the high bit. + 0x50, // P + 0x4E, // N + 0x47, // G + 0x0D, // Line ending CRLF + 0x0A, // Line ending CRLF + 0x1A, // EOF + 0x0A // LF + }; - [Fact] - public void ImageCanSavePngInParallel() - { - string path = this.CreateOutputDirectory("Png"); - - Parallel.ForEach( - Files, - file => - { - using (Image image = file.CreateImage()) - { - using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png")) - { - image.SaveAsPng(output); - } - } - }); + Assert.Equal(expected, data); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs new file mode 100644 index 000000000..882f903d6 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/PngSmokeTests.cs @@ -0,0 +1,83 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests.Formats.Png +{ + using System; + using System.Collections.Generic; + using System.Text; + using System.IO; + using Xunit; + using ImageSharp.Formats; + using System.Linq; + using ImageSharp.IO; + + public class PngSmokeTests + { + [Theory] + [WithTestPatternImages(300, 300, PixelTypes.All)] + public void GeneralTest(TestImageProvider provider) + where TColor : struct, IPixel + { + // does saving a file then repoening mean both files are identical??? + using (Image image = provider.GetImage()) + using (MemoryStream ms = new MemoryStream()) + { + // image.Save(provider.Utility.GetTestOutputFileName("bmp")); + + image.Save(ms, new PngEncoder()); + ms.Position = 0; + using (Image img2 = Image.Load(ms, new PngDecoder())) + { + // img2.Save(provider.Utility.GetTestOutputFileName("bmp", "_loaded"), new BmpEncoder()); + ImageComparer.CheckSimilarity(image, img2); + } + } + } + + [Theory] + [WithTestPatternImages(100, 100, PixelTypes.All)] + public void CanSaveIndexedPng(TestImageProvider provider) + where TColor : struct, IPixel + { + // does saving a file then repoening mean both files are identical??? + using (Image image = provider.GetImage()) + using (MemoryStream ms = new MemoryStream()) + { + // image.Save(provider.Utility.GetTestOutputFileName("bmp")); + image.MetaData.Quality = 256; + image.Save(ms, new PngEncoder()); + ms.Position = 0; + using (Image img2 = Image.Load(ms, new PngDecoder())) + { + // img2.Save(provider.Utility.GetTestOutputFileName("bmp", "_loaded"), new BmpEncoder()); + ImageComparer.CheckSimilarity(image, img2); + } + } + } + + [Theory] + [WithTestPatternImages(300, 300, PixelTypes.All)] + public void Resize(TestImageProvider provider) + where TColor : struct, IPixel + { + // does saving a file then repoening mean both files are identical??? + using (Image image = provider.GetImage()) + using (MemoryStream ms = new MemoryStream()) + { + // image.Save(provider.Utility.GetTestOutputFileName("png")); + image.Resize(100, 100); + // image.Save(provider.Utility.GetTestOutputFileName("png", "resize")); + + image.Save(ms, new PngEncoder()); + ms.Position = 0; + using (Image img2 = Image.Load(ms, new PngDecoder())) + { + ImageComparer.CheckSimilarity(image, img2); + } + } + } + } +} diff --git a/tests/ImageSharp.Tests/Helpers/MathFTests.cs b/tests/ImageSharp.Tests/Helpers/MathFTests.cs new file mode 100644 index 000000000..7f3fb77d0 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/MathFTests.cs @@ -0,0 +1,69 @@ +namespace ImageSharp.Tests.Helpers +{ + using System; + + using Xunit; + + public class MathFTests + { + [Fact] + public void MathF_PI_Is_Equal() + { + Assert.Equal(MathF.PI, (float)Math.PI); + } + + [Fact] + public void MathF_Ceililng_Is_Equal() + { + Assert.Equal(MathF.Ceiling(0.3333F), (float)Math.Ceiling(0.3333F)); + } + + [Fact] + public void MathF_Abs_Is_Equal() + { + Assert.Equal(MathF.Abs(-0.3333F), (float)Math.Abs(-0.3333F)); + } + + [Fact] + public void MathF_Exp_Is_Equal() + { + Assert.Equal(MathF.Exp(1.2345F), (float)Math.Exp(1.2345F)); + } + + [Fact] + public void MathF_Floor_Is_Equal() + { + Assert.Equal(MathF.Floor(1.2345F), (float)Math.Floor(1.2345F)); + } + + [Fact] + public void MathF_Min_Is_Equal() + { + Assert.Equal(MathF.Min(1.2345F, 5.4321F), (float)Math.Min(1.2345F, 5.4321F)); + } + + [Fact] + public void MathF_Max_Is_Equal() + { + Assert.Equal(MathF.Max(1.2345F, 5.4321F), (float)Math.Max(1.2345F, 5.4321F)); + } + + [Fact] + public void MathF_Pow_Is_Equal() + { + Assert.Equal(MathF.Pow(1.2345F, 5.4321F), (float)Math.Pow(1.2345F, 5.4321F)); + } + + [Fact] + public void MathF_Sin_Is_Equal() + { + Assert.Equal(MathF.Sin(1.2345F), (float)Math.Sin(1.2345F)); + } + + [Fact] + public void MathF_Sqrt_Is_Equal() + { + Assert.Equal(MathF.Sqrt(2F), (float)Math.Sqrt(2F)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/IO/BigEndianBitConverter.CopyBytesTests.cs b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.CopyBytesTests.cs new file mode 100644 index 000000000..4cdf9122a --- /dev/null +++ b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.CopyBytesTests.cs @@ -0,0 +1,230 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests.IO +{ + using System; + using ImageSharp.IO; + using Xunit; + + /// + /// The tests. + /// + public class BigEndianBitConverterCopyBytesTests + { + [Fact] + public void CopyToWithNullBufferThrowsException() + { + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(false, null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((short)42, null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((ushort)42, null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42, null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42u, null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42L, null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((ulong)42L, null, 0)); + } + + [Fact] + public void CopyToWithIndexTooBigThrowsException() + { + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(false, new byte[1], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((short)42, new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((ushort)42, new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42, new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42u, new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42L, new byte[8], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((ulong)42L, new byte[8], 1)); + } + + [Fact] + public void CopyToWithBufferTooSmallThrowsException() + { + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(false, new byte[0], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((short)42, new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((ushort)42, new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42, new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42u, new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes(42L, new byte[7], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.CopyBytes((ulong)42L, new byte[7], 0)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests the two byte arrays for equality. + /// + /// The expected bytes. + /// The actual bytes. + private void CheckBytes(byte[] expected, byte[] actual) + { + Assert.Equal(expected.Length, actual.Length); + Assert.Equal(expected, actual); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/IO/BigEndianBitConverterTests.cs b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.GetBytesTests.cs similarity index 54% rename from tests/ImageSharp.Tests/IO/BigEndianBitConverterTests.cs rename to tests/ImageSharp.Tests/IO/BigEndianBitConverter.GetBytesTests.cs index 2030c3dca..06962e010 100644 --- a/tests/ImageSharp.Tests/IO/BigEndianBitConverterTests.cs +++ b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.GetBytesTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -6,25 +6,47 @@ namespace ImageSharp.Tests.IO { using ImageSharp.IO; - using Xunit; /// /// The tests. /// - public class BigEndianBitConverterTests + public class BigEndianBitConverterGetBytesTests { + /// + /// Tests that passing a returns the correct bytes. + /// + [Fact] + public void GetBytesBoolean() + { + this.CheckBytes(new byte[] { 0 }, EndianBitConverter.BigEndianConverter.GetBytes(false)); + this.CheckBytes(new byte[] { 1 }, EndianBitConverter.BigEndianConverter.GetBytes(true)); + } + /// /// Tests that passing a returns the correct bytes. /// [Fact] public void GetBytesShort() { - this.CheckBytes(new byte[] { 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((short)0)); - this.CheckBytes(new byte[] { 0, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((short)1)); - this.CheckBytes(new byte[] { 1, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((short)256)); - this.CheckBytes(new byte[] { 255, 255 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((short)-1)); - this.CheckBytes(new byte[] { 1, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((short)257)); + 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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); } /// @@ -33,13 +55,13 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesInt() { - this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)0)); - this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)1)); - this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)256)); - this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)65536)); - this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)16777216)); - this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)-1)); - this.CheckBytes(new byte[] { 0, 0, 1, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((int)257)); + 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)); } /// @@ -48,13 +70,13 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesUInt() { - this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)0)); - this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)1)); - this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)256)); - this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)65536)); - this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)16777216)); - this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)uint.MaxValue)); - this.CheckBytes(new byte[] { 0, 0, 1, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes((uint)257)); + 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)); } /// @@ -63,17 +85,17 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesLong() { - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(0L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(256L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(65536L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(16777216L)); - this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(4294967296L)); - this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1099511627776L)); - this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1099511627776L * 256)); - this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1099511627776L * 256 * 256)); - this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(-1L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(257L)); + 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)); } /// @@ -82,17 +104,17 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesULong() { - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(0UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(256UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(65536UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(16777216UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(4294967296UL)); - this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1099511627776UL)); - this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1099511627776UL * 256)); - this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(1099511627776UL * 256 * 256)); - this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(ulong.MaxValue)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 1 }, EndianBitConverter.GetConverter(Endianness.BigEndian).GetBytes(257UL)); + 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)); } /// diff --git a/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs new file mode 100644 index 000000000..50a86d3cc --- /dev/null +++ b/tests/ImageSharp.Tests/IO/BigEndianBitConverter.ToTypeTests.cs @@ -0,0 +1,214 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests.IO +{ + using System; + using ImageSharp.IO; + using Xunit; + + /// + /// The tests. + /// + public class BigEndianBitConverterTests + { + [Fact] + public void CopyToWithNullBufferThrowsException() + { + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToBoolean(null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt16(null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt16(null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt32(null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt32(null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt64(null, 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt64(null, 0)); + } + + [Fact] + public void CopyToWithIndexTooBigThrowsException() + { + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToBoolean(new byte[1], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt16(new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt16(new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt32(new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt32(new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt64(new byte[8], 1)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt64(new byte[8], 1)); + } + + [Fact] + public void CopyToWithBufferTooSmallThrowsException() + { + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToBoolean(new byte[0], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt16(new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt16(new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt32(new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt32(new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToInt64(new byte[7], 0)); + Assert.Throws(() => EndianBitConverter.BigEndianConverter.ToUInt64(new byte[7], 0)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [Fact] + public void ToBoolean() + { + Assert.Equal(false, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0 }, 0)); + Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1 }, 0)); + Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 42 }, 0)); + + Assert.Equal(false, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1)); + Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1)); + Assert.Equal(true, EndianBitConverter.BigEndianConverter.ToBoolean(new byte[] { 0, 42 }, 1)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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(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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.CopyBytesTests.cs b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.CopyBytesTests.cs new file mode 100644 index 000000000..5ff47409b --- /dev/null +++ b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.CopyBytesTests.cs @@ -0,0 +1,230 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests.IO +{ + using System; + using ImageSharp.IO; + using Xunit; + + /// + /// The tests. + /// + public class LittleEndianBitConverterCopyBytesTests + { + [Fact] + public void CopyToWithNullBufferThrowsException() + { + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(false, null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((short)42, null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)42, null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42, null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42u, null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42L, null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ulong)42L, null, 0)); + } + + [Fact] + public void CopyToWithIndexTooBigThrowsException() + { + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(false, new byte[1], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((short)42, new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)42, new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42, new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42u, new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42L, new byte[8], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ulong)42L, new byte[8], 1)); + } + + [Fact] + public void CopyToWithBufferTooSmallThrowsException() + { + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(false, new byte[0], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((short)42, new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ushort)42, new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42, new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42u, new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes(42L, new byte[7], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.CopyBytes((ulong)42L, new byte[7], 0)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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); + } + + /// + /// Tests the two byte arrays for equality. + /// + /// The expected bytes. + /// The actual bytes. + private void CheckBytes(byte[] expected, byte[] actual) + { + Assert.Equal(expected.Length, actual.Length); + Assert.Equal(expected, actual); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/IO/LittleEndianBitConverterTests.cs b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.GetBytesTests.cs similarity index 53% rename from tests/ImageSharp.Tests/IO/LittleEndianBitConverterTests.cs rename to tests/ImageSharp.Tests/IO/LittleEndianBitConverter.GetBytesTests.cs index fe7662306..7fd7a97d4 100644 --- a/tests/ImageSharp.Tests/IO/LittleEndianBitConverterTests.cs +++ b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.GetBytesTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -6,25 +6,47 @@ namespace ImageSharp.Tests.IO { using ImageSharp.IO; - using Xunit; /// /// The tests. /// - public class LittleEndianBitConverterTests + public class LittleEndianBitConverterGetBytesTests { + /// + /// Tests that passing a returns the correct bytes. + /// + [Fact] + public void GetBytesBoolean() + { + this.CheckBytes(new byte[] { 0 }, EndianBitConverter.LittleEndianConverter.GetBytes(false)); + this.CheckBytes(new byte[] { 1 }, EndianBitConverter.LittleEndianConverter.GetBytes(true)); + } + /// /// Tests that passing a returns the correct bytes. /// [Fact] public void GetBytesShort() { - this.CheckBytes(new byte[] { 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((short)0)); - this.CheckBytes(new byte[] { 1, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((short)1)); - this.CheckBytes(new byte[] { 0, 1 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((short)256)); - this.CheckBytes(new byte[] { 255, 255 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((short)-1)); - this.CheckBytes(new byte[] { 1, 1 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((short)257)); + 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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); } /// @@ -33,13 +55,13 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesInt() { - this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)0)); - this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)1)); - this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)256)); - this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)65536)); - this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)16777216)); - this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)-1)); - this.CheckBytes(new byte[] { 1, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((int)257)); + 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)); } /// @@ -48,13 +70,13 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesUInt() { - this.CheckBytes(new byte[] { 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)0)); - this.CheckBytes(new byte[] { 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)1)); - this.CheckBytes(new byte[] { 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)256)); - this.CheckBytes(new byte[] { 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)65536)); - this.CheckBytes(new byte[] { 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)16777216)); - this.CheckBytes(new byte[] { 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)uint.MaxValue)); - this.CheckBytes(new byte[] { 1, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes((uint)257)); + 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)); } /// @@ -63,17 +85,17 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesLong() { - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(0L)); - this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1L)); - this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(256L)); - this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(65536L)); - this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(16777216L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(4294967296L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1099511627776L)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1099511627776L * 256)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1099511627776L * 256 * 256)); - this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(-1L)); - this.CheckBytes(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(257L)); + 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)); } /// @@ -82,17 +104,17 @@ namespace ImageSharp.Tests.IO [Fact] public void GetBytesULong() { - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(0UL)); - this.CheckBytes(new byte[] { 1, 0, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1UL)); - this.CheckBytes(new byte[] { 0, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(256UL)); - this.CheckBytes(new byte[] { 0, 0, 1, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(65536UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 1, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(16777216UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 1, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(4294967296UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 1, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1099511627776UL)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 1, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1099511627776UL * 256)); - this.CheckBytes(new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(1099511627776UL * 256 * 256)); - this.CheckBytes(new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(ulong.MaxValue)); - this.CheckBytes(new byte[] { 1, 1, 0, 0, 0, 0, 0, 0 }, EndianBitConverter.GetConverter(Endianness.LittleEndian).GetBytes(257UL)); + 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)); } /// diff --git a/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs new file mode 100644 index 000000000..fa8b2a1a2 --- /dev/null +++ b/tests/ImageSharp.Tests/IO/LittleEndianBitConverter.ToTypeTests.cs @@ -0,0 +1,212 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests.IO +{ + using System; + using ImageSharp.IO; + using Xunit; + + /// + /// The tests. + /// + public class LittleEndianBitConverterToTypeTests + { + [Fact] + public void CopyToWithNullBufferThrowsException() + { + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToBoolean(null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt16(null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt16(null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt32(null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt32(null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt64(null, 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt64(null, 0)); + } + + [Fact] + public void CopyToWithIndexTooBigThrowsException() + { + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[1], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt16(new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[2], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt32(new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[4], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt64(new byte[8], 1)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[8], 1)); + } + + [Fact] + public void CopyToWithBufferTooSmallThrowsException() + { + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[0], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt16(new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt16(new byte[1], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt32(new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt32(new byte[3], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToInt64(new byte[7], 0)); + Assert.Throws(() => EndianBitConverter.LittleEndianConverter.ToUInt64(new byte[7], 0)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [Fact] + public void ToBoolean() + { + Assert.Equal(false, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0 }, 0)); + Assert.Equal(true, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1 }, 0)); + + Assert.Equal(false, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 1, 0 }, 1)); + Assert.Equal(true, EndianBitConverter.LittleEndianConverter.ToBoolean(new byte[] { 0, 1 }, 1)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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(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)); + } + + /// + /// Tests that passing a returns the correct bytes. + /// + [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)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index ddb9414cc..10b0cbb94 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -86,6 +86,20 @@ namespace ImageSharp.Tests } + [Fact] + public void LoadFromNoneSeekableStream() + { + NoneSeekableStream stream = new NoneSeekableStream(this.DataStream); + Image img = Image.Load(stream); + + Assert.NotNull(img); + Assert.Equal(TestFormat.GlobalTestFormat, img.CurrentImageFormat); + + + TestFormat.GlobalTestFormat.VerifyDecodeCall(this.Marker, null, Configuration.Default); + + } + [Fact] public void LoadFromStreamWithType() { diff --git a/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs b/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs new file mode 100644 index 000000000..bc36b60eb --- /dev/null +++ b/tests/ImageSharp.Tests/Image/NoneSeekableStream.cs @@ -0,0 +1,50 @@ +using System; +using System.IO; + +namespace ImageSharp.Tests +{ + internal class NoneSeekableStream : Stream + { + private Stream dataStream; + + public NoneSeekableStream(Stream dataStream) + { + this.dataStream = dataStream; + } + + public override bool CanRead => this.dataStream.CanRead; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override long Length => this.dataStream.Length; + + public override long Position { get => this.dataStream.Position; set => throw new NotImplementedException(); } + + public override void Flush() + { + this.dataStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + return this.dataStream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ImageComparer.cs b/tests/ImageSharp.Tests/ImageComparer.cs new file mode 100644 index 000000000..41b884dd4 --- /dev/null +++ b/tests/ImageSharp.Tests/ImageComparer.cs @@ -0,0 +1,119 @@ +namespace ImageSharp.Tests +{ + using System; + using ImageSharp; + using Xunit; + + /// + /// Class to perform simple image comparisons. + /// + public static class ImageComparer + { + const int DefaultScalingFactor = 32; // this is means the images get scaled into a 32x32 image to sample pixels + const int DefaultSegmentThreshold = 3; // the greyscale difference between 2 segements my be > 3 before it influances the overall difference + const float DefaultImageThreshold = 0.000f; // after segment threasholds the images must have no differences + + /// + /// Does a visual comparison between 2 images and then asserts the difference is less then a configurable threshold + /// + /// The color of the expected image + /// The color type fo the the actual image + /// The expected image + /// The actual image + /// + /// The threshold for the percentage difference where the images are asumed to be the same. + /// The default/undefined value is + /// + /// + /// The threashold of the individual segments before it acumulates towards the overall difference. + /// The default undefined value is + /// + /// + /// This is a sampling factor we sample a grid of average pixels width by high + /// The default undefined value is + /// + public static void CheckSimilarity(Image expected, Image actual, float imageTheshold = DefaultImageThreshold, byte segmentThreshold = DefaultSegmentThreshold, int scalingFactor = DefaultScalingFactor) + where TColorA : struct, IPixel + where TColorB : struct, IPixel + { + float percentage = expected.PercentageDifference(actual, segmentThreshold, scalingFactor); + + Assert.InRange(percentage, 0, imageTheshold); + } + + /// + /// Does a visual comparison between 2 images and then and returns the percentage diffence between the 2 + /// + /// The color of the source image + /// The color type for the target image + /// The source image + /// The target image + /// + /// The threashold of the individual segments before it acumulates towards the overall difference. + /// The default undefined value is + /// + /// + /// This is a sampling factor we sample a grid of average pixels width by high + /// The default undefined value is + /// + /// Returns a number from 0 - 1 which represents the diference focter between the images. + public static float PercentageDifference(this Image source, Image target, byte segmentThreshold = DefaultSegmentThreshold, int scalingFactor = DefaultScalingFactor) + where TColorA : struct, IPixel + where TColorB : struct, IPixel + { + // code adapted from https://www.codeproject.com/Articles/374386/Simple-image-comparison-in-NET + Fast2DArray differences = GetDifferences(source, target, scalingFactor); + + int diffPixels = 0; + + foreach (byte b in differences.Data) + { + if (b > segmentThreshold) { diffPixels++; } + } + + return diffPixels / (scalingFactor * scalingFactor); + } + + private static Fast2DArray GetDifferences(Image source, Image target, int scalingFactor) + where TColorA : struct, IPixel + where TColorB : struct, IPixel + { + Fast2DArray differences = new Fast2DArray(scalingFactor, scalingFactor); + Fast2DArray firstGray = source.GetGrayScaleValues(scalingFactor); + Fast2DArray secondGray = target.GetGrayScaleValues(scalingFactor); + + for (int y = 0; y < scalingFactor; y++) + { + for (int x = 0; x < scalingFactor; x++) + { + differences[x, y] = (byte)Math.Abs(firstGray[x, y] - secondGray[x, y]); + } + } + + return differences; + } + + private static Fast2DArray GetGrayScaleValues(this Image source, int scalingFactor) + where TColorA : struct, IPixel + { + byte[] buffer = new byte[4]; + using (Image img = new Image(source).Resize(scalingFactor, scalingFactor).Grayscale()) + { + using (PixelAccessor pixels = img.Lock()) + { + Fast2DArray grayScale = new Fast2DArray(scalingFactor, scalingFactor); + for (int y = 0; y < scalingFactor; y++) + { + for (int x = 0; x < scalingFactor; x++) + { + pixels[x, y].ToXyzBytes(buffer, 0); + grayScale[x, y] = buffer[1]; + } + } + + return grayScale; + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 1bc31286d..f380724df 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -268,6 +268,24 @@ namespace ImageSharp.Tests } } + [Fact] + public void ExifTypeUndefined() + { + Image image = TestFile.Create(TestImages.Jpeg.Baseline.Bad.ExifUndefType).CreateImage(); + Assert.NotNull(image); + + ExifProfile profile = image.MetaData.ExifProfile; + Assert.NotNull(profile); + + foreach (ExifValue value in profile.Values) + { + if (value.DataType == ExifDataType.Undefined) + { + Assert.Equal(4, value.NumberOfComponents); + } + } + } + private static ExifProfile GetExifProfile() { Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage(); diff --git a/tests/ImageSharp.Tests/Processors/Filters/GrayscaleTest.cs b/tests/ImageSharp.Tests/Processors/Filters/GrayscaleTest.cs index 91f383dd2..97947a787 100644 --- a/tests/ImageSharp.Tests/Processors/Filters/GrayscaleTest.cs +++ b/tests/ImageSharp.Tests/Processors/Filters/GrayscaleTest.cs @@ -9,30 +9,32 @@ namespace ImageSharp.Tests using Xunit; using ImageSharp.Processing; + using ImageSharp.Tests; + using System.Numerics; public class GrayscaleTest : FileTestBase { - public static readonly TheoryData GrayscaleValues - = new TheoryData - { - GrayscaleMode.Bt709 , - GrayscaleMode.Bt601 , - }; - + /// + /// Use test patterns over loaded images to save decode time. + /// [Theory] - [MemberData(nameof(GrayscaleValues))] - public void ImageShouldApplyGrayscaleFilter(GrayscaleMode value) + [WithTestPatternImages(50, 50, PixelTypes.StandardImageClass, GrayscaleMode.Bt709)] + [WithTestPatternImages(50, 50, PixelTypes.StandardImageClass, GrayscaleMode.Bt601)] + public void ImageShouldApplyGrayscaleFilterAll(TestImageProvider provider, GrayscaleMode value) + where TColor : struct, IPixel { - string path = this.CreateOutputDirectory("Grayscale"); - - foreach (TestFile file in Files) + using (Image image = provider.GetImage()) { - string filename = file.GetFileName(value); - using (Image image = file.CreateImage()) - using (FileStream output = File.OpenWrite($"{path}/{filename}")) + image.Grayscale(value); + byte[] data = new byte[3]; + foreach (TColor p in image.Pixels) { - image.Grayscale(value).Save(output); + p.ToXyzBytes(data, 0); + Assert.Equal(data[0], data[1]); + Assert.Equal(data[1], data[2]); } + + image.DebugSave(provider); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index f0a0e8dd8..e9d658887 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -61,6 +61,7 @@ namespace ImageSharp.Tests public static class Bad { public const string MissingEOF = "Jpg/baseline/badeof.jpg"; + public const string ExifUndefType = "Jpg/baseline/ExifUndefType.jpg"; } public const string Cmyk = "Jpg/baseline/cmyk.jpg"; diff --git a/tests/ImageSharp.Tests/TestImages/Formats/Jpg/baseline/ExifUndefType.jpg b/tests/ImageSharp.Tests/TestImages/Formats/Jpg/baseline/ExifUndefType.jpg new file mode 100644 index 000000000..3a7f29c7d Binary files /dev/null and b/tests/ImageSharp.Tests/TestImages/Formats/Jpg/baseline/ExifUndefType.jpg differ diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImageAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImageAttribute.cs new file mode 100644 index 000000000..98bc45f5b --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithTestPatternImageAttribute.cs @@ -0,0 +1,38 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.Reflection; + + /// + /// Triggers passing instances which produce a blank image of size width * height. + /// One instance will be passed for each the pixel format defined by the pixelTypes parameter + /// + public class WithTestPatternImagesAttribute : ImageDataAttributeBase + { + /// + /// Triggers passing an that produces a test pattern image of size width * height + /// + /// The required width + /// The required height + /// The requested parameter + /// Additional theory parameter values + public WithTestPatternImagesAttribute(int width, int height, PixelTypes pixelTypes, params object[] additionalParameters) + : base(pixelTypes, additionalParameters) + { + this.Width = width; + this.Height = height; + } + + public int Width { get; } + public int Height { get; } + + protected override string GetFactoryMethodName(MethodInfo testMethod) => "TestPattern"; + + protected override object[] GetFactoryMethodArgs(MethodInfo testMethod, Type factoryType) => new object[] { this.Width, this.Height }; + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs index ad4d2cc98..6dc0d89c5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BlankProvider.cs @@ -6,25 +6,46 @@ namespace ImageSharp.Tests { using System; + using Xunit.Abstractions; public abstract partial class TestImageProvider where TColor : struct, IPixel { - private class BlankProvider : TestImageProvider + private class BlankProvider : TestImageProvider, IXunitSerializable { public BlankProvider(int width, int height) { this.Width = width; this.Height = height; } + public BlankProvider() + { + this.Width = 100; + this.Height = 100; + } public override string SourceFileOrDescription => $"Blank{this.Width}x{this.Height}"; - protected int Height { get; } + protected int Height { get; private set; } - protected int Width { get; } + protected int Width { get; private set; } public override Image GetImage() => this.Factory.CreateImage(this.Width, this.Height); + + + public override void Deserialize(IXunitSerializationInfo info) + { + this.Width = info.GetValue("width"); + this.Height = info.GetValue("height"); + base.Deserialize(info); + } + + public override void Serialize(IXunitSerializationInfo info) + { + info.AddValue("width", this.Width); + info.AddValue("height", this.Height); + base.Serialize(info); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs index 7975f9b7e..bc18209f3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs @@ -7,11 +7,12 @@ namespace ImageSharp.Tests { using System; using System.Collections.Concurrent; + using Xunit.Abstractions; public abstract partial class TestImageProvider where TColor : struct, IPixel { - private class FileProvider : TestImageProvider + private class FileProvider : TestImageProvider, IXunitSerializable { // Need PixelTypes in the dictionary key, because result images of TestImageProvider.FileProvider // are shared between PixelTypes.Color & PixelTypes.StandardImageClass @@ -33,6 +34,10 @@ namespace ImageSharp.Tests this.filePath = filePath; } + public FileProvider() + { + } + public override string SourceFileOrDescription => this.filePath; public override Image GetImage() @@ -49,6 +54,19 @@ namespace ImageSharp.Tests return this.Factory.CreateImage(cachedImage); } + + public override void Deserialize(IXunitSerializationInfo info) + { + this.filePath = info.GetValue("path"); + + base.Deserialize(info); // must be called last + } + + public override void Serialize(IXunitSerializationInfo info) + { + base.Serialize(info); + info.AddValue("path", this.filePath); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 1593014ae..9a6750872 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Tests { using System; + using Xunit.Abstractions; /// /// Provides instances for parametric unit tests. @@ -14,15 +15,15 @@ namespace ImageSharp.Tests public abstract partial class TestImageProvider where TColor : struct, IPixel { - private class SolidProvider : BlankProvider + private class SolidProvider : BlankProvider { - private readonly byte a; + private byte a; - private readonly byte b; + private byte b; - private readonly byte g; + private byte g; - private readonly byte r; + private byte r; public SolidProvider(int width, int height, byte r, byte g, byte b, byte a) : base(width, height) @@ -33,6 +34,15 @@ namespace ImageSharp.Tests this.a = a; } + public SolidProvider() + : base() + { + this.r = 0; + this.g = 0; + this.b = 0; + this.a = 0; + } + public override string SourceFileOrDescription => $"Solid{this.Width}x{this.Height}_({this.r},{this.g},{this.b},{this.a})"; @@ -44,6 +54,24 @@ namespace ImageSharp.Tests return image.Fill(color); } + + public override void Serialize(IXunitSerializationInfo info) + { + info.AddValue("red", this.r); + info.AddValue("green", this.g); + info.AddValue("blue", this.b); + info.AddValue("alpha", this.a); + base.Serialize(info); + } + + public override void Deserialize(IXunitSerializationInfo info) + { + this.r = info.GetValue("red"); + this.g = info.GetValue("green"); + this.b = info.GetValue("blue"); + this.a = info.GetValue("alpha"); + base.Deserialize(info); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs index cdb31ab69..26192ba1e 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs @@ -7,12 +7,13 @@ namespace ImageSharp.Tests { using System; using System.Reflection; + using Xunit.Abstractions; /// /// Provides instances for parametric unit tests. /// /// The pixel format of the image - public abstract partial class TestImageProvider + public abstract partial class TestImageProvider where TColor : struct, IPixel { public PixelTypes PixelType { get; private set; } = typeof(TColor).GetPixelType(); @@ -25,13 +26,22 @@ namespace ImageSharp.Tests public ImagingTestCaseUtility Utility { get; private set; } public GenericFactory Factory { get; private set; } = new GenericFactory(); + public string TypeName { get; private set; } + public string MethodName { get; private set; } - public static TestImageProvider Blank( + public static TestImageProvider TestPattern( int width, int height, MethodInfo testMethod = null, PixelTypes pixelTypeOverride = PixelTypes.Undefined) - => new BlankProvider(width, height).Init(testMethod, pixelTypeOverride); + => new TestPatternProvider(width, height).Init(testMethod, pixelTypeOverride); + + public static TestImageProvider Blank( + int width, + int height, + MethodInfo testMethod = null, + PixelTypes pixelTypeOverride = PixelTypes.Undefined) + => new BlankProvider(width, height).Init(testMethod, pixelTypeOverride); public static TestImageProvider File( string filePath, @@ -65,12 +75,30 @@ namespace ImageSharp.Tests /// public abstract Image GetImage(); - protected TestImageProvider Init(MethodInfo testMethod, PixelTypes pixelTypeOverride) + public virtual void Deserialize(IXunitSerializationInfo info) + { + PixelTypes pixelType = info.GetValue("PixelType"); + string typeName = info.GetValue("TypeName"); + string methodName = info.GetValue("MethodName"); + + this.Init(typeName, methodName, pixelType); + } + + public virtual void Serialize(IXunitSerializationInfo info) + { + info.AddValue("PixelType", this.PixelType); + info.AddValue("TypeName", this.TypeName); + info.AddValue("MethodName", this.MethodName); + } + + protected TestImageProvider Init(string typeName, string methodName, PixelTypes pixelTypeOverride) { if (pixelTypeOverride != PixelTypes.Undefined) { this.PixelType = pixelTypeOverride; } + this.TypeName = typeName; + this.MethodName = methodName; if (pixelTypeOverride == PixelTypes.StandardImageClass) { @@ -78,19 +106,24 @@ namespace ImageSharp.Tests } this.Utility = new ImagingTestCaseUtility() - { - SourceFileOrDescription = this.SourceFileOrDescription, - PixelTypeName = this.PixelType.ToString() - }; + { + SourceFileOrDescription = this.SourceFileOrDescription, + PixelTypeName = this.PixelType.ToString() + }; - if (testMethod != null) + if (methodName != null) { - this.Utility.Init(testMethod); + this.Utility.Init(typeName, methodName); } return this; } + protected TestImageProvider Init(MethodInfo testMethod, PixelTypes pixelTypeOverride) + { + return Init(testMethod?.DeclaringType.Name, testMethod?.Name, pixelTypeOverride); + } + public override string ToString() { string provName = this.GetType().Name.Replace("Provider", ""); diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs new file mode 100644 index 000000000..39ce61495 --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -0,0 +1,210 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.Collections.Generic; + using System.Numerics; + using Xunit.Abstractions; + + public abstract partial class TestImageProvider + where TColor : struct, IPixel + { + + /// + /// A test image provider that produces test patterns. + /// + /// + private class TestPatternProvider : BlankProvider + { + static Dictionary> testImages = new Dictionary>(); + + public TestPatternProvider(int width, int height) + : base(width, height) + { + } + + public TestPatternProvider() + : base() + { + } + + public override string SourceFileOrDescription => $"TestPattern{this.Width}x{this.Height}"; + + public override Image GetImage() + { + lock (testImages) + { + if (!testImages.ContainsKey(this.SourceFileOrDescription)) + { + Image image = new Image(this.Width, this.Height); + DrawTestPattern(image); + testImages.Add(this.SourceFileOrDescription, image); + } + } + + return new Image(testImages[this.SourceFileOrDescription]); + } + + /// + /// Draws the test pattern on an image by drawing 4 other patterns in the for quadrants of the image. + /// + /// + private static void DrawTestPattern(Image image) + { + // first lets split the image into 4 quadrants + using (PixelAccessor pixels = image.Lock()) + { + BlackWhiteChecker(pixels); // top left + VirticalBars(pixels); // top right + TransparentGradients(pixels); // bottom left + Rainbow(pixels); // bottom right + } + } + /// + /// Fills the top right quadrant with alternating solid vertical bars. + /// + /// + private static void VirticalBars(PixelAccessor pixels) + { + // topLeft + int left = pixels.Width / 2; + int right = pixels.Width; + int top = 0; + int bottom = pixels.Height / 2; + int stride = pixels.Width / 12; + TColor[] c = { + NamedColors.HotPink, + NamedColors.Blue + }; + int p = 0; + for (int y = top; y < bottom; y++) + { + for (int x = left; x < right; x++) + { + if (x % stride == 0) + { + p++; + p = p % c.Length; + } + pixels[x, y] = c[p]; + } + } + } + + /// + /// fills the top left quadrant with a black and white checker board. + /// + /// + private static void BlackWhiteChecker(PixelAccessor pixels) + { + // topLeft + int left = 0; + int right = pixels.Width / 2; + int top = 0; + int bottom = pixels.Height / 2; + int stride = pixels.Width / 6; + TColor[] c = { + NamedColors.Black, + NamedColors.White + }; + + int p = 0; + for (int y = top; y < bottom; y++) + { + if (y % stride == 0) + { + p++; + p = p % c.Length; + } + int pstart = p; + for (int x = left; x < right; x++) + { + if (x % stride == 0) + { + p++; + p = p % c.Length; + } + pixels[x, y] = c[p]; + } + p = pstart; + } + } + + /// + /// Fills the bottom left quadrent with 3 horizental bars in Red, Green and Blue with a alpha gradient from left (transparent) to right (solid). + /// + /// + private static void TransparentGradients(PixelAccessor pixels) + { + // topLeft + int left = 0; + int right = pixels.Width / 2; + int top = pixels.Height / 2; + int bottom = pixels.Height; + int height = (int)Math.Ceiling(pixels.Height / 6f); + + Vector4 red = Color.Red.ToVector4(); // use real color so we can see har it translates in the test pattern + Vector4 green = Color.Green.ToVector4(); // use real color so we can see har it translates in the test pattern + Vector4 blue = Color.Blue.ToVector4(); // use real color so we can see har it translates in the test pattern + + TColor c = default(TColor); + + for (int x = left; x < right; x++) + { + blue.W = red.W = green.W = (float)x / (float)right; + + c.PackFromVector4(red); + int topBand = top; + for (int y = topBand; y < top + height; y++) + { + pixels[x, y] = c; + } + topBand = topBand + height; + c.PackFromVector4(green); + for (int y = topBand; y < topBand + height; y++) + { + pixels[x, y] = c; + } + topBand = topBand + height; + c.PackFromVector4(blue); + for (int y = topBand; y < bottom; y++) + { + pixels[x, y] = c; + } + } + } + + /// + /// Fills the bottom right quadrant with all the colors producable by converting itterating over a uint and unpacking it. + /// A better algorithm could be used but it works + /// + /// + private static void Rainbow(PixelAccessor pixels) + { + int left = pixels.Width / 2; + int right = pixels.Width; + int top = pixels.Height / 2; + int bottom = pixels.Height; + + int pixelCount = left * top; + uint stepsPerPixel = (uint)(uint.MaxValue / pixelCount); + TColor c = default(TColor); + Color t = new Color(0); + + for (int x = left; x < right; x++) + for (int y = top; y < bottom; y++) + { + t.PackedValue += stepsPerPixel; + Vector4 v = t.ToVector4(); + //v.W = (x - left) / (float)left; + c.PackFromVector4(v); + pixels[x, y] = c; + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index bcccd1b44..9fd33d90b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -44,13 +44,26 @@ namespace ImageSharp.Tests /// /// /// The required extension - public string GetTestOutputFileName(string extension = null) + public string GetTestOutputFileName(string extension = null, string tag = null) { string fn = string.Empty; + if (string.IsNullOrWhiteSpace(extension)) + { + extension = null; + } + fn = Path.GetFileNameWithoutExtension(this.SourceFileOrDescription); - extension = extension ?? Path.GetExtension(this.SourceFileOrDescription); - extension = extension ?? ".bmp"; + + if (string.IsNullOrWhiteSpace(extension)) + { + extension = Path.GetExtension(this.SourceFileOrDescription); + } + + if (string.IsNullOrWhiteSpace(extension)) + { + extension = ".bmp"; + } if (extension[0] != '.') { @@ -65,7 +78,14 @@ namespace ImageSharp.Tests pixName = '_' + pixName; } - return $"{this.GetTestOutputDir()}/{this.TestName}{pixName}{fn}{extension}"; + tag = tag ?? string.Empty; + if (tag != string.Empty) + { + tag = '_' + tag; + } + + + return $"{this.GetTestOutputDir()}/{this.TestName}{pixName}{fn}{tag}{extension}"; } /// @@ -80,7 +100,7 @@ namespace ImageSharp.Tests where TColor : struct, IPixel { string path = this.GetTestOutputFileName(extension); - + extension = Path.GetExtension(path); IImageFormat format = GetImageFormatByExtension(extension); encoder = encoder ?? format.Encoder; @@ -91,16 +111,21 @@ namespace ImageSharp.Tests } } + internal void Init(string typeName, string methodName) + { + this.TestGroupName = typeName; + this.TestName = methodName; + } + internal void Init(MethodInfo method) { - this.TestGroupName = method.DeclaringType.Name; - this.TestName = method.Name; + this.Init(method.DeclaringType.Name, method.Name); } private static IImageFormat GetImageFormatByExtension(string extension) { - extension = extension.ToLower(); - return Configuration.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension)); + extension = extension?.TrimStart('.'); + return Configuration.Default.ImageFormats.First(f => f.SupportedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); } private string GetTestOutputDir() diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs new file mode 100644 index 000000000..e2bc2bd2d --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -0,0 +1,20 @@ + +namespace ImageSharp.Tests +{ + using System; + using System.Collections.Generic; + using System.Text; + + public static class TestImageExtensions + { + public static void DebugSave(this Image img, TestImageProvider provider, string extension = "png") + where TColor : struct, IPixel + { + if(!bool.TryParse(Environment.GetEnvironmentVariable("CI"), out bool isCI) || !isCI) + { + // we are running locally then we want to save it out + provider.Utility.SaveTestOutputFile(img, extension); + } + } + } +}