From 85b15415eb355783a122f44c40d16de44537f77b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 29 Jan 2017 19:58:37 +1100 Subject: [PATCH 01/85] Working build --- ImageSharp.sln | 157 ++++++++++++++---- build/build.csproj | 26 +++ build/build.xproj | 25 --- build/project.json | 22 --- global.json | 6 - .../ImageSharp.Drawing.csproj | 66 ++++++++ .../ImageSharp.Drawing.xproj | 25 --- src/ImageSharp.Drawing/project.json | 97 ----------- .../ImageSharp.Formats.Bmp.csproj | 65 ++++++++ .../ImageSharp.Formats.Bmp.xproj | 25 --- src/ImageSharp.Formats.Bmp/project.json | 93 ----------- .../ImageSharp.Formats.Gif.csproj | 65 ++++++++ .../ImageSharp.Formats.Gif.xproj | 25 --- src/ImageSharp.Formats.Gif/project.json | 93 ----------- .../ImageSharp.Formats.Jpeg.csproj | 65 ++++++++ .../ImageSharp.Formats.Jpeg.xproj | 25 --- src/ImageSharp.Formats.Jpeg/project.json | 93 ----------- .../ImageSharp.Formats.Png.csproj | 65 ++++++++ .../ImageSharp.Formats.Png.xproj | 25 --- src/ImageSharp.Formats.Png/project.json | 93 ----------- .../ImageSharp.Processing.csproj | 65 ++++++++ .../ImageSharp.Processing.xproj | 25 --- src/ImageSharp.Processing/project.json | 93 ----------- src/ImageSharp/ImageSharp.csproj | 62 +++++++ src/ImageSharp/ImageSharp.xproj | 25 --- src/ImageSharp/project.json | 89 ---------- tests/ImageSharp.Benchmarks/Benchmark.cmd | 3 - .../ImageSharp.Benchmarks.csproj | 22 +++ .../ImageSharp.Benchmarks.xproj | 19 --- tests/ImageSharp.Benchmarks/Program.cs | 2 - .../Properties/AssemblyInfo.cs | 27 --- tests/ImageSharp.Benchmarks/project.json | 59 ------- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 23 +++ tests/ImageSharp.Tests/ImageSharp.Tests.xproj | 22 --- .../Properties/AssemblyInfo.cs | 23 --- tests/ImageSharp.Tests/TestBase.cs | 6 +- tests/ImageSharp.Tests/project.json | 70 -------- 37 files changed, 653 insertions(+), 1138 deletions(-) create mode 100644 build/build.csproj delete mode 100644 build/build.xproj delete mode 100644 build/project.json delete mode 100644 global.json create mode 100644 src/ImageSharp.Drawing/ImageSharp.Drawing.csproj delete mode 100644 src/ImageSharp.Drawing/ImageSharp.Drawing.xproj delete mode 100644 src/ImageSharp.Drawing/project.json create mode 100644 src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj delete mode 100644 src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.xproj delete mode 100644 src/ImageSharp.Formats.Bmp/project.json create mode 100644 src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj delete mode 100644 src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.xproj delete mode 100644 src/ImageSharp.Formats.Gif/project.json create mode 100644 src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj delete mode 100644 src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.xproj delete mode 100644 src/ImageSharp.Formats.Jpeg/project.json create mode 100644 src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj delete mode 100644 src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.xproj delete mode 100644 src/ImageSharp.Formats.Png/project.json create mode 100644 src/ImageSharp.Processing/ImageSharp.Processing.csproj delete mode 100644 src/ImageSharp.Processing/ImageSharp.Processing.xproj delete mode 100644 src/ImageSharp.Processing/project.json create mode 100644 src/ImageSharp/ImageSharp.csproj delete mode 100644 src/ImageSharp/ImageSharp.xproj delete mode 100644 src/ImageSharp/project.json delete mode 100644 tests/ImageSharp.Benchmarks/Benchmark.cmd create mode 100644 tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj delete mode 100644 tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.xproj delete mode 100644 tests/ImageSharp.Benchmarks/Properties/AssemblyInfo.cs delete mode 100644 tests/ImageSharp.Benchmarks/project.json create mode 100644 tests/ImageSharp.Tests/ImageSharp.Tests.csproj delete mode 100644 tests/ImageSharp.Tests/ImageSharp.Tests.xproj delete mode 100644 tests/ImageSharp.Tests/Properties/AssemblyInfo.cs delete mode 100644 tests/ImageSharp.Tests/project.json diff --git a/ImageSharp.sln b/ImageSharp.sln index f1e9fb1045..97021cffee 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -1,14 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.26127.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp", "src\ImageSharp\ImageSharp.xproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Tests", "tests\ImageSharp.Tests\ImageSharp.Tests.xproj", "{F836E8E6-B4D9-4208-8346-140C74678B91}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.xproj", "{299D8E18-102C-42DE-ADBF-79098EE706A8}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -31,31 +25,32 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C06 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{56801022-D71A-4FBE-BC5B-CBA08E2284EC}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Drawing", "src\ImageSharp.Drawing\ImageSharp.Drawing.xproj", "{2E33181E-6E28-4662-A801-E2E7DC206029}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{E919DF0B-2607-4462-8FC0-5C98FE50F8C9}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "build", "build\build.xproj", "{575A5002-DD9F-4335-AA47-1DD87FA13645}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E574A07-F879-4811-9C41-5CBDC6BAFDB7}" + ProjectSection(SolutionItems) = preProject + src\Shared\AssemblyInfo.Common.cs = src\Shared\AssemblyInfo.Common.cs + src\Shared\stylecop.json = src\Shared\stylecop.json + EndProjectSection EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Formats.Bmp", "src\ImageSharp.Formats.Bmp\ImageSharp.Formats.Bmp.xproj", "{C77661B9-F793-422E-8E27-AC60ECC5F215}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Formats.Gif", "src\ImageSharp.Formats.Gif\ImageSharp.Formats.Gif.xproj", "{27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Drawing", "src\ImageSharp.Drawing\ImageSharp.Drawing.csproj", "{2E33181E-6E28-4662-A801-E2E7DC206029}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Formats.Jpeg", "src\ImageSharp.Formats.Jpeg\ImageSharp.Formats.Jpeg.xproj", "{7213767C-0003-41CA-AB18-0223CFA7CE4B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{575A5002-DD9F-4335-AA47-1DD87FA13645}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Formats.Png", "src\ImageSharp.Formats.Png\ImageSharp.Formats.Png.xproj", "{556ABDCF-ED93-4327-BE98-F6815F78B9B8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Bmp", "src\ImageSharp.Formats.Bmp\ImageSharp.Formats.Bmp.csproj", "{C77661B9-F793-422E-8E27-AC60ECC5F215}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Processing", "src\ImageSharp.Processing\ImageSharp.Processing.xproj", "{A623CFE9-9D2B-4528-AD1F-2E834B061134}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Gif", "src\ImageSharp.Formats.Gif\ImageSharp.Formats.Gif.csproj", "{27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{9E574A07-F879-4811-9C41-5CBDC6BAFDB7}" - ProjectSection(SolutionItems) = preProject - src\Shared\AssemblyInfo.Common.cs = src\Shared\AssemblyInfo.Common.cs - src\Shared\stylecop.json = src\Shared\stylecop.json - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Jpeg", "src\ImageSharp.Formats.Jpeg\ImageSharp.Formats.Jpeg.csproj", "{7213767C-0003-41CA-AB18-0223CFA7CE4B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Png", "src\ImageSharp.Formats.Png\ImageSharp.Formats.Png.csproj", "{556ABDCF-ED93-4327-BE98-F6815F78B9B8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Processing", "src\ImageSharp.Processing\ImageSharp.Processing.csproj", "{A623CFE9-9D2B-4528-AD1F-2E834B061134}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" ProjectSection(ProjectDependencies) = postProject - {299D8E18-102C-42DE-ADBF-79098EE706A8} = {299D8E18-102C-42DE-ADBF-79098EE706A8} {2E33181E-6E28-4662-A801-E2E7DC206029} = {2E33181E-6E28-4662-A801-E2E7DC206029} {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} = {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} @@ -65,64 +60,159 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tes {A623CFE9-9D2B-4528-AD1F-2E834B061134} = {A623CFE9-9D2B-4528-AD1F-2E834B061134} EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Tests", "tests\ImageSharp.Tests\ImageSharp.Tests.csproj", "{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x64.ActiveCfg = Debug|x64 + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x64.Build.0 = Debug|x64 + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x86.ActiveCfg = Debug|x86 + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x86.Build.0 = Debug|x86 {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|Any CPU.ActiveCfg = Release|Any CPU {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|Any CPU.Build.0 = Release|Any CPU - {F836E8E6-B4D9-4208-8346-140C74678B91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F836E8E6-B4D9-4208-8346-140C74678B91}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F836E8E6-B4D9-4208-8346-140C74678B91}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F836E8E6-B4D9-4208-8346-140C74678B91}.Release|Any CPU.Build.0 = Release|Any CPU - {299D8E18-102C-42DE-ADBF-79098EE706A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {299D8E18-102C-42DE-ADBF-79098EE706A8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {299D8E18-102C-42DE-ADBF-79098EE706A8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {299D8E18-102C-42DE-ADBF-79098EE706A8}.Release|Any CPU.Build.0 = Release|Any CPU + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.ActiveCfg = Release|x64 + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.Build.0 = Release|x64 + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.ActiveCfg = Release|x86 + {2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.Build.0 = Release|x86 {2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x64.ActiveCfg = Debug|x64 + {2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x64.Build.0 = Debug|x64 + {2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x86.ActiveCfg = Debug|x86 + {2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x86.Build.0 = Debug|x86 {2E33181E-6E28-4662-A801-E2E7DC206029}.Release|Any CPU.ActiveCfg = Release|Any CPU {2E33181E-6E28-4662-A801-E2E7DC206029}.Release|Any CPU.Build.0 = Release|Any CPU + {2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x64.ActiveCfg = Release|x64 + {2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x64.Build.0 = Release|x64 + {2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x86.ActiveCfg = Release|x86 + {2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x86.Build.0 = Release|x86 {575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|Any CPU.Build.0 = Debug|Any CPU + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x64.ActiveCfg = Debug|x64 + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x64.Build.0 = Debug|x64 + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x86.ActiveCfg = Debug|x86 + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x86.Build.0 = Debug|x86 {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|Any CPU.ActiveCfg = Release|Any CPU {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|Any CPU.Build.0 = Release|Any CPU + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x64.ActiveCfg = Release|x64 + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x64.Build.0 = Release|x64 + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x86.ActiveCfg = Release|x86 + {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x86.Build.0 = Release|x86 {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x64.ActiveCfg = Debug|x64 + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x64.Build.0 = Debug|x64 + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x86.ActiveCfg = Debug|x86 + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x86.Build.0 = Debug|x86 {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|Any CPU.ActiveCfg = Release|Any CPU {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|Any CPU.Build.0 = Release|Any CPU + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x64.ActiveCfg = Release|x64 + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x64.Build.0 = Release|x64 + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x86.ActiveCfg = Release|x86 + {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x86.Build.0 = Release|x86 {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x64.ActiveCfg = Debug|x64 + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x64.Build.0 = Debug|x64 + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x86.ActiveCfg = Debug|x86 + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x86.Build.0 = Debug|x86 {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|Any CPU.ActiveCfg = Release|Any CPU {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|Any CPU.Build.0 = Release|Any CPU + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x64.ActiveCfg = Release|x64 + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x64.Build.0 = Release|x64 + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x86.ActiveCfg = Release|x86 + {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x86.Build.0 = Release|x86 {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x64.ActiveCfg = Debug|x64 + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x64.Build.0 = Debug|x64 + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x86.ActiveCfg = Debug|x86 + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x86.Build.0 = Debug|x86 {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|Any CPU.Build.0 = Release|Any CPU + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x64.ActiveCfg = Release|x64 + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x64.Build.0 = Release|x64 + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x86.ActiveCfg = Release|x86 + {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x86.Build.0 = Release|x86 {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x64.ActiveCfg = Debug|x64 + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x64.Build.0 = Debug|x64 + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x86.ActiveCfg = Debug|x86 + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x86.Build.0 = Debug|x86 {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|Any CPU.ActiveCfg = Release|Any CPU {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|Any CPU.Build.0 = Release|Any CPU + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x64.ActiveCfg = Release|x64 + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x64.Build.0 = Release|x64 + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x86.ActiveCfg = Release|x86 + {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x86.Build.0 = Release|x86 {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x64.ActiveCfg = Debug|x64 + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x64.Build.0 = Debug|x64 + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x86.ActiveCfg = Debug|x86 + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x86.Build.0 = Debug|x86 {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|Any CPU.ActiveCfg = Release|Any CPU {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|Any CPU.Build.0 = Release|Any CPU + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x64.ActiveCfg = Release|x64 + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x64.Build.0 = Release|x64 + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x86.ActiveCfg = Release|x86 + {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x86.Build.0 = Release|x86 {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.ActiveCfg = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.Build.0 = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x86.Build.0 = Debug|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.Build.0 = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.ActiveCfg = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.Build.0 = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.ActiveCfg = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.Build.0 = Release|Any CPU + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.ActiveCfg = Debug|x64 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.Build.0 = Debug|x64 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x86.ActiveCfg = Debug|x86 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x86.Build.0 = Debug|x86 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|Any CPU.Build.0 = Release|Any CPU + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x64.ActiveCfg = Release|x64 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x64.Build.0 = Release|x64 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x86.ActiveCfg = Release|x86 + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x86.Build.0 = Release|x86 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x64.ActiveCfg = Debug|x64 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x64.Build.0 = Debug|x64 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.ActiveCfg = Debug|x86 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.Build.0 = Debug|x86 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|Any CPU.Build.0 = Release|Any CPU + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.ActiveCfg = Release|x64 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.Build.0 = Release|x64 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.ActiveCfg = Release|x86 + {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {9E574A07-F879-4811-9C41-5CBDC6BAFDB7} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {F836E8E6-B4D9-4208-8346-140C74678B91} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} - {299D8E18-102C-42DE-ADBF-79098EE706A8} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {2E33181E-6E28-4662-A801-E2E7DC206029} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {575A5002-DD9F-4335-AA47-1DD87FA13645} = {E919DF0B-2607-4462-8FC0-5C98FE50F8C9} {C77661B9-F793-422E-8E27-AC60ECC5F215} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} @@ -130,7 +220,8 @@ Global {7213767C-0003-41CA-AB18-0223CFA7CE4B} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {556ABDCF-ED93-4327-BE98-F6815F78B9B8} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {A623CFE9-9D2B-4528-AD1F-2E834B061134} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {9E574A07-F879-4811-9C41-5CBDC6BAFDB7} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} + {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} + {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} EndGlobalSection EndGlobal diff --git a/build/build.csproj b/build/build.csproj new file mode 100644 index 0000000000..38e6415999 --- /dev/null +++ b/build/build.csproj @@ -0,0 +1,26 @@ + + + net46 + win7-x64 + portable + true + build + Exe + build + ..\ImageSharp.ruleset + + + + + + + + + All + + + + + + + \ No newline at end of file diff --git a/build/build.xproj b/build/build.xproj deleted file mode 100644 index 3b85ca8722..0000000000 --- a/build/build.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 575a5002-dd9f-4335-aa47-1dd87fa13645 - build - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/build/project.json b/build/project.json deleted file mode 100644 index cf95cc8a0b..0000000000 --- a/build/project.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "debugType": "portable", - "emitEntryPoint": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../src/Shared/stylecop.json", "/ruleset:../ImageSharp.ruleset" ] - }, - "dependencies": { - "Microsoft.DotNet.ProjectModel": "1.0.0-rc3-003121", - "LibGit2Sharp": "0.23.0", - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - } - }, - "frameworks": { - "net46": { - // this is only a net46 app because of LibGit2Sharp once they have a version that works on coreclr we can shift over. - } - } -} diff --git a/global.json b/global.json deleted file mode 100644 index 7346bdc280..0000000000 --- a/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "projects": [ "src" ], - "sdk": { - "version": "1.0.0-preview2-003121" - } -} \ No newline at end of file diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj new file mode 100644 index 0000000000..fc36e7ed5f --- /dev/null +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -0,0 +1,66 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp.Drawing + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp.Drawing + ImageSharp.Drawing + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.xproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.xproj deleted file mode 100644 index 488f86bc7a..0000000000 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2e33181e-6e28-4662-a801-e2e7dc206029 - ImageSharp.Drawing - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Drawing/project.json b/src/ImageSharp.Drawing/project.json deleted file mode 100644 index 04a5601706..0000000000 --- a/src/ImageSharp.Drawing/project.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp.Drawing", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Processing": { - "target": "project", - "version": "1.0.0-*" - }, - "StyleCop.Analyzers": { - "version": "1.0.0", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj new file mode 100644 index 0000000000..9caa41643a --- /dev/null +++ b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj @@ -0,0 +1,65 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp.Formats.Bmp + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp.Formats.Bmp + ImageSharp.Formats.Bmp + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.xproj b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.xproj deleted file mode 100644 index 94916399bd..0000000000 --- a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - c77661b9-f793-422e-8e27-ac60ecc5f215 - ImageSharp.Formats.Bmp - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Bmp/project.json b/src/ImageSharp.Formats.Bmp/project.json deleted file mode 100644 index 575e414aa1..0000000000 --- a/src/ImageSharp.Formats.Bmp/project.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp.Formats.Bmp", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj new file mode 100644 index 0000000000..2890e58a83 --- /dev/null +++ b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj @@ -0,0 +1,65 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp.Formats.Gif + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp.Formats.Gif + ImageSharp.Formats.Gif + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.xproj b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.xproj deleted file mode 100644 index d11c20c482..0000000000 --- a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 27ad4b5f-ecc4-4c63-9ecb-04ec772fdb6f - ImageSharp.Formats.Gif - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Gif/project.json b/src/ImageSharp.Formats.Gif/project.json deleted file mode 100644 index e12d3c733f..0000000000 --- a/src/ImageSharp.Formats.Gif/project.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp.Formats.Gif", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj new file mode 100644 index 0000000000..e249c58f21 --- /dev/null +++ b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj @@ -0,0 +1,65 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp.Formats.Jpeg + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp.Formats.Jpeg + ImageSharp.Formats.Jpeg + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.xproj b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.xproj deleted file mode 100644 index a22dc5ea34..0000000000 --- a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 7213767c-0003-41ca-ab18-0223cfa7ce4b - ImageSharp.Formats - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/project.json b/src/ImageSharp.Formats.Jpeg/project.json deleted file mode 100644 index de16f6c1ce..0000000000 --- a/src/ImageSharp.Formats.Jpeg/project.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp.Formats.Jpeg", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj b/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj new file mode 100644 index 0000000000..83a48cd2f1 --- /dev/null +++ b/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj @@ -0,0 +1,65 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp.Formats.Png + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp.Formats.Png + ImageSharp.Formats.Png + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.xproj b/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.xproj deleted file mode 100644 index f12901d6bc..0000000000 --- a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 556abdcf-ed93-4327-be98-f6815f78b9b8 - ImageSharp.Formats.Png - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Png/project.json b/src/ImageSharp.Formats.Png/project.json deleted file mode 100644 index eac71d8c71..0000000000 --- a/src/ImageSharp.Formats.Png/project.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp.Formats.Png", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp.Processing/ImageSharp.Processing.csproj b/src/ImageSharp.Processing/ImageSharp.Processing.csproj new file mode 100644 index 0000000000..cd051d1b80 --- /dev/null +++ b/src/ImageSharp.Processing/ImageSharp.Processing.csproj @@ -0,0 +1,65 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp.Processing + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp.Processing + ImageSharp.Processing + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Processing/ImageSharp.Processing.xproj b/src/ImageSharp.Processing/ImageSharp.Processing.xproj deleted file mode 100644 index 1fdba5ce9a..0000000000 --- a/src/ImageSharp.Processing/ImageSharp.Processing.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - a623cfe9-9d2b-4528-ad1f-2e834b061134 - ImageSharp.Processing - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Processing/project.json b/src/ImageSharp.Processing/project.json deleted file mode 100644 index 2ff224fa4a..0000000000 --- a/src/ImageSharp.Processing/project.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp.Processing", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-alpha1" - }, - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj new file mode 100644 index 0000000000..da8586a3e2 --- /dev/null +++ b/src/ImageSharp/ImageSharp.csproj @@ -0,0 +1,62 @@ + + + A cross-platform library for the processing of image files; written in C# + ImageSharp + 1.0.0-alpha1 + James Jackson-South and contributors + netstandard1.1;net45;net461 + true + true + ImageSharp + ImageSharp + Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png + https://github.com/JimBobSquarePants/ImageSharp + http://www.apache.org/licenses/LICENSE-2.0 + git + https://github.com/JimBobSquarePants/ImageSharp + false + false + false + false + false + false + false + false + false + + + + + + + + All + + + + + + + + + + + + + + + + ..\..\ImageSharp.ruleset + + + true + + + + + + + + + \ No newline at end of file diff --git a/src/ImageSharp/ImageSharp.xproj b/src/ImageSharp/ImageSharp.xproj deleted file mode 100644 index bf2f6a67bc..0000000000 --- a/src/ImageSharp/ImageSharp.xproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 2aa31a1f-142c-43f4-8687-09abca4b3a26 - ImageSharp - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - True - - - - - - \ No newline at end of file diff --git a/src/ImageSharp/project.json b/src/ImageSharp/project.json deleted file mode 100644 index 117d320900..0000000000 --- a/src/ImageSharp/project.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "version": "1.0.0-alpha1-*", - "title": "ImageSharp", - "description": "A cross-platform library for the processing of image files; written in C#", - "authors": [ - "James Jackson-South and contributors" - ], - "packOptions": { - "owners": [ - "James Jackson-South and contributors" - ], - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", - "requireLicenseAcceptance": false, - "repository": { - "type": "git", - "url": "https://github.com/JimBobSquarePants/ImageSharp" - }, - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true, - "xmlDoc": true, - "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], - "compile": [ - "../Shared/*.cs" - ] - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true, - "optimize": true - } - } - }, - "dependencies": { - "StyleCop.Analyzers": { - "version": "1.1.0-beta001", - "type": "build" - }, - "System.Buffers": "4.0.0", - "System.Runtime.CompilerServices.Unsafe": "4.0.0" - }, - "frameworks": { - "netstandard1.1": { - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.IO": "4.1.0", - "System.IO.Compression": "4.1.0", - "System.Linq": "4.1.0", - "System.Numerics.Vectors": "4.1.1", - "System.ObjectModel": "4.0.12", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.Numerics": "4.0.1", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Threading.Tasks.Parallel": "4.0.1" - } - }, - "net45": { - "dependencies": { - "System.Numerics.Vectors": "4.1.1", - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" } - } - }, - "net461": { - "dependencies": { - "System.Threading.Tasks.Parallel": "4.0.0" - }, - "frameworkAssemblies": { - "System.Runtime": { "type": "build" }, - "System.Numerics": "4.0.0.0", - "System.Numerics.Vectors": "4.0.0.0" - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Benchmark.cmd b/tests/ImageSharp.Benchmarks/Benchmark.cmd deleted file mode 100644 index f777e5b8f6..0000000000 --- a/tests/ImageSharp.Benchmarks/Benchmark.cmd +++ /dev/null @@ -1,3 +0,0 @@ -@echo off -dotnet run --configuration Release -pause diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj new file mode 100644 index 0000000000..142825c55d --- /dev/null +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -0,0 +1,22 @@ + + + Exe + net461 + win7-x64 + True + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.xproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.xproj deleted file mode 100644 index 184faefd81..0000000000 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.xproj +++ /dev/null @@ -1,19 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 299d8e18-102c-42de-adbf-79098ee706a8 - ImageSharp.Benchmarks - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Program.cs b/tests/ImageSharp.Benchmarks/Program.cs index 8c609f015f..7ecf632743 100644 --- a/tests/ImageSharp.Benchmarks/Program.cs +++ b/tests/ImageSharp.Benchmarks/Program.cs @@ -7,8 +7,6 @@ namespace ImageSharp.Benchmarks { using BenchmarkDotNet.Running; - using ImageSharp.Formats; - public class Program { /// diff --git a/tests/ImageSharp.Benchmarks/Properties/AssemblyInfo.cs b/tests/ImageSharp.Benchmarks/Properties/AssemblyInfo.cs deleted file mode 100644 index 39f8b862d7..0000000000 --- a/tests/ImageSharp.Benchmarks/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using BenchmarkDotNet.Attributes; -using ImageSharp.Benchmarks; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageSharp.Benchmarks")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ImageSharp.Benchmarks")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("299d8e18-102c-42de-adbf-79098ee706a8")] - -[assembly: Config(typeof(Config))] \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/project.json b/tests/ImageSharp.Benchmarks/project.json deleted file mode 100644 index 8650a8af41..0000000000 --- a/tests/ImageSharp.Benchmarks/project.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "version": "1.0.0-*", - "description": "ImageSharp.Benchmarks Console Application", - "authors": [ "James.South" ], - "packOptions": { - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "emitEntryPoint": true, - "allowUnsafe": true - }, - "dependencies": { - "BenchmarkDotNet.Diagnostics.Windows": "0.10.1", - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Drawing": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Jpeg": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Png": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Bmp": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Gif": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Processing": { - "target": "project", - "version": "1.0.0-*" - } - }, - "commands": { - "ImageSharp.Benchmarks": "ImageSharp.Benchmarks" - }, - "frameworks": { - "net46": { - "dependencies": { - }, - "frameworkAssemblies": { - "System.Drawing": "" - } - } - } -} diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj new file mode 100644 index 0000000000..198f0f33f6 --- /dev/null +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -0,0 +1,23 @@ + + + netcoreapp1.0 + True + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.xproj b/tests/ImageSharp.Tests/ImageSharp.Tests.xproj deleted file mode 100644 index d2c2d15a03..0000000000 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.xproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - f836e8e6-b4d9-4208-8346-140c74678b91 - ImageSharp.Tests - .\obj - .\bin\ - v4.5.1 - - - 2.0 - - - - - - \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Properties/AssemblyInfo.cs b/tests/ImageSharp.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index 3d57ceff5c..0000000000 --- a/tests/ImageSharp.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ImageSharp.Tests")] -[assembly: AssemblyDescription("A cross-platform library for processing of image files written in C#")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ImageSharp.Tests")] -[assembly: AssemblyCopyright("Copyright © James Jackson-South and contributors.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f836e8e6-b4d9-4208-8346-140c74678b91")] diff --git a/tests/ImageSharp.Tests/TestBase.cs b/tests/ImageSharp.Tests/TestBase.cs index 2b92591eb7..c7514d5aee 100644 --- a/tests/ImageSharp.Tests/TestBase.cs +++ b/tests/ImageSharp.Tests/TestBase.cs @@ -6,6 +6,8 @@ namespace ImageSharp.Tests { using System.IO; + using System.Reflection; + using ImageSharp.Formats; /// @@ -23,7 +25,9 @@ namespace ImageSharp.Tests /// protected string CreateOutputDirectory(string path, params string[] pathParts) { - path = Path.Combine("TestOutput", path); + string assemblyLocation = typeof(TestFile).GetTypeInfo().Assembly.Location; + assemblyLocation = Path.GetDirectoryName(assemblyLocation); + path = Path.GetFullPath(Path.Combine(assemblyLocation, "../../../TestOutput", path)); if (pathParts != null && pathParts.Length > 0) { diff --git a/tests/ImageSharp.Tests/project.json b/tests/ImageSharp.Tests/project.json deleted file mode 100644 index 9f9c0c7150..0000000000 --- a/tests/ImageSharp.Tests/project.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "version": "1.0.0-*", - "description": "ImageSharp.Tests Class Library", - "authors": [ "James Jackson-South and contributors" ], - "packOptions": { - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project", - "version": "1.0.0-*" - }, - "xunit": "2.2.0-*", - "dotnet-test-xunit": "2.2.0-*", - "ImageSharp.Drawing": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Png": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Jpeg": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Bmp": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Formats.Gif": { - "target": "project", - "version": "1.0.0-*" - }, - "ImageSharp.Processing": { - "target": "project", - "version": "1.0.0-*" - } - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0-*" - }, - "Microsoft.CodeCoverage": "1.0.2" - } - }, - "net451": { - "dependencies": { - } - } - }, - "testRunner": "xunit" -} \ No newline at end of file From a3296ff9d9694081bf8ec2256a54d437d1666ea4 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 18:43:49 +0000 Subject: [PATCH 02/85] migrate build script to csproj bump version number due to project file type changing we are reseting the build counter. --- .gitignore | 3 + build/Program.cs | 98 +++++++++++-------- build/build.csproj | 2 +- .../ImageSharp.Drawing.csproj | 2 +- .../ImageSharp.Formats.Bmp.csproj | 2 +- .../ImageSharp.Formats.Gif.csproj | 2 +- .../ImageSharp.Formats.Jpeg.csproj | 2 +- .../ImageSharp.Processing.csproj | 2 +- src/ImageSharp/ImageSharp.csproj | 2 +- .../ImageSharp.Benchmarks.csproj | 2 +- 10 files changed, 69 insertions(+), 48 deletions(-) diff --git a/.gitignore b/.gitignore index 6e291ec94d..61c78d0c8b 100644 --- a/.gitignore +++ b/.gitignore @@ -211,5 +211,8 @@ artifacts/ #BenchmarkDotNet **/BenchmarkDotNet.Artifacts/ +# Build process +*.csproj.bak + #CodeCoverage **/CodeCoverage/* \ No newline at end of file diff --git a/build/Program.cs b/build/Program.cs index a79743393c..6e04dc1df4 100644 --- a/build/Program.cs +++ b/build/Program.cs @@ -10,10 +10,10 @@ namespace ConsoleApplication using System.IO; using System.Linq; using System.Text; - + using System.Xml; using LibGit2Sharp; - using Microsoft.DotNet.ProjectModel; - using Newtonsoft.Json; + using Microsoft.Build.Construction; + using Microsoft.Build.Evaluation; using NuGet.Versioning; /// @@ -65,31 +65,29 @@ namespace ConsoleApplication { var resetmode = args.Contains("reset"); - // Find the project root where glbal.json lives - var root = ProjectRootResolver.ResolveRootDirectory("."); + // Find the project root + var root = Path.GetFullPath(Path.Combine(LibGit2Sharp.Repository.Discover("."), "..")); // Lets find the repo var repo = new LibGit2Sharp.Repository(root); // Lets find all the project.json files in the src folder (don't care about versioning `tests`) - var projectFiles = Directory.EnumerateFiles(Path.Combine(root, "src"), Project.FileName, SearchOption.AllDirectories); + var projectFiles = Directory.EnumerateFiles(Path.Combine(root, "src"), "*.csproj", SearchOption.AllDirectories); + + ResetProject(projectFiles); // Open them and convert them to source projects - var projects = projectFiles.Select(x => ProjectReader.GetProject(x)) + var projects = projectFiles.Select(x => ProjectRootElement.Open(x, ProjectCollection.GlobalProjectCollection, true)) .Select(x => new SourceProject(x, repo.Info.WorkingDirectory)) .ToList(); - if (resetmode) - { - ResetProject(projects); - } - else + if (!resetmode) { CaclulateProjectVersionNumber(projects, repo); UpdateVersionNumbers(projects); - CreateBuildScript(projects); + CreateBuildScript(projects, root); foreach (var p in projects) { @@ -98,12 +96,14 @@ namespace ConsoleApplication } } - private static void CreateBuildScript(IEnumerable projects) + private static void CreateBuildScript(IEnumerable projects, string root) { + var outputDir = Path.GetFullPath(Path.Combine(root, @"artifacts\bin\ImageSharp")); + var sb = new StringBuilder(); foreach (var p in projects) { - sb.AppendLine($@"dotnet pack --configuration Release --output ""artifacts\bin\ImageSharp"" ""{p.ProjectFilePath}"""); + sb.AppendLine($@"dotnet pack --configuration Release --output ""{outputDir}"" ""{p.ProjectFilePath}"""); } File.WriteAllText("build-inner.cmd", sb.ToString()); @@ -113,17 +113,17 @@ namespace ConsoleApplication { foreach (var p in projects) { - // TODO force update of all dependent projects to point to the newest build. - // we skip the build number and standard CI prefix on first commits - var newVersion = p.FinalVersionNumber; - // create a backup file so we can rollback later without breaking formatting File.Copy(p.FullProjectFilePath, $"{p.FullProjectFilePath}.bak", true); + } - dynamic projectFile = JsonConvert.DeserializeObject(File.ReadAllText(p.FullProjectFilePath)); + foreach (var p in projects) + { + // TODO force update of all dependent projects to point to the newest build. + // we skip the build number and standard CI prefix on first commits + var newVersion = p.FinalVersionNumber; - projectFile.version = $"{newVersion}-*"; - File.WriteAllText(p.FullProjectFilePath, JsonConvert.SerializeObject(projectFile, Formatting.Indented)); + p.UpdateVersion(newVersion); } } @@ -168,7 +168,7 @@ namespace ConsoleApplication projects.ForEach(x => x.CalculateVersion(repo, branch)); } - private static void ResetProject(List projects) + private static void ResetProject(IEnumerable projectPaths) { if (File.Exists("build-inner.cmd")) { @@ -176,12 +176,12 @@ namespace ConsoleApplication } // revert the project.json change be reverting it but skipp all the git stuff as its not needed - foreach (var p in projects) + foreach (var p in projectPaths) { - if (File.Exists($"{p.FullProjectFilePath}.bak")) + if (File.Exists($"{p}.bak")) { - File.Copy($"{p.FullProjectFilePath}.bak", p.FullProjectFilePath, true); - File.Delete($"{p.FullProjectFilePath}.bak"); + File.Copy($"{p}.bak", p, true); + File.Delete($"{p}.bak"); } } } @@ -192,21 +192,24 @@ namespace ConsoleApplication public class SourceProject { private readonly IEnumerable dependencies; + private readonly ProjectRootElement project; /// /// Initializes a new instance of the class. /// /// The project. /// The root. - public SourceProject(Project project, string root) + public SourceProject(ProjectRootElement project, string root) { - this.Name = project.Name; - this.ProjectDirectory = project.ProjectDirectory.Substring(root.Length); - this.ProjectFilePath = project.ProjectFilePath.Substring(root.Length); - this.FullProjectFilePath = project.ProjectFilePath; - this.Version = project.Version; - this.dependencies = project.Dependencies.Select(x => x.Name); + this.Name = project.Properties.FirstOrDefault(x => x.Name == "AssemblyTitle").Value; + + this.ProjectDirectory = project.DirectoryPath.Substring(root.Length); + this.ProjectFilePath = project.ProjectFileLocation.File.Substring(root.Length); + this.FullProjectFilePath = Path.GetFullPath(project.ProjectFileLocation.File); + this.Version = new NuGetVersion(project.Properties.FirstOrDefault(x => x.Name == "VersionPrefix").Value); + this.dependencies = project.Items.Where(x => x.ItemType == "ProjectReference").Select(x => Path.GetFullPath(Path.Combine(project.DirectoryPath, x.Include))); this.FinalVersionNumber = this.Version.ToFullString(); + this.project = project; } /// @@ -223,7 +226,7 @@ namespace ConsoleApplication /// /// The version. /// - public NuGetVersion Version { get; } + public NuGetVersion Version { get; private set; } /// /// Gets the dependent projects. @@ -279,7 +282,18 @@ namespace ConsoleApplication /// The projects. public void PopulateDependencies(IEnumerable projects) { - this.DependentProjects = projects.Where(x => this.dependencies.Contains(x.Name)).ToList(); + this.DependentProjects = projects.Where(x => this.dependencies.Contains(x.FullProjectFilePath)).ToList(); + } + + /// + /// Update the version number in the project file + /// + /// the new version number to save. + internal void UpdateVersion(string versionnumber) + { + this.project.AddProperty("VersionPrefix", versionnumber); + this.Version = new NuGetVersion(versionnumber); + this.project.Save(); } /// @@ -334,11 +348,15 @@ namespace ConsoleApplication var blob = repo.Lookup(projectFileChange.Oid); using (var s = blob.GetContentStream()) { - var project = new ProjectReader().ReadProject(s, this.Name, this.FullProjectFilePath, null); - if (project.Version != this.Version) + using (var reader = XmlReader.Create(s)) { - // version changed - return false; + var proj = ProjectRootElement.Create(reader); + var version = new NuGetVersion(proj.Properties.FirstOrDefault(x => x.Name == "VersionPrefix").Value); + if (version != this.Version) + { + // version changed + return false; + } } } } diff --git a/build/build.csproj b/build/build.csproj index 38e6415999..49f6489b4f 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -13,7 +13,7 @@ - + All diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index fc36e7ed5f..d9688f242a 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp.Drawing - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true diff --git a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj index 9caa41643a..6b741d32cf 100644 --- a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj +++ b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp.Formats.Bmp - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true diff --git a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj index 2890e58a83..a7ee625f77 100644 --- a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj +++ b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp.Formats.Gif - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true diff --git a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj index e249c58f21..0b1888c278 100644 --- a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj +++ b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp.Formats.Jpeg - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true diff --git a/src/ImageSharp.Processing/ImageSharp.Processing.csproj b/src/ImageSharp.Processing/ImageSharp.Processing.csproj index cd051d1b80..52794e5b36 100644 --- a/src/ImageSharp.Processing/ImageSharp.Processing.csproj +++ b/src/ImageSharp.Processing/ImageSharp.Processing.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp.Processing - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index da8586a3e2..4ebfb9a4ad 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 142825c55d..b4bedf8274 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -7,7 +7,7 @@ false - + From eeffb2d513a3b16e49573292a8b34fbe015ec3d5 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 19:00:00 +0000 Subject: [PATCH 03/85] missing dependency --- build/build.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/build/build.csproj b/build/build.csproj index 49f6489b4f..074c81a4f8 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -13,6 +13,7 @@ + From 02a15736072b6faa0cd09f9b6903482886cb8dee Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 20:31:30 +0000 Subject: [PATCH 04/85] fix image version --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 2792ab0fc6..600a06a2fa 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: 1.0.0.{build} -os: Visual Studio 2015 +image: Visual Studio 2017 RC init: - ps: iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/PureKrome/0f79e25693d574807939/raw/8cf3160c9516ef1f4effc825c0a44acc918a0b5a/appveyor-build-info.ps')) From 5f64eb3806f5e1ef2321d4039bfb038134abd4e9 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 20:55:13 +0000 Subject: [PATCH 05/85] revert Image --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 600a06a2fa..2792ab0fc6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: 1.0.0.{build} -image: Visual Studio 2017 RC +os: Visual Studio 2015 init: - ps: iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/PureKrome/0f79e25693d574807939/raw/8cf3160c9516ef1f4effc825c0a44acc918a0b5a/appveyor-build-info.ps')) From dcfd71280af69872242acd980b98dca2e9e4fae8 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 20:56:11 +0000 Subject: [PATCH 06/85] use RC3 version of dotnet cli --- dotnet-latest.ps1 | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/dotnet-latest.ps1 b/dotnet-latest.ps1 index bb2c5dcfed..32c53d7e1f 100644 --- a/dotnet-latest.ps1 +++ b/dotnet-latest.ps1 @@ -10,19 +10,31 @@ if (Test-Path $ArtifactsPath) { New-Item $ArtifactsPath -ItemType Directory -ErrorAction Ignore | Out-Null Write-Host "Created artifacts folder '$ArtifactsPath'" +$installRequired = $TRUE # Install the latest dotnet cli if (Get-Command "dotnet.exe" -ErrorAction SilentlyContinue) { Write-Host "dotnet SDK already installed" - dotnet --version -} else { + + $version = dotnet --version 2>&1 + if($version -ne "1.0.0-rc3-004530"){ + Write-Host "$version installed but require 1.0.0-rc3-004530" + $installRequired = $TRUE + }else{ + Write-Host "$version already installed" + $installRequired = $FALSE + } +} + +if($installRequired -eq $TRUE) +{ Write-Host "Installing dotnet SDK" $installScript = Join-Path $ArtifactsPath "dotnet-install.ps1" Write-Host $installScript - Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/install.ps1" ` + Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-rc3/scripts/obtain/dotnet-install.ps1" ` -OutFile $installScript & $installScript From 0f900befe129e8275baa9e18f930529499502d59 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 22:45:25 +0000 Subject: [PATCH 07/85] disable style cop as it spams the build log stylecop.analyzers seems to not like the dotnet cli build system, and throws lots of errors. --- appveyor.yml | 7 +++++++ build/build.csproj | 6 ------ src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 6 +----- .../ImageSharp.Formats.Bmp.csproj | 6 +----- .../ImageSharp.Formats.Gif.csproj | 6 +----- .../ImageSharp.Formats.Jpeg.csproj | 6 +----- .../ImageSharp.Formats.Png.csproj | 8 ++------ .../ImageSharp.Processing.csproj | 6 +----- src/ImageSharp/ImageSharp.csproj | 12 ++++-------- tests/CodeCoverage/CodeCoverage.cmd | 2 +- 10 files changed, 19 insertions(+), 46 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2792ab0fc6..19bb8f4627 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,10 @@ init: environment: # Version Suffix version_suffix: alpha + # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + # Disable sending usage data to Microsoft + DOTNET_CLI_TELEMETRY_OPTOUT: true install: # Use the install script to grab the latest dotnet install @@ -21,8 +25,11 @@ build_script: - cmd: build.cmd test_script: +- dotnet test tests\ImageSharp.Tests\ImageSharp.Tests.csproj --configuration release - tests\CodeCoverage\CodeCoverage.cmd +test: off + artifacts: - path: artifacts\bin\ImageSharp\**\*.nupkg diff --git a/build/build.csproj b/build/build.csproj index 074c81a4f8..371c6f91b5 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -9,16 +9,10 @@ build ..\ImageSharp.ruleset - - - - - All - diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index d9688f242a..ba4ccb7d1e 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -27,16 +27,12 @@ - - - All - @@ -54,7 +50,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj index 6b741d32cf..77df6cac28 100644 --- a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj +++ b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj @@ -27,15 +27,11 @@ - - - All - @@ -53,7 +49,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj index a7ee625f77..0b4fd4c2da 100644 --- a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj +++ b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj @@ -27,15 +27,11 @@ - - - All - @@ -53,7 +49,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj index 0b1888c278..f09576932d 100644 --- a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj +++ b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj @@ -27,15 +27,11 @@ - - - All - @@ -53,7 +49,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj b/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj index 83a48cd2f1..b58d5fbf3b 100644 --- a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj +++ b/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp.Formats.Png - 1.0.0-alpha1 + 1.0.0-alpha2 James Jackson-South and contributors netstandard1.1;net45;net461 true @@ -27,15 +27,11 @@ - - - All - @@ -53,7 +49,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/src/ImageSharp.Processing/ImageSharp.Processing.csproj b/src/ImageSharp.Processing/ImageSharp.Processing.csproj index 52794e5b36..820c1852d7 100644 --- a/src/ImageSharp.Processing/ImageSharp.Processing.csproj +++ b/src/ImageSharp.Processing/ImageSharp.Processing.csproj @@ -27,15 +27,11 @@ - - - All - @@ -53,7 +49,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 4ebfb9a4ad..762e68b508 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -27,15 +27,11 @@ - - - All - - - - + + + @@ -50,7 +46,7 @@ ..\..\ImageSharp.ruleset - true + true diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index e4fe3f9382..056e00ca97 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -12,7 +12,7 @@ cd .. cd .. rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"C:\Program Files\dotnet\dotnet.exe" -targetargs:"test tests\ImageSharp.Tests -c Release -f net451" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"C:\Program Files\dotnet\dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml if %errorlevel% neq 0 exit /b %errorlevel% From 46fa4cf6b7d2ba3aae8eb4edcbd1d3b2e2ad2fe3 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 22:50:39 +0000 Subject: [PATCH 08/85] run tests after build --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 19bb8f4627..fe860688bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,7 +24,8 @@ install: build_script: - cmd: build.cmd -test_script: +# run the tests in after build instead of tests to prevent appveryor trying to do its own thing and breaking +after_build : - dotnet test tests\ImageSharp.Tests\ImageSharp.Tests.csproj --configuration release - tests\CodeCoverage\CodeCoverage.cmd From 6dc91945c102e15d5354fa0cda0db1fce45d22f8 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 22:55:44 +0000 Subject: [PATCH 09/85] lets try a relative path --- tests/CodeCoverage/CodeCoverage.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index 056e00ca97..8ffa2000f8 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -12,7 +12,7 @@ cd .. cd .. rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"C:\Program Files\dotnet\dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml if %errorlevel% neq 0 exit /b %errorlevel% From d1f95e1c0ac88ddc2a3fb2ad5bec963dc7a5a368 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 23:02:50 +0000 Subject: [PATCH 10/85] specify runtime --- appveyor.yml | 6 +----- tests/CodeCoverage/CodeCoverage.cmd | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fe860688bf..90f5d8e62a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,13 +24,9 @@ install: build_script: - cmd: build.cmd -# run the tests in after build instead of tests to prevent appveryor trying to do its own thing and breaking -after_build : -- dotnet test tests\ImageSharp.Tests\ImageSharp.Tests.csproj --configuration release +test_script: - tests\CodeCoverage\CodeCoverage.cmd -test: off - artifacts: - path: artifacts\bin\ImageSharp\**\*.nupkg diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index 8ffa2000f8..b9d7ac0b1a 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -12,7 +12,7 @@ cd .. cd .. rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451 --RuntimeIdentifier=win7-x64" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml if %errorlevel% neq 0 exit /b %errorlevel% From 0ceac01a50916c26b0ab4c3b52ff9e6cdc332f70 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 23:06:13 +0000 Subject: [PATCH 11/85] correct runtime --- tests/CodeCoverage/CodeCoverage.cmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index b9d7ac0b1a..2086a94191 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -12,7 +12,7 @@ cd .. cd .. rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451 --RuntimeIdentifier=win7-x64" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451 -r win7-x64" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml if %errorlevel% neq 0 exit /b %errorlevel% From 0553bf26d6948a41682e9e56005d1badbc1978d2 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 23:32:04 +0000 Subject: [PATCH 12/85] build tests for net45 and let codecov run it --- tests/CodeCoverage/CodeCoverage.cmd | 2 +- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index 2086a94191..99c218f02a 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -12,7 +12,7 @@ cd .. cd .. rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net451 -r win7-x64" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net45" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 198f0f33f6..1dfe948ee5 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,6 +1,7 @@  - netcoreapp1.0 + netcoreapp1.0;net45 + win7-x64 True @@ -17,6 +18,11 @@ + + + + + From c9ed0989a5055f77ef4947f30956b4e6e95633c5 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 29 Jan 2017 23:37:38 +0000 Subject: [PATCH 13/85] added new relative path --- tests/ImageSharp.Tests/TestFile.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index 3d66958416..96bf5cbb05 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -137,7 +137,8 @@ namespace ImageSharp.Tests "TestImages/Formats/", // Here for code coverage tests. "tests/ImageSharp.Tests/TestImages/Formats/", // from travis/build script "../../../ImageSharp.Tests/TestImages/Formats/", // from Sandbox46 - "../../../../TestImages/Formats/" + "../../../../TestImages/Formats/", + "../../../TestImages/Formats/" }; directories = directories.SelectMany(x => new[] From 282a77d917a3581ea6ab6def9ff7edd807603c3e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 4 Feb 2017 16:48:35 +0100 Subject: [PATCH 14/85] Sandbox46: It's possible now to use project references instead of dll references --- .../ImageSharp.Sandbox46.csproj | 57 +++++++++++-------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 305fac6369..5391fff902 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -172,29 +172,6 @@ True - - - ..\..\src\ImageSharp\bin\$(Configuration)\net461\ImageSharp.dll - - - ..\..\src\ImageSharp.Drawing\bin\$(Configuration)\net461\ImageSharp.Drawing.dll - - - ..\..\src\ImageSharp.Formats.Bmp\bin\$(Configuration)\net461\ImageSharp.Formats.Bmp.dll - - - ..\..\src\ImageSharp.Formats.Gif\bin\$(Configuration)\net461\ImageSharp.Formats.Gif.dll - - - ..\..\src\ImageSharp.Formats.Jpeg\bin\$(Configuration)\net461\ImageSharp.Formats.Jpeg.dll - - - ..\..\src\ImageSharp.Formats.Png\bin\$(Configuration)\net461\ImageSharp.Formats.Png.dll - - - ..\..\src\ImageSharp.Processing\bin\$(Configuration)\net461\ImageSharp.Processing.dll - - Tests\Drawing\PolygonTests.cs @@ -328,6 +305,40 @@ + + + {2e33181e-6e28-4662-a801-e2e7dc206029} + ImageSharp.Drawing + + + {c77661b9-f793-422e-8e27-ac60ecc5f215} + ImageSharp.Formats.Bmp + + + {27ad4b5f-ecc4-4c63-9ecb-04ec772fdb6f} + ImageSharp.Formats.Gif + + + {7213767c-0003-41ca-ab18-0223cfa7ce4b} + ImageSharp.Formats.Jpeg + + + {556abdcf-ed93-4327-be98-f6815f78b9b8} + ImageSharp.Formats.Png + + + {a623cfe9-9d2b-4528-ad1f-2e834b061134} + ImageSharp.Processing + + + {2aa31a1f-142c-43f4-8687-09abca4b3a26} + ImageSharp + + + {2bf743d8-2a06-412d-96d7-f448f00c5ea5} + ImageSharp.Benchmarks + + From e8285ef6660a64dd6d945849761d470a9b932fb5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Feb 2017 01:17:31 +0100 Subject: [PATCH 15/85] Benchmarks: PixelAccessorVirtualCopy, vectorization --- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 5 + .../Color/Bulk/PixelAccessorVirtualCopy.cs | 129 ++++++++++++++++++ .../Drawing/DrawBeziers.cs | 2 +- .../Drawing/DrawLines.cs | 2 +- .../Drawing/DrawPolygon.cs | 2 +- .../Drawing/FillWithPattern.cs | 2 +- .../General/Vectorization/BitwiseOrUint32.cs | 54 ++++++++ .../General/Vectorization/DivFloat.cs | 54 ++++++++ .../General/Vectorization/DivUInt32.cs | 54 ++++++++ .../General/Vectorization/MulFloat.cs | 54 ++++++++ .../General/Vectorization/MulUInt32.cs | 54 ++++++++ .../Vectorization/ReinterpretUInt32AsFloat.cs | 62 +++++++++ .../ImageSharp.Sandbox46.csproj | 11 +- tests/ImageSharp.Sandbox46/Program.cs | 19 ++- tests/ImageSharp.Sandbox46/app.config | 4 + tests/ImageSharp.Sandbox46/packages.config | 1 + 16 files changed, 501 insertions(+), 8 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index 338f491827..b31ada10bb 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -120,6 +120,11 @@ namespace ImageSharp /// public bool PooledMemory { get; private set; } + /// + /// Gets the pixel buffer array. + /// + public TColor[] PixelBuffer => this.pixelBuffer; + /// /// Gets the pointer to the pixel buffer. /// diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs new file mode 100644 index 0000000000..ed649792fa --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs @@ -0,0 +1,129 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ImageSharp.Benchmarks.Color.Bulk +{ + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using BenchmarkDotNet.Attributes; + + using Color = ImageSharp.Color; + + /// + /// Benchmark to measure the effect of using virtual bulk-copy calls inside PixelAccessor methods + /// + public unsafe class PixelAccessorVirtualCopy + { + abstract class CopyExecutor + { + internal abstract void VirtualCopy(ArrayPointer destination, ArrayPointer source, int count); + } + + class UnsafeCopyExecutor : CopyExecutor + { + [MethodImpl(MethodImplOptions.NoInlining)] + internal override unsafe void VirtualCopy(ArrayPointer destination, ArrayPointer source, int count) + { + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)count*4); + } + } + + private PixelAccessor pixelAccessor; + + private PixelArea area; + + private CopyExecutor executor; + + [Params(64, 256)] + public int Width { get; set; } + + public int Height { get; set; } = 256; + + + [Setup] + public void Setup() + { + this.pixelAccessor = new PixelAccessor(this.Width, this.Height); + this.area = new PixelArea(this.Width / 2, this.Height, ComponentOrder.Xyzw); + this.executor = new UnsafeCopyExecutor(); + } + + [Cleanup] + public void Cleanup() + { + this.pixelAccessor.Dispose(); + this.area.Dispose(); + } + + [Benchmark(Baseline = true)] + public void CopyRawUnsafeInlined() + { + uint byteCount = (uint)this.area.Width * 4; + + int targetX = this.Width / 4; + int targetY = 0; + + for (int y = 0; y < this.Height; y++) + { + byte* source = this.area.PixelBase + (y * this.area.RowStride); + byte* destination = this.GetRowPointer(targetX, targetY + y); + + Unsafe.CopyBlock(destination, source, byteCount); + } + } + + [Benchmark] + public void CopyArrayPointerUnsafeInlined() + { + uint byteCount = (uint)this.area.Width * 4; + + int targetX = this.Width / 4; + int targetY = 0; + + for (int y = 0; y < this.Height; y++) + { + ArrayPointer source = this.GetAreaRow(y); + ArrayPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + } + } + + [Benchmark] + public void CopyArrayPointerUnsafeVirtual() + { + int targetX = this.Width / 4; + int targetY = 0; + + for (int y = 0; y < this.Height; y++) + { + ArrayPointer source = this.GetAreaRow(y); + ArrayPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); + this.executor.VirtualCopy(destination, source, this.area.Width); + } + } + + private byte* GetRowPointer(int x, int y) + { + return (byte*)this.pixelAccessor.DataPointer + (((y * this.pixelAccessor.Width) + x) * Unsafe.SizeOf()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ArrayPointer GetPixelAccessorRow(int x, int y) + { + return new ArrayPointer( + this.pixelAccessor.PixelBuffer, + (void*)this.pixelAccessor.DataPointer, + (y * this.pixelAccessor.Width) + x + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ArrayPointer GetAreaRow(int y) + { + return new ArrayPointer(this.area.Bytes, this.area.PixelBase, y * this.area.RowStride); + } + } +} diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs index c066ac18c7..a10417b90b 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawBeziers.cs @@ -28,7 +28,7 @@ namespace ImageSharp.Benchmarks { graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - var pen = new Pen(Color.HotPink, 10); + var pen = new Pen(System.Drawing.Color.HotPink, 10); graphics.DrawBeziers(pen, new[] { new PointF(10, 500), new PointF(30, 10), diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs index 78f71b6606..146def3637 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawLines.cs @@ -28,7 +28,7 @@ namespace ImageSharp.Benchmarks { graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - var pen = new Pen(Color.HotPink, 10); + var pen = new Pen(System.Drawing.Color.HotPink, 10); graphics.DrawLines(pen, new[] { new PointF(10, 10), new PointF(550, 50), diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs index 88618b9128..e6c1ac0d65 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawPolygon.cs @@ -27,7 +27,7 @@ namespace ImageSharp.Benchmarks { graphics.InterpolationMode = InterpolationMode.Default; graphics.SmoothingMode = SmoothingMode.AntiAlias; - var pen = new Pen(Color.HotPink, 10); + var pen = new Pen(System.Drawing.Color.HotPink, 10); graphics.DrawPolygon(pen, new[] { new PointF(10, 10), new PointF(550, 50), diff --git a/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs b/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs index 718474f1f8..589ac0cd43 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/FillWithPattern.cs @@ -25,7 +25,7 @@ namespace ImageSharp.Benchmarks using (Graphics graphics = Graphics.FromImage(destination)) { graphics.SmoothingMode = SmoothingMode.AntiAlias; - var brush = new HatchBrush(HatchStyle.BackwardDiagonal, Color.HotPink); + var brush = new HatchBrush(HatchStyle.BackwardDiagonal, System.Drawing.Color.HotPink); graphics.FillRectangle(brush, new Rectangle(0,0, 800,800)); // can't find a way to flood fill with a brush } using (MemoryStream ms = new MemoryStream()) diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs new file mode 100644 index 0000000000..dd20e85d5b --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/BitwiseOrUint32.cs @@ -0,0 +1,54 @@ +namespace ImageSharp.Benchmarks.General.Vectorization +{ + using System.Numerics; + + using BenchmarkDotNet.Attributes; + + public class BitwiseOrUInt32 + { + private uint[] input; + + private uint[] result; + + [Params(32)] + public int InputSize { get; set; } + + private uint testValue; + + [Setup] + public void Setup() + { + this.input = new uint[this.InputSize]; + this.result = new uint[this.InputSize]; + this.testValue = 42; + + for (int i = 0; i < this.InputSize; i++) + { + this.input[i] = (uint) i; + } + } + + [Benchmark(Baseline = true)] + public void Standard() + { + uint v = this.testValue; + for (int i = 0; i < this.input.Length; i++) + { + this.result[i] = this.input[i] | v; + } + } + + [Benchmark] + public void Simd() + { + Vector v = new Vector(this.testValue); + + for (int i = 0; i < this.input.Length; i+=Vector.Count) + { + Vector a = new Vector(this.input, i); + a = Vector.BitwiseOr(a, v); + a.CopyTo(this.result, i); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs new file mode 100644 index 0000000000..61582b7dc5 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivFloat.cs @@ -0,0 +1,54 @@ +namespace ImageSharp.Benchmarks.General.Vectorization +{ + using System.Numerics; + + using BenchmarkDotNet.Attributes; + + public class DivFloat + { + private float[] input; + + private float[] result; + + [Params(32)] + public int InputSize { get; set; } + + private float testValue; + + [Setup] + public void Setup() + { + this.input = new float[this.InputSize]; + this.result = new float[this.InputSize]; + this.testValue = 42; + + for (int i = 0; i < this.InputSize; i++) + { + this.input[i] = (uint)i; + } + } + + [Benchmark(Baseline = true)] + public void Standard() + { + float v = this.testValue; + for (int i = 0; i < this.input.Length; i++) + { + this.result[i] = this.input[i] / v; + } + } + + [Benchmark] + public void Simd() + { + Vector v = new Vector(this.testValue); + + for (int i = 0; i < this.input.Length; i += Vector.Count) + { + Vector a = new Vector(this.input, i); + a = a / v; + a.CopyTo(this.result, i); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs new file mode 100644 index 0000000000..75fa03c04b --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/DivUInt32.cs @@ -0,0 +1,54 @@ +namespace ImageSharp.Benchmarks.General.Vectorization +{ + using System.Numerics; + + using BenchmarkDotNet.Attributes; + + public class DivUInt32 + { + private uint[] input; + + private uint[] result; + + [Params(32)] + public int InputSize { get; set; } + + private uint testValue; + + [Setup] + public void Setup() + { + this.input = new uint[this.InputSize]; + this.result = new uint[this.InputSize]; + this.testValue = 42; + + for (int i = 0; i < this.InputSize; i++) + { + this.input[i] = (uint)i; + } + } + + [Benchmark(Baseline = true)] + public void Standard() + { + uint v = this.testValue; + for (int i = 0; i < this.input.Length; i++) + { + this.result[i] = this.input[i] / v; + } + } + + [Benchmark] + public void Simd() + { + Vector v = new Vector(this.testValue); + + for (int i = 0; i < this.input.Length; i += Vector.Count) + { + Vector a = new Vector(this.input, i); + a = a / v; + a.CopyTo(this.result, i); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs new file mode 100644 index 0000000000..151145e128 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulFloat.cs @@ -0,0 +1,54 @@ +namespace ImageSharp.Benchmarks.General.Vectorization +{ + using System.Numerics; + + using BenchmarkDotNet.Attributes; + + public class MulFloat + { + private float[] input; + + private float[] result; + + [Params(32)] + public int InputSize { get; set; } + + private float testValue; + + [Setup] + public void Setup() + { + this.input = new float[this.InputSize]; + this.result = new float[this.InputSize]; + this.testValue = 42; + + for (int i = 0; i < this.InputSize; i++) + { + this.input[i] = (uint)i; + } + } + + [Benchmark(Baseline = true)] + public void Standard() + { + float v = this.testValue; + for (int i = 0; i < this.input.Length; i++) + { + this.result[i] = this.input[i] * v; + } + } + + [Benchmark] + public void Simd() + { + Vector v = new Vector(this.testValue); + + for (int i = 0; i < this.input.Length; i += Vector.Count) + { + Vector a = new Vector(this.input, i); + a = a * v; + a.CopyTo(this.result, i); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs new file mode 100644 index 0000000000..f7d6cf9b9c --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/MulUInt32.cs @@ -0,0 +1,54 @@ +namespace ImageSharp.Benchmarks.General.Vectorization +{ + using System.Numerics; + + using BenchmarkDotNet.Attributes; + + public class MulUInt32 + { + private uint[] input; + + private uint[] result; + + [Params(32)] + public int InputSize { get; set; } + + private uint testValue; + + [Setup] + public void Setup() + { + this.input = new uint[this.InputSize]; + this.result = new uint[this.InputSize]; + this.testValue = 42; + + for (int i = 0; i < this.InputSize; i++) + { + this.input[i] = (uint)i; + } + } + + [Benchmark(Baseline = true)] + public void Standard() + { + uint v = this.testValue; + for (int i = 0; i < this.input.Length; i++) + { + this.result[i] = this.input[i] * v; + } + } + + [Benchmark] + public void Simd() + { + Vector v = new Vector(this.testValue); + + for (int i = 0; i < this.input.Length; i += Vector.Count) + { + Vector a = new Vector(this.input, i); + a = a * v; + a.CopyTo(this.result, i); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs new file mode 100644 index 0000000000..b0ca181cd6 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/ReinterpretUInt32AsFloat.cs @@ -0,0 +1,62 @@ +namespace ImageSharp.Benchmarks.General.Vectorization +{ + using System.Numerics; + using System.Runtime.InteropServices; + + using BenchmarkDotNet.Attributes; + + public class ReinterpretUInt32AsFloat + { + private uint[] input; + + private float[] result; + + [Params(32)] + public int InputSize { get; set; } + + [StructLayout(LayoutKind.Explicit)] + struct UIntFloatUnion + { + [FieldOffset(0)] + public float f; + + [FieldOffset(0)] + public uint i; + } + + + [Setup] + public void Setup() + { + this.input = new uint[this.InputSize]; + this.result = new float[this.InputSize]; + + for (int i = 0; i < this.InputSize; i++) + { + this.input[i] = (uint)i; + } + } + + [Benchmark(Baseline = true)] + public void Standard() + { + UIntFloatUnion u = default(UIntFloatUnion); + for (int i = 0; i < this.input.Length; i++) + { + u.i = this.input[i]; + this.result[i] = u.f; + } + } + + [Benchmark] + public void Simd() + { + for (int i = 0; i < this.input.Length; i += Vector.Count) + { + Vector a = new Vector(this.input, i); + Vector b = Vector.AsVectorSingle(a); + b.CopyTo(this.result, i); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 2444db0312..d1b059f44b 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -109,6 +109,10 @@ ..\..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll True + + ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.3.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll + True + ..\..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net461\System.Security.Cryptography.Algorithms.dll True @@ -202,6 +206,9 @@ + + Benchmarks\PixelAccessorVirtualCopy.cs + Tests\Drawing\PolygonTests.cs @@ -327,9 +334,7 @@ - - - + diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 48219902be..f289ac2db2 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -8,6 +8,7 @@ namespace ImageSharp.Sandbox46 using System; using System.Runtime.DesignerServices; + using ImageSharp.Benchmarks.Color.Bulk; using ImageSharp.Tests; using Xunit.Abstractions; @@ -36,7 +37,23 @@ namespace ImageSharp.Sandbox46 /// public static void Main(string[] args) { - RunDecodeJpegProfilingTests(); + //RunDecodeJpegProfilingTests(); + TestPixelAccessorCopyFromXyzw(); + Console.ReadLine(); + } + + private static void TestPixelAccessorCopyFromXyzw() + { + PixelAccessorVirtualCopy benchmark = new PixelAccessorVirtualCopy(); + benchmark.Width = 64; + benchmark.Setup(); + + benchmark.CopyRawUnsafeInlined(); + benchmark.CopyArrayPointerUnsafe(); + benchmark.CopyArrayPointerVirtualUnsafe(); + benchmark.CopyArrayPointerVirtualMarshal(); + + benchmark.Cleanup(); } private static void RunDecodeJpegProfilingTests() diff --git a/tests/ImageSharp.Sandbox46/app.config b/tests/ImageSharp.Sandbox46/app.config index 5a049c66e3..3328297a54 100644 --- a/tests/ImageSharp.Sandbox46/app.config +++ b/tests/ImageSharp.Sandbox46/app.config @@ -10,6 +10,10 @@ + + + + \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/packages.config b/tests/ImageSharp.Sandbox46/packages.config index 65ad74fa67..426f5f1b52 100644 --- a/tests/ImageSharp.Sandbox46/packages.config +++ b/tests/ImageSharp.Sandbox46/packages.config @@ -29,6 +29,7 @@ + From 6475c52ced12a48cdbddb6a979a97cf831e90ff6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 20 Feb 2017 01:25:11 +0100 Subject: [PATCH 16/85] additional PixelAccessorVirtualCopy Param --- .../Color/Bulk/PixelAccessorVirtualCopy.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs index ed649792fa..9222d6bac2 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs @@ -37,7 +37,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk private CopyExecutor executor; - [Params(64, 256)] + [Params(64, 256, 512)] public int Width { get; set; } public int Height { get; set; } = 256; From ec79e5b43ff6a38aea9c8ef8798f45fa22d0b9e3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 07:56:09 +1100 Subject: [PATCH 17/85] Re export images [skip ci] --- build/icons/imagesharp-logo-128.png | Bin 6622 -> 6569 bytes build/icons/imagesharp-logo-256.png | Bin 14020 -> 13949 bytes build/icons/imagesharp-logo-32.png | Bin 1479 -> 1439 bytes build/icons/imagesharp-logo-512.png | Bin 31672 -> 31256 bytes build/icons/imagesharp-logo-64.png | Bin 3143 -> 3132 bytes build/icons/imagesharp-logo.png | Bin 59600 -> 59646 bytes 6 files changed, 0 insertions(+), 0 deletions(-) diff --git a/build/icons/imagesharp-logo-128.png b/build/icons/imagesharp-logo-128.png index 267e56263209b5b912996d5d1415fbc3ca6687a5..6d05c222cd8e42e2990d05fb33b745a4e1b208c2 100644 GIT binary patch delta 6533 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 diff --git a/build/icons/imagesharp-logo-256.png b/build/icons/imagesharp-logo-256.png index 49fc2e8ed0ce8fec9f39fdf606fd28d42ebb8cd0..fc59b03e1a19171ed999e936e6c6ba908682edb2 100644 GIT binary patch literal 13949 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 VW71AW&=&vz002ovPDHLkV1f)frda?0 delta 1401 zcmV-<1%~>c3&#tPBnkm@Qb$4nuFf3kks%uj!vFvd!vV){sAQ2wD1SFeL_t(oN3B;| zY*bYg?WYlc;MX4qv1I_MNEr%DuyhKQnFCM9Zp zeSLF!dwUCddU~n_9e;8k5`d8Buv|OjS|!)~@$vE5YTEsqkS-9?8o?yR`uqDaG&F?K z(NT$NMIySL8H&WD8Pb8%pr#1ssLLYSDCutYEz z#PIMi!~tezTCOGH+$=?#n00q|+hy`)l2AAjiD<>F5Dte8M}JgCE)5I}%vbc*CZY}z z_cLlnqa(i?1OkC*HvC;(T@EFqH`a^;S!YI|BfJ+d5C%kUW>?9XP1XD|2hOB;6m)`_ zU^%FzWN#W59P2d`X}=x(et&dLlqlK%OyRrOR4>|@fU@};Ox(XXMKWBr-vj*;`Rv_0g7sp>PJK!r!Mx>`x z%gIvH0nx5x2HKet-9X}CQ!$p+uQ#ym%nnpmRUpTmf*en(IN*VMwF7SFQUfP;ZbGnr zcMRdSpMSKR1kW1LZes?-0~HQnm!X01#QDr; zw48)0L5L2tSuMivo4WD(myIzv3-;lOl`aEIR=K1c9yn5+c+$QCCr_Nhg-u&y4s`8$ zUw_LhOebf%gK)&(=Xb_Hq7UP)j{-j`R^tNh~zhqp|R;4URk{d`HS|WV9^1* z<~Rgz?+C7J--Rph?ACG-aUZ4pBsP$8V}E%R2ZCWdeeh?K1NFaN#g9iC4dHl{?Kp-| z{{X^cJ}nm^A0moR#+p}oFg`|BeSlw_U?yfsIo2IGgV7;B-f(_m5`SrN5vq$$Y3E15 zOf!0(z=k+Y9u^3u*~953#pC?nBe>W*isNO!;N{eV*p~JY-u0B>>%BkVa(j<8c$!n$nqc zBH9lMw@oO%{ZCoHM2kXU!c`scuGsqK`9D+Y3yNUgn zM2&Tli6w$5MnFdr>6n?d=!b@L$yRaOnkQmvT~rH^@pH=3a4XRv9$p0R`A#h|Vv=)A zo$vjckj@tIJQ1ms`*uN4iLt(ZdEYAc6>^^^*93phlal@e=-F)Ejpr(H00000NkvXX Hu0mjfSHhoq diff --git a/build/icons/imagesharp-logo-512.png b/build/icons/imagesharp-logo-512.png index e869c516db8be75257a12007161bcc9bdf843078..5d5fb854ead971869824ee645d57ee0aa5f912d2 100644 GIT binary patch literal 31256 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 Y%Ek|rf3bdpO*iC;iq7LoC9AOi1K)L9#sB~S diff --git a/build/icons/imagesharp-logo-64.png b/build/icons/imagesharp-logo-64.png index 518866ffde308c8ea9dbc1b19dba7f7223415305..4e97906e517651723ba1060cb131a9a158278408 100644 GIT binary patch delta 3069 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 LNkvXXu0mjf#9zUF delta 3078 zcmV+h4EgiC7{?fpBnkm@Qb$4nuFf3kks%uj!vFvd!vV){sAQ2wD1Wy}L_t(|Ue%j< zP*v9*#~IUP+NLv|E=ead{i6>Q2N4tz#0?b?d=FBCIvFKu8W&6&mk3&06=D;rMy+VA zCOS~NSq+**jz8Z-0j?|0rkm;3HLycGn`%x8G-zO($k zzjMy-oO|visJ~NlbANMaQ&ZEz#>U2-4Gj&ak!!bZ-Lm3eP=eQN^c!-9@?x0^^3`HlRh<8v-BNrF|4OrLPR3`uok(wENskXNEXJ}{+_GGh4fDp_J*vkz1 zEXpIG3G?Q*wzfVkH9PQ0622RSI|K#;_8j0)2BXmkU0q#ZvwzvZ;cy7CTCHF_51Q{bTvcI7b(ca#!bO5KItgP&D$?U#K zI0t`#J^zuiA?kH^0qtQyQ%*e^(AH9%j!#PF2bM@YM)(WL2FUXwV+IQ92VWrYJZ-+kfEojWd0Knf)} zzNOo@Z&S3FD;lglFG4*Md|n;u>gq;eL3ybgY;)cdG##)5Wd~qTyo;kbQj+IB(VW3T z@+OCZi>Q&o4(&owxaU1{1=G4nuz#HX6F6*v-DfDb%(yq`#!;a?Pe9M) z@=SpTK0Eg4T!BzA-&kIj%bNFOF!4&vJ7Ke-4}KUe@pt8>eI&-xdkXwC!kc+BTqX{@FDgre1$^JimB@b9Ea zd6d`{MB3NKlweJneV2BQ=XX4Q-q5Pu1!@s8O2E@IaCOcsA(dVGv*vNjnYrlx1 zgPHJ)XLRuL5*?%&h;T?vO=TD+MuQ-Pm(*|=5$SAPQ? zt^ErX7lZ{p@%m>wWbvHeeX?2pz1z4Pc5dOqiC`3-=yX7G66m8skYL8M(ZO(Ru2{Gd z%lm(DvB4YY9znGlyg>7xp4hMp9UUFQg6`2W}6 zR8Q~6MabegG#ZNMiG_1a8)7hU`hPxMl{ZPqHk$vZ_yvEKzmgjtX~c6Do>>7UAC@qo zX{qBR2ZZ4F6xji(DM>=o4b!3a^HQ+aRrQL)>bt$l^8)Pr6Xbx){DMCL@Xassh2k0i z(nHc5F4lnJhod9n*!P(;XTqvgt64wxz~^-9-`n}0%^+(Dz9 z>qV-9a06uI7if-%3c2IO(v@QINYu8e5EhR^9K}0DCLjjL&dzoTxaH;LkdcuAsRjci z4IcrCx}l62$fv)EfUkPt>YN2Gws-^G;BmdEy`4sYd_h#e6UoQt3dIuPfurgrjHyYJK%tBgit(DJ|b3FmpdrV2^~O)3V32- z(JzJK3GM(QYT8(@9blL~9TJ0wd2~Qo=on#L?&xy|7>ef$#S?rAaDS$zBzT+xoRsJo zk5iy>>{LxXp3qDI3q@ONB4j_TF z46agkIKw7*Kx^NTmy@Sy-y4(%B1i)hPYHYeZTt`wo6))49@2LuXsxy^EyU z`G0lw+WS1Aht}`{__@+%L)TJ%35@z~v?B!8#H|J&$~d8Up)g3S1hW#EQ-< zE2fw*m;xiMRLW=n1a{oVWV<9IutXJMAUUgSfV@2zmPp#MqF5L4$mu>4&l3$Lthhkg z5H&ndae*Q|id2f`HXR6f*t<*E$Sc^0e9u78@C)?b!CPqRk<-<^PD>p|`(=`u{ePRV z@d#{G-Yjv*5p?d}AMt^DTqK;pYh}nt$-IY?=*44fJPYYk8bgqgbg~ra%a$aXMwV!( zOHkWcef~c}z9ck`ZlHG1ZKlF78FB`#&9r>d=pd(1@Fa0GQV9A?*XYoa_V468!ICCJ z!yW6*cl+M&!%k!j8nqD(?2G>w?qiLH`uh3}gG#tMVFVsR=WWPdbV$8QfIrk@kMG0! zrcvEeGmlQfO;a!mn2$nsphHUVZ#AO%cUz<#^HpJ<6DamA{F{N(OD9#+Pbnzq|Lp_A U%CiqL0RR9107*qoM6N<$f|0P+y8r+H diff --git a/build/icons/imagesharp-logo.png b/build/icons/imagesharp-logo.png index 69b2ae89e01710ceea66322fe34226ff4b200576..ed1c36c5ea23eb1bb21eb0be9d5138575029a3b4 100644 GIT binary patch literal 59646 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 F1OOzA^^5=j literal 59600 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 q6!I4(uGr4 Date: Fri, 24 Feb 2017 09:15:09 +1100 Subject: [PATCH 18/85] Update readme [skip ci] --- README.md | 2 +- build/icons/imagesharp-logo-heading.png | Bin 0 -> 8609 bytes features.md | 16 +++++++++++++--- 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 build/icons/imagesharp-logo-heading.png diff --git a/README.md b/README.md index cbe03bb4e1..9d5c9788a7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ImageSharp +# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. diff --git a/build/icons/imagesharp-logo-heading.png b/build/icons/imagesharp-logo-heading.png new file mode 100644 index 0000000000000000000000000000000000000000..882d8376c075c02a5379255222a9464de01dc086 GIT binary patch literal 8609 zcmb_?_dlFp(6%1IiWVeG2%?un57AjfT|}>8SuI2ty+-dML??P(tQI{=R*6L26}`9U zy}ft7&-4BT@B72<-e*7OGjrxTGuN4!b4O~bD}sm~6JcRtfs~cxwXm?T*MMhlLLA`R z68W$N_`!D7Qk2E28ll?+26#3yYBE?@weiH)7WlyUzO#~nD;5@M&%Y0Lzf*}7@aH2p z1${SdCu=uP3l|ucvxV(DH{N$JH%39;=e#cj1aXZ%U|~HaSC*I2@iN`ba&&(9CZm6S z+5do;p(3NK(#6KpIJ!)MO`vyx%)r6|8}!yI5|5maFuyY}hA}h1IH}`VKMXR(^q?yuG!Rkg{P!7FxkJiwf8O zl9BQGy&G);HwBF+ad1Lqp$3|k(5%ThXeHxq4f9T%2RC7G0#Bha+R@Pw1Oh#=kt!=M z2V`t*Z+{V2Vxc(h@Yr`$Qv>yS;EMNFC1RtZ7zt&El=Bd&6+g2jR0tYyb=!O|_>D<~ zu9g_?&hOni+S$1XiSh?JXl4WOEUA{IfWGoG+j~(X-(X^iN^-Osanrm0vbzQ|5+1O8 zfUzYjTaP?`8#_7vn6^ewPj765o6*w6Rf{b2oT3(yXE~Ej1{dtyQ8Z78ZD|q1oW(Nw z@c*I4ds-x4w1Y$YbxwgL-&p(#qgaZfR+xi?uAPGM-EXjYaD0@87bw0@zYX90DXW z3fzaIv5bW8pQa!x+rue;#HGLX^OIPe2-OGh)h9DX>zV;eE_TB<(-9OD)QnS$Xuy{l z@WtVr+1k#?c+CHn4*u?4k?$8WdjR@HJgCPXKS$|ik*A)_z%(mguB)wya?EAI=SxEw z*antDa%w;@qZRjU%IxH15l>4*L-j+QBvMUjZxnHx0avK z0R(YiT34_ucT^3h)O1g}rKF$SB)^zd0v2-56K3y8&useaw^r;6_rt^8mJG+9)tL@u zH+ajImEZf3)udJ<$xCKG3UbUbVU)(hr-Z?y=q7d}ADVk^khjsn_K_#1u-PY!o*4c_ zIB$-h?PUC$z$VI^-2y&YW?V-=1vL%qi%o5TuXE8?!!KnX4?v!NQqg`}C5!gVf}hlE zOQWqbjJ^;jJ^D8nPaTcf&S9c^%Ld;26}v-S#cEm{OBvZWFHv$~7`7KaQyiyNNTz=e zbC~oGMr>fZ;SQlqZO4}mq*6MuS^->zWK_!ENTA{6IL*2|zj8jP9u|vaBuo!10798% zvn(ruCaPYC4gB|a+YX%}<$Qb=U)ptXk*z(UljF9u(UWj0yu7jZI!L5*uqt(MBd6!9 z+Pz1Y%!y4IUM5Ef%jY~h_TE0J);2Tyv-;x4B#}r6_@V3@W&jmsQO>LDi=&k?_IIyt zce`zFkTE+KeG&|QexD^@vm~h%xQQD9(8jjL@wiVo*IL^Y@6TR#ID0ZTOz@YGl|7aj zfSm5l-{IPr`klOqVsqm>MNL{OJeKW%u5@`8bx#pm&ZR>bo>5dr7PRE@blFbte zhapKqhhhoShf=xpI5{~{gM;fs=>pCRotc?*N%rC*vu@e|P42&J=i%ZKciTwVHhcs1 z;I7d_B6UOQs8bsH&2-y!7b{Wp#|ljED=#>Pe-Xy6f7roDx=b726m(ne?Ljw z$@viBO~{Hb=9H4dh`TyBEN-ta0L&;GQgb5^%W<)YhDe9{hlsR*3ONVn%rbGgL`+VF zLG#X4R|An{KXp>g(P1CyUq@Zx?g2^9Yp3@?fM<}o+@6^DK0m_Jq6aR~1b-!4bm5W`2^Tc@DU=o=XQ_}k5ctT545$lpKmHjrtypPs? z-D-t+-23hRl`8(9h{c|dPR*;-|0_ZmCEQ`iGSsF>k}sra)RWx7!+Ijy?#k9ZrOkR) z+#yltxo3)j+2yvt*;WQ2^5|gCq#rBYVZ^2HMaK#h<0s1X0LQ&VrE=B7t`3tfFE1_o z<0_3Bd8MT0o18d+HFD@6cMZv1o3_7R`HP*e_k=%SK3Q9hWtf`LpKkQn#ZKrgtlhz$+4*s6N< z1RMP1?QM*8$;-#LhpsFB59pa|0YQsT(fgEW!eu?x=98+wl-9mdptq_PdowmighTlX z(c_I{5US(5U-83>@OU%2+q5UDC7H)6uY09*Xm&%d6CVTnM?aUBTVH>SX|Si7!L6(W zEPB_g6mi>5{x3$L!aqv0QaD?kC-vFEdCo)d)wlS4Qz_qL1w};432EW>sN3^w@{EFp z{oWF$|HRU33gOG9@Oa((RQSn4aivlrg`QZeWasMkm8okzH9^dyij*v=_n|JeO8_^e zgof?TG?t5MsAgK}p2k6!1r_ZV&rL$u@84;fxJmzygJl6sqBU4!Ihrfup2yHH#Ego= z2cTw!+iSM#S}YYj;G)6B%*Dk^-Rk!~dg*&UIuo#Df+kD}4JhFi%e5nt$E5h(T%G{A z3j%@Y?(Uv>*Q)k4CplSLM<;a5)Y6i9w%mbl zF!#jN6oaVqLNAS(yzu48wvE3Eq}sGC;r8gKRJ`2I_S^YSK)w+b74@cEcXfRo+}pAG z$tawZzQuYtqt50hlK_>FU6paO%l<;wSCzC3Pmrc`%45Y9fD@lE40J!ujosY?3qN_oOHkiNACBm%P)=@5L0k-49g9Sr?KZ+)DOpv` zpS%ly&1kl5DYNmh)nj)HUB?ChU_w|RwdXXT#TJN9O#S($7q{^(O;<}BCr%6ASJ*u} z>%V`R8yXrS;)6JkCQ0eI>G)F-TuOEqhpVQOD^Gnks;c5)2L%pfy8}}Nh^InsJx}Gr zM`=8ADRiq%ciXnKW|dx1gC6nn@HBYPxk?UzD(7jPg%*B93NJ(AMaN96CfqY-AsIQe`Boh$q5wzbB> znz{9y0CnZ*E{6BHQPQWT)$aY2tO92;8Tz@bGEy~PKhPXwde`| zRs3#cZEcCWPV(7P;!FrJy1;Uww|Ng_{B)Mf*H1 zcJR{vRUzGyB^L|n-KAeNK1M`pa?NoAKhwuF;Kn_E5;BpuIreET@bGkZhDHm$!F;qf zTmbULd9yp)nnr;Dj!ta7mrP+I^S)!ts>Jc-Q@K;U(KKW8a{~#GCBu3v{>WdvH;!G^ z2rf>}(fSQ$r+uETm{`Pc^mUET;imxOREc*#tm+Wt5H)YjX4(SV*S(>&15R#F6>#IF z&dE}CTL$)4Rvx89X*h@eZ@|1xja7kO_6R)hZry7ijN$VdQbWH!pCfcOxmf(jpcOTO zx4}X*{?c`GtIQ#W>BXnQ=^*nT?oLA=u%d@SX#T`87TBpT1{vYmc&c^2brEwtwMYE!o1v@2AzIvCt+^ZN4 z^`6OY4(N8~p(Va$gc}<(;$rE66ciM;j`~?O7!t~Fujm09ts3AP#d8FiReJ>?RvF5o zJ!Ee)^|w;m%)4;>Cx`CSu8VYBfNmBk3ByXs=$iK1$j#5q%*-?*F+olRAAV&KRPS^a zi-C@vXAD^5HKaJ5PqQTb#4df!-yfO!ECk&P7OGK&v-tiJc9`y*s`G>u5FgcDzY-0; zCc|!GZ!IcXZY0#|`P1yG+%`um?BKPRbG&`v1Y}uWVty%UXH)n;;lar8mbNR~wA;KE zc)vSN8k;-nFI8?NfPwZcx9ADP;j91hYl}b1Hq!_g@iRN@a3W{#MRExG`fEK7GhCED z1v=JI@Mu^I0X1BCQhB>`$9P1L4M1WN(`HHKj}+e8WO8bU8yap2RtTIy>U*!RuMZCo%gQ*nzjHwd zrkR&Y26UZcR|TI%J(g>OzOspNNli&1dGhKrI_(i)1M!#r39jmIZ%sb#W&r9 zH3AAkEu>|DegWF<=T|{N~_m4&9`#77H ziVZXKzvvuEEwXi|>fTH-MY4c1h0PvWP_hM0S^H~+sJ?L znzjFN7ZUjs+NPaPooPp4RHp1dmdZ~=AHT0C>qH=CbNw$o!e zq+)`nv#*`0a5Oq{cfN=?or*4lk93Xdb%JGBk*FknRqhK{^(Au^Ky#=AlI;oPq_0E#oC12XxL_ zr(GfU0?vCFv{;DQ8!COVlPzLy_)Nbk9lTrl{Z%EIO{2)`R;F@kNX_=;@|IA2J|&yF zrUNBAcK}DH;Etdm#R3$au$lBs#aT?Rthd7~;N}FNgn9of$5hh&e23yFoDwcKL4Vr% zce7$qjvr$Y$-izAXq&u$TdR#uI=lWVKU2#n{$Yr386jcY&74t96X*SYG2*2Di+ujU z%Dj+vxpRF#AI{Gxtg8^u3GR=`iT6;$rg<~(dj#r5 znin{j-!_|)2>dV&^0FR#uQsawG~kkAcuFB&vdR}k6dw1&%H+BEQnEK+%w4=z=-K=$ zS)bP|>Nj@nYxbef?G>)@G3Q+&Q591f>_>B7=mHwr||tv8w3 za~L-VN1hV>{uZ8q_0U3fR02+i^ROIW$ajd6|| zOd6M+i))N`VtC(ld#2Ip&6|e`4bFh~8Pr)rb;R?vg!dn)pRT{~+mdN$pm@oGh_ zac9R*YRz|!UQcqqI*nfE)iu+)>V_K{<4)x{Tfh-~<^G z3UxfQ6z)ehu?x`}TQb*2}uJ zktb&S0e@awT2+R{Mtl6ub`ICSyH|&hBdrBWF&*MJnwnb04(%!nbVEZIZ^?$|b;Dk> zm(f2-jg?_C+#1OePvbQ))YspDp+7ycclvHizy=1)km3}4UaepAwj9g)^L1U$&Cbe? zWU8Oo5QgiAwds9*eM0t=3ltxb$EpDSS%2Rhn7T@2h1%v2B#Kbrn+X=LiXrz+rk54i z{_xxWX2JB~NGVuXI{-!5jR6Pu^E;Ckqa%I>vK(aSf!VpVYrT+;|KW{yum1korUdgw zf%L+(=7spa*Awf7cu!i`kwz;4S#o*;3Nn%U>C*=T{sHr0mP>+VZnyh%@=;qP0rC#^ z;SB2GT_@6T<5myH`F6j#d03uv2H#TK+SZ>0lsc3dy073$kNCU@CXp((AhUk*!xX&$ z2x22dnQ)E753S?(`aH?>%>)GcMQ^!%e6pQK&Fi_p7c| z`dhD$P~pAd5v@}oUv|#=t~%r0pP}5&KutsA^Ro9)@jKG`977ng9aOUlq~i}CKD=%P z51W&D?k~t-rt!>jO0_*+gCm)eit-o0F`ifV{%XgeCPNh-6L)p-l}i}RvbxPYvvVCOB2mg6By}|!P!kiiFsJ@2@6SO}a|T5_C=@CP_nubasJ_6DGr5)Y zrP}>}`uWw+L=iJ5StSHWF0S)S)kK8$tP)kC;6sH#0!x)+6ws59tpY>8)fa2k)d@*& z(bG!5xDP_7I(1}Vzd7M#` zld+*4_e;&Kl|E1hbet~Vh{VGo9w5zEj&!6t?5WKm`}PV{*LkSNu%id}MzSSlHv0mr z=LXK?rW9V!R=QI!M4^C58UEJMMKZs2 zE^nMt`GZ&@r-B;)iSo&fSuyT8{i_GR}>wk`|IW6iD`t9~PyXI4_+OQ~ zms)K2W1(0bk`oI5y6kHVrPwHY^26WRuOqJ3l)v2Y?#KmJJUxT&i7mB+M`1{#7!KQ* ztk0LT=uy_$&N5FDD5GqGs_E=mFV;h(4GbPBxaT%Bxc9|8qM9L{$yj9g?B-`aD=xYO zrzkP)xPNG=Z|=kR`~MmYnyfJBVc?shI%i8aNdakzjS4^a1%2b*k)w;LC`fGxMxkXw zNYOs_cWw#1bdx3g_AdChCZvjc=t!taXbV%;Ir4ZUPvOK zF4S|!0+KF1;pc^@t7nP^5nIf_2#|`t0|`&TBJbpXPVt8i%Fsom3)mbwjowS&KeiMD z-&d+b1fBFlULnP%B84Ew8G3^>j|ejeu%$}GY;XMRFkoKyC?_&+EvQ$aZOVpGZw7v7+MSZTFBhFrK^IfxkyW{3}lzdn*B_ejbA#rG|Hs?pEhF?9dw z!tS6QjJm9}D2nlAt>w|mEtw0nd!gD6R9l}jg0L;fro{bU*=h>AMELTz6WHnsD;Y5> ze?h!wm%2ID?oj*HS{)<>3n|yDwoAqwG9T#lV=PsvS^NHfjNf3S-li{?n+P8QkIpBkD@@`r^S z3nsa7f_YF=U>KWvrao{wmHKoxBCz?@!nYaYCXsQ~LGHHDdSDX=Q$XfKw@Wm$4HXqb zC8tVX*dAc=0%&^2|wLD#GS!Kg0uoY|$WE*_#=S=D> zN{U8;;VrvBu8xW*>-$jvRG{uhK8eY<5DMCOlM4l3 zeS9I;zd0l(dKLOIZNoS^Bj0RIH!{8(p*trrO?1*-O39BxPOJ-LeP>}W18!d(@piWR zUFp7g1J#j%vz?*{*h7%v@`*2d99PIrl+gS^4$EAe;iJ8sWIiWb6XO#*`{%8~vT01< z6i}6ETUq6lu2pxrQU#xn7GqDT7mG;*F@yj4)1yDjYVY-^`v{__kU0llD!SPuEx=?Z1Zcs-LnO1szVSCk47i zwKg}Sl_&WhCHa+vwP-pkEB^pGi|5HNFr7Q-y7V_pSo7~@TT+F|@F>wm4hgEP4I&L0 zrKP3HvwSSM!oW>&z2{-NOrMo=mLL45?jMgCN9|&D;QHojA>=_Ey?8jU4is7okQdMa zJ=vSjVX8HEZRX&aP6|Wm=9ie=Fx(zu+X`$?xU4LQQ_4ZnW8eAM8RPW zx=7i`FAVR$$f%|mU~_;=G|uzt36i?2V5}_Lk+1(9Jn9`{?1WJ}dPo@+6=H#YdY1$yOUMQSr00Rc7t$*d}O5TISCM). - [x] Bgra32 @@ -133,5 +143,5 @@ We've achieved a lot so far and hope to do a lot more in the future. We're alway - [x] DrawImage - [ ] Gradient brush (Need help) - **DrawingText** - - [x] DrawString (Single variant support just now, no italic,bold) + - [ ] DrawString (In-progress. Single variant support just now, no italic,bold) - Other stuff I haven't thought of. \ No newline at end of file From c85dc30a367cfdfdace3fbc4aa78b5b04ce2111d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 09:20:25 +1100 Subject: [PATCH 19/85] Reduce logo height [skip ci] --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 9d5c9788a7..87708cf05d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. From bc3680cf6c53a093cd5a3081f986dd59c994017b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Feb 2017 09:20:45 +1100 Subject: [PATCH 20/85] Drop px [skip ci] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 87708cf05d..d44a15bfd4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ +# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. From 04a46bc0f846254ed5471865936212ec948a49d0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 25 Feb 2017 13:58:02 +1100 Subject: [PATCH 21/85] Prevent logo squish on mobile [skip ci] --- README.md | 2 +- build/icons/imagesharp-logo-heading.png | Bin 8609 -> 10474 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d44a15bfd4..9d5c9788a7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# ImageSharp +# ImageSharp **ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`. diff --git a/build/icons/imagesharp-logo-heading.png b/build/icons/imagesharp-logo-heading.png index 882d8376c075c02a5379255222a9464de01dc086..b10d367bfda6135939e5ddea15ffed3be31293df 100644 GIT binary patch literal 10474 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 e=J%%uQ=TEM%|`i-dEi_kilVFK=pu literal 8609 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 Date: Sat, 25 Feb 2017 17:46:20 +0000 Subject: [PATCH 22/85] Update SixLabors.Shapes version --- src/ImageSharp.Drawing.Paths/project.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json index bf6b1fae8f..b761233c37 100644 --- a/src/ImageSharp.Drawing.Paths/project.json +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -44,7 +44,7 @@ "ImageSharp.Drawing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-alpha0005", + "SixLabors.Shapes": "0.1.0-alpha0006", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" From 07b5ff4e2d8553ebc6a54e45c22baa1524bde44e Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 25 Feb 2017 17:59:11 +0000 Subject: [PATCH 23/85] Fix drawing on transparent background --- src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs | 1 - src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs | 1 - tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs | 3 +-- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index 913293ff34..95f4ab4726 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -110,7 +110,6 @@ namespace ImageSharp.Drawing.Processors Vector4 sourceVector = color.Color.ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); - finalColor.W = backgroundVector.W; TColor packed = default(TColor); packed.PackFromVector4(finalColor); diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index fed97275d6..4f468c7070 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -202,7 +202,6 @@ namespace ImageSharp.Drawing.Processors Vector4 sourceVector = applicator[x, y].ToVector4(); Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity); - finalColor.W = backgroundVector.W; TColor packed = default(TColor); packed.PackFromVector4(finalColor); diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index a41afd3334..1d3ead81f2 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -32,7 +32,6 @@ namespace ImageSharp.Tests.Drawing using (FileStream output = File.OpenWrite($"{path}/Simple.png")) { image - .BackgroundColor(Color.Blue) .FillPolygon(Color.HotPink, simplePath, new GraphicsOptions(true)) .Save(output); } @@ -45,7 +44,7 @@ namespace ImageSharp.Tests.Drawing Assert.Equal(Color.HotPink, sourcePixels[50, 50]); - Assert.Equal(Color.Blue, sourcePixels[2, 2]); + Assert.NotEqual(Color.HotPink, sourcePixels[2, 2]); } } } From c5b5ea77f89eb5b3cb2f70caee11af9ffd1e8a68 Mon Sep 17 00:00:00 2001 From: Mordechai Zuber Date: Sun, 26 Feb 2017 07:14:01 +0200 Subject: [PATCH 24/85] Wyam documentation --- .gitignore | 3 ++- config.wyam | 4 ++++ input/about.md | 3 +++ theme/index.cshtml | 3 +++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 config.wyam create mode 100644 input/about.md create mode 100644 theme/index.cshtml diff --git a/.gitignore b/.gitignore index 6e291ec94d..d1463bd549 100644 --- a/.gitignore +++ b/.gitignore @@ -212,4 +212,5 @@ artifacts/ **/BenchmarkDotNet.Artifacts/ #CodeCoverage -**/CodeCoverage/* \ No newline at end of file +**/CodeCoverage/* +docs/ diff --git a/config.wyam b/config.wyam new file mode 100644 index 0000000000..3a4b64c540 --- /dev/null +++ b/config.wyam @@ -0,0 +1,4 @@ +#recipe Docs +Settings[Keys.Host] = "imagesharp.org"; +Settings[Keys.Title] = "Image Sharp"; +FileSystem.OutputPath = "./docs"; \ No newline at end of file diff --git a/input/about.md b/input/about.md new file mode 100644 index 0000000000..42739928ae --- /dev/null +++ b/input/about.md @@ -0,0 +1,3 @@ +Title: About This Project +--- +This project is awesome! \ No newline at end of file diff --git a/theme/index.cshtml b/theme/index.cshtml new file mode 100644 index 0000000000..d3656f800b --- /dev/null +++ b/theme/index.cshtml @@ -0,0 +1,3 @@ +Title: Home +--- +Welcome to the documentation for ImageSharp \ No newline at end of file From cceaeb03e6b406dd6ca7017131b98591ba17333d Mon Sep 17 00:00:00 2001 From: Toxantron Date: Sun, 26 Feb 2017 19:02:00 +0100 Subject: [PATCH 25/85] Benchmark running on linux Script for benchmarks Fix from cherry-picking CPU governor not necessary --- .vscode/tasks.json | 7 +++++++ global.json | 4 ++-- tests/ImageSharp.Benchmarks/Program.cs | 5 +++-- tests/ImageSharp.Benchmarks/benchmark.sh | 7 +++++++ tests/ImageSharp.Benchmarks/project.json | 14 +++++++++++++- 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100755 tests/ImageSharp.Benchmarks/benchmark.sh diff --git a/.vscode/tasks.json b/.vscode/tasks.json index aeae5c6ca9..128265ff6f 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -13,6 +13,13 @@ "showOutput": "always", "problemMatcher": "$msCompile" }, + { + "taskName": "build benchmark", + "suppressTaskName": true, + "args": [ "build", "tests/ImageSharp.Benchmarks/project.json", "-f", "netcoreapp1.1", "-c", "Release" ], + "showOutput": "always", + "problemMatcher": "$msCompile" + }, { "taskName": "test", "args": ["tests/ImageSharp.Tests/project.json", "-f", "netcoreapp1.1"], diff --git a/global.json b/global.json index 7346bdc280..c1b6f33634 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { - "projects": [ "src" ], - "sdk": { + "projects": [ "src", "tests" ], + "sdk": { "version": "1.0.0-preview2-003121" } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Program.cs b/tests/ImageSharp.Benchmarks/Program.cs index 8c609f015f..789068426b 100644 --- a/tests/ImageSharp.Benchmarks/Program.cs +++ b/tests/ImageSharp.Benchmarks/Program.cs @@ -6,8 +6,9 @@ namespace ImageSharp.Benchmarks { using BenchmarkDotNet.Running; - + using ImageSharp.Formats; + using System.Reflection; public class Program { @@ -19,7 +20,7 @@ namespace ImageSharp.Benchmarks /// public static void Main(string[] args) { - new BenchmarkSwitcher(typeof(Program).Assembly).Run(args); + new BenchmarkSwitcher(typeof(Program).GetTypeInfo().Assembly).Run(args); } } } diff --git a/tests/ImageSharp.Benchmarks/benchmark.sh b/tests/ImageSharp.Benchmarks/benchmark.sh new file mode 100755 index 0000000000..1966475bca --- /dev/null +++ b/tests/ImageSharp.Benchmarks/benchmark.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# Build in release mode +dotnet build -c Release -f netcoreapp1.1 + +# Run benchmarks +dotnet bin/Release/netcoreapp1.1/ImageSharp.Benchmarks.dll \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/project.json b/tests/ImageSharp.Benchmarks/project.json index 866a36faae..6a8be9f896 100644 --- a/tests/ImageSharp.Benchmarks/project.json +++ b/tests/ImageSharp.Benchmarks/project.json @@ -14,7 +14,6 @@ "allowUnsafe": true }, "dependencies": { - "BenchmarkDotNet.Diagnostics.Windows": "0.10.1", "ImageSharp": { "target": "project" }, @@ -46,10 +45,23 @@ "frameworks": { "net46": { "dependencies": { + "BenchmarkDotNet.Diagnostics.Windows": "0.10.1" }, "frameworkAssemblies": { "System.Drawing": "" } + }, + "netcoreapp1.1": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.1.0-*" + }, + "BenchmarkDotNet": "0.10.2", + "CoreCompat.System.Drawing": "1.0.0-beta006", + "runtime.linux-x64.CoreCompat.System.Drawing": "1.0.0-beta009", + "System.Reflection": "4.3.0" + } } } } From f6823888e17f2d36420d3477738786704ba329e1 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 1 Mar 2017 02:25:33 +0100 Subject: [PATCH 26/85] added "BenchmarkDotNet.Core" dependency --- tests/ImageSharp.Benchmarks/project.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Benchmarks/project.json b/tests/ImageSharp.Benchmarks/project.json index 6a8be9f896..810c666bcc 100644 --- a/tests/ImageSharp.Benchmarks/project.json +++ b/tests/ImageSharp.Benchmarks/project.json @@ -60,7 +60,8 @@ "BenchmarkDotNet": "0.10.2", "CoreCompat.System.Drawing": "1.0.0-beta006", "runtime.linux-x64.CoreCompat.System.Drawing": "1.0.0-beta009", - "System.Reflection": "4.3.0" + "System.Reflection": "4.3.0", + "BenchmarkDotNet.Core": "0.10.2" } } } From daa7b65e86668f08b0fb9eb345f3085f865ce28b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 2 Mar 2017 00:23:49 +0100 Subject: [PATCH 27/85] revert adding explicit "BenchmarkDotNet.Core" dependency --- tests/ImageSharp.Benchmarks/project.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/project.json b/tests/ImageSharp.Benchmarks/project.json index 810c666bcc..6a8be9f896 100644 --- a/tests/ImageSharp.Benchmarks/project.json +++ b/tests/ImageSharp.Benchmarks/project.json @@ -60,8 +60,7 @@ "BenchmarkDotNet": "0.10.2", "CoreCompat.System.Drawing": "1.0.0-beta006", "runtime.linux-x64.CoreCompat.System.Drawing": "1.0.0-beta009", - "System.Reflection": "4.3.0", - "BenchmarkDotNet.Core": "0.10.2" + "System.Reflection": "4.3.0" } } } From a52f6bf1b5065db0d88680c8e6c8a5ace1e6a037 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 2 Mar 2017 01:50:24 +0100 Subject: [PATCH 28/85] BulkPixelOperations skeleton --- src/ImageSharp/Colors/Color.cs | 3 + src/ImageSharp/Colors/PackedPixel/Alpha8.cs | 3 + src/ImageSharp/Colors/PackedPixel/Argb.cs | 3 + src/ImageSharp/Colors/PackedPixel/Bgr565.cs | 3 + src/ImageSharp/Colors/PackedPixel/Bgra4444.cs | 3 + src/ImageSharp/Colors/PackedPixel/Bgra5551.cs | 3 + .../Colors/PackedPixel/BulkPixelOperations.cs | 56 ++++++++++ src/ImageSharp/Colors/PackedPixel/Byte4.cs | 3 + .../Colors/PackedPixel/HalfSingle.cs | 3 + .../Colors/PackedPixel/HalfVector2.cs | 3 + .../Colors/PackedPixel/HalfVector4.cs | 3 + src/ImageSharp/Colors/PackedPixel/IPixel.cs | 4 + .../Colors/PackedPixel/NormalizedByte2.cs | 3 + .../Colors/PackedPixel/NormalizedByte4.cs | 3 + .../Colors/PackedPixel/NormalizedShort2.cs | 3 + .../Colors/PackedPixel/NormalizedShort4.cs | 3 + src/ImageSharp/Colors/PackedPixel/Rg32.cs | 3 + .../Colors/PackedPixel/Rgba1010102.cs | 3 + src/ImageSharp/Colors/PackedPixel/Rgba64.cs | 3 + src/ImageSharp/Colors/PackedPixel/Short2.cs | 3 + src/ImageSharp/Colors/PackedPixel/Short4.cs | 3 + src/ImageSharp/Common/Memory/ArrayPointer.cs | 50 +++++++++ .../General/ArrayCopy.cs | 25 ++++- .../Colors/BulkPixelOperationsTests.cs | 104 ++++++++++++++++++ .../Common/ArrayPointerTests.cs | 94 +++++++++++++++- 25 files changed, 381 insertions(+), 9 deletions(-) create mode 100644 src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs create mode 100644 src/ImageSharp/Common/Memory/ArrayPointer.cs create mode 100644 tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs diff --git a/src/ImageSharp/Colors/Color.cs b/src/ImageSharp/Colors/Color.cs index 469774b348..8a869935c1 100644 --- a/src/ImageSharp/Colors/Color.cs +++ b/src/ImageSharp/Colors/Color.cs @@ -112,6 +112,9 @@ namespace ImageSharp this.packedValue = packed; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + ///

/// Gets or sets the red component. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Alpha8.cs b/src/ImageSharp/Colors/PackedPixel/Alpha8.cs index 485725d71a..1181eb9e47 100644 --- a/src/ImageSharp/Colors/PackedPixel/Alpha8.cs +++ b/src/ImageSharp/Colors/PackedPixel/Alpha8.cs @@ -26,6 +26,9 @@ namespace ImageSharp /// public byte PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Argb.cs b/src/ImageSharp/Colors/PackedPixel/Argb.cs index bef986fb9c..1b97d2337a 100644 --- a/src/ImageSharp/Colors/PackedPixel/Argb.cs +++ b/src/ImageSharp/Colors/PackedPixel/Argb.cs @@ -109,6 +109,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Gets or sets the red component. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs index ebe8d25335..41b2bdc2e0 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs @@ -39,6 +39,9 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs b/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs index ccd6ab1f3e..99659a36bc 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs @@ -38,6 +38,9 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs b/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs index a7a2e899a5..86864fd485 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs @@ -40,6 +40,9 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs new file mode 100644 index 0000000000..c914b3921c --- /dev/null +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs @@ -0,0 +1,56 @@ +namespace ImageSharp +{ + using System.Numerics; + + public unsafe class BulkPixelOperations + where TColor : struct, IPixel + { + public static BulkPixelOperations Instance { get; } = default(TColor).BulkOperations; + + internal virtual void PackFromVector4( + ArrayPointer sourceVectors, + ArrayPointer destColors, + int count) + { + } + + internal virtual void PackToVector4( + ArrayPointer sourceColors, + ArrayPointer destVectors, + int count) + { + } + + internal virtual void PackToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + } + + internal virtual void PackFromXyzBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) + { + } + + internal virtual void PackToXyzwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + } + + internal virtual void PackFromXyzwBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) + { + } + + internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + } + + internal virtual void PackFromZyxBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) + { + } + + internal virtual void PackToZyxwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + } + + internal virtual void PackFromZyxwBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) + { + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Colors/PackedPixel/Byte4.cs b/src/ImageSharp/Colors/PackedPixel/Byte4.cs index 9d5eb9be81..5712027d96 100644 --- a/src/ImageSharp/Colors/PackedPixel/Byte4.cs +++ b/src/ImageSharp/Colors/PackedPixel/Byte4.cs @@ -41,6 +41,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs b/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs index acfa639b70..0bc82c3a61 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs @@ -36,6 +36,9 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs b/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs index e02c226dd7..778f86e0f6 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs @@ -45,6 +45,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); /// /// Compares two objects for equality. diff --git a/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs b/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs index 7c7f640e49..c24553d3f3 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs @@ -49,6 +49,9 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/IPixel.cs b/src/ImageSharp/Colors/PackedPixel/IPixel.cs index 1c3e20a7e4..c17fe86ccf 100644 --- a/src/ImageSharp/Colors/PackedPixel/IPixel.cs +++ b/src/ImageSharp/Colors/PackedPixel/IPixel.cs @@ -15,6 +15,10 @@ namespace ImageSharp public interface IPixel : IPixel, IEquatable where TSelf : struct, IPixel { + /// + /// Gets the instance for this pixel type. + /// + BulkPixelOperations BulkOperations { get; } } /// diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs index 116a681726..d425806c27 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs @@ -51,6 +51,9 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs index 7aaa30c520..cba3f0e863 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs @@ -52,6 +52,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); /// /// Compares two objects for equality. diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs index 2f4ef89d65..4bc7f94277 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs @@ -51,6 +51,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs index 60c5c9805a..c848b72369 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs @@ -53,6 +53,9 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Rg32.cs b/src/ImageSharp/Colors/PackedPixel/Rg32.cs index 9e5e5a711c..9eb2247c9b 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rg32.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rg32.cs @@ -36,6 +36,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs index 95a8d3b978..4f99feb6e5 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs @@ -39,6 +39,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs index 679a55c4e6..a23e57ec3d 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs @@ -38,6 +38,9 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Short2.cs b/src/ImageSharp/Colors/PackedPixel/Short2.cs index 1c1cb28c34..f26e825789 100644 --- a/src/ImageSharp/Colors/PackedPixel/Short2.cs +++ b/src/ImageSharp/Colors/PackedPixel/Short2.cs @@ -51,6 +51,9 @@ namespace ImageSharp /// public uint PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Colors/PackedPixel/Short4.cs b/src/ImageSharp/Colors/PackedPixel/Short4.cs index 2c11a1f8b1..6dc7545e1b 100644 --- a/src/ImageSharp/Colors/PackedPixel/Short4.cs +++ b/src/ImageSharp/Colors/PackedPixel/Short4.cs @@ -53,6 +53,9 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } + /// + public BulkPixelOperations BulkOperations => new BulkPixelOperations(); + /// /// Compares two objects for equality. /// diff --git a/src/ImageSharp/Common/Memory/ArrayPointer.cs b/src/ImageSharp/Common/Memory/ArrayPointer.cs new file mode 100644 index 0000000000..c864d31fd1 --- /dev/null +++ b/src/ImageSharp/Common/Memory/ArrayPointer.cs @@ -0,0 +1,50 @@ +namespace ImageSharp +{ + using System.Runtime.CompilerServices; + + /// + /// Utility methods to + /// + internal static class ArrayPointer + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int count) + where T : struct + { + Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(count)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int countInSource) + where T : struct + { + Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInSource)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int countInDest) + where T : struct + { + Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInDest)); + } + + /// + /// Gets the size of `count` elements in bytes. + /// + /// The count of the elements + /// The size in bytes as int + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int SizeOf(int count) + where T : struct => Unsafe.SizeOf() * count; + + /// + /// Gets the size of `count` elements in bytes as UInt32 + /// + /// The count of the elements + /// The size in bytes as UInt32 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint USizeOf(int count) + where T : struct + => (uint)SizeOf(count); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs b/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs index dddd83e424..72fd6dc248 100644 --- a/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs +++ b/tests/ImageSharp.Benchmarks/General/ArrayCopy.cs @@ -2,22 +2,23 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // - namespace ImageSharp.Benchmarks.General { using System; using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; + [Config(typeof(Config.Short))] public class ArrayCopy { - [Params(100, 1000, 10000)] + [Params(10, 100, 1000, 10000)] public int Count { get; set; } - private byte[] source; + byte[] source; - private byte[] destination; + byte[] destination; [Setup] public void SetUp() @@ -42,6 +43,12 @@ namespace ImageSharp.Benchmarks.General } } + [Benchmark(Description = "Copy using Buffer.BlockCopy()")] + public void CopyUsingBufferBlockCopy() + { + Buffer.BlockCopy(this.source, 0, this.destination, 0, this.Count); + } + [Benchmark(Description = "Copy using Buffer.MemoryCopy")] public unsafe void CopyUsingBufferMemoryCopy() { @@ -51,5 +58,15 @@ namespace ImageSharp.Benchmarks.General Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count); } } + + + [Benchmark(Description = "Copy using Marshal.Copy")] + public unsafe void CopyUsingMarshalCopy() + { + fixed (byte* pinnedDestination = this.destination) + { + Marshal.Copy(this.source, 0, (IntPtr)pinnedDestination, this.Count); + } + } } } diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs new file mode 100644 index 0000000000..413bd94515 --- /dev/null +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -0,0 +1,104 @@ +namespace ImageSharp.Tests.Colors +{ + using System; + + using Xunit; + + public class BulkPixelOperationsTests + { + public class TypeParam + { + } + + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackFromVector4(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackToVector4(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackToXyzBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackFromXyzBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackToXyzwBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackFromXyzwBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackToZyxBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackFromZyxBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackToZyxwBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + + [Theory] + [InlineData(default(TypeParam))] + [InlineData(default(TypeParam))] + public virtual void PackFromZyxwBytes(TypeParam dummy) + where TColor : struct, IPixel + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/ArrayPointerTests.cs b/tests/ImageSharp.Tests/Common/ArrayPointerTests.cs index 076e2512c8..916a109475 100644 --- a/tests/ImageSharp.Tests/Common/ArrayPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/ArrayPointerTests.cs @@ -3,6 +3,7 @@ namespace ImageSharp.Tests.Common { using System; + using System.Runtime.CompilerServices; using Xunit; @@ -10,18 +11,16 @@ namespace ImageSharp.Tests.Common { public struct Foo { -#pragma warning disable CS0414 - private int a; + public int A; - private double b; -#pragma warning restore CS0414 + public double B; internal static Foo[] CreateArray(int size) { Foo[] result = new Foo[size]; for (int i = 0; i < size; i++) { - result[i] = new Foo() { a = i, b = i }; + result[i] = new Foo() { A = i, B = i }; } return result; } @@ -79,5 +78,90 @@ namespace ImageSharp.Tests.Common Assert.Equal((IntPtr)(p + totalOffset), ap.PointerAtOffset); } } + + public class Copy + { + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void GenericToOwnType(int count) + { + Foo[] source = Foo.CreateArray(count + 2); + Foo[] dest = new Foo[count + 5]; + + fixed (Foo* pSource = source) + fixed (Foo* pDest = dest) + { + ArrayPointer apSource = new ArrayPointer(source, pSource); + ArrayPointer apDest = new ArrayPointer(dest, pDest); + + ArrayPointer.Copy(apSource, apDest, count); + } + + Assert.Equal(source[0], dest[0]); + Assert.Equal(source[count-1], dest[count-1]); + Assert.NotEqual(source[count], dest[count]); + } + + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void GenericToBytes(int count) + { + int destCount = count * sizeof(Foo); + Foo[] source = Foo.CreateArray(count + 2); + byte[] dest = new byte[destCount + sizeof(Foo) + 1]; + + fixed (Foo* pSource = source) + fixed (byte* pDest = dest) + { + ArrayPointer apSource = new ArrayPointer(source, pSource); + ArrayPointer apDest = new ArrayPointer(dest, pDest); + + ArrayPointer.Copy(apSource, apDest, count); + } + + Assert.True(ElementsAreEqual(source, dest, 0)); + Assert.True(ElementsAreEqual(source, dest, count - 1)); + Assert.False(ElementsAreEqual(source, dest, count)); + } + + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void BytesToGeneric(int count) + { + int destCount = count * sizeof(Foo); + byte[] source = new byte[destCount + sizeof(Foo) + 1]; + Foo[] dest = Foo.CreateArray(count + 2); + + fixed(byte* pSource = source) + fixed (Foo* pDest = dest) + { + ArrayPointer apSource = new ArrayPointer(source, pSource); + ArrayPointer apDest = new ArrayPointer(dest, pDest); + + ArrayPointer.Copy(apSource, apDest, count); + } + + Assert.True(ElementsAreEqual(dest, source, 0)); + Assert.True(ElementsAreEqual(dest, source, count - 1)); + Assert.False(ElementsAreEqual(dest, source, count)); + } + + private static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index) + { + fixed (Foo* pArray = array) + fixed (byte* pRaw = rawArray) + { + Foo* pCasted = (Foo*)pRaw; + + Foo val1 = pArray[index]; + Foo val2 = pCasted[index]; + + return val1.Equals(val2); + } + } + } } } \ No newline at end of file From 78f997cd06195dabb27f31f3575b801f209287e6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 2 Mar 2017 03:10:00 +0100 Subject: [PATCH 29/85] PinnedBuffer, better tests --- src/ImageSharp/Common/Memory/ArrayPointer.cs | 7 ++ src/ImageSharp/Common/Memory/PinnedBuffer.cs | 109 +++++++++++++++++ src/ImageSharp/Image/PixelPool{TColor}.cs | 1 + .../Colors/BulkPixelOperationsTests.cs | 114 +++++++++++------- .../Common/PinnedBufferTests.cs | 69 +++++++++++ 5 files changed, 257 insertions(+), 43 deletions(-) create mode 100644 src/ImageSharp/Common/Memory/PinnedBuffer.cs create mode 100644 tests/ImageSharp.Tests/Common/PinnedBufferTests.cs diff --git a/src/ImageSharp/Common/Memory/ArrayPointer.cs b/src/ImageSharp/Common/Memory/ArrayPointer.cs index c864d31fd1..56cae35a45 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer.cs +++ b/src/ImageSharp/Common/Memory/ArrayPointer.cs @@ -7,6 +7,13 @@ namespace ImageSharp /// internal static class ArrayPointer { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe ArrayPointer GetArrayPointer(this PinnedBuffer buffer) + where T : struct + { + return new ArrayPointer(buffer.Array, (void*)buffer.Pointer); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int count) where T : struct diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer.cs b/src/ImageSharp/Common/Memory/PinnedBuffer.cs new file mode 100644 index 0000000000..c6e0c7c6f9 --- /dev/null +++ b/src/ImageSharp/Common/Memory/PinnedBuffer.cs @@ -0,0 +1,109 @@ +namespace ImageSharp +{ + using System; + using System.Buffers; + using System.Runtime.InteropServices; + + /// + /// Manages a pinned buffer of 'T' as a Disposable resource. + /// The backing array is either pooled or comes from the outside. + /// TODO: Should replace the pinning/dispose logic in several classes like or ! + /// + /// The value type. + internal class PinnedBuffer : IDisposable + where T : struct + { + private GCHandle handle; + + private bool isBufferRented; + + private bool isDisposed; + + /// + /// TODO: Consider reusing functionality of + /// + private static readonly ArrayPool ArrayPool = ArrayPool.Create(); + + /// + /// Initializes a new instance of the class. + /// + /// The desired count of elements. (Minimum size for ) + public PinnedBuffer(int count) + { + this.Count = count; + this.Array = ArrayPool.Rent(count); + this.isBufferRented = true; + this.Pin(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The array to pin. + public PinnedBuffer(T[] array) + { + this.Count = array.Length; + this.Array = array; + this.Pin(); + } + + /// + /// The count of "relevant" elements. Usually be smaller than 'Array.Length' when is pooled. + /// + public int Count { get; private set; } + + /// + /// The (pinned) array of elements. + /// + public T[] Array { get; private set; } + + /// + /// Pointer to the pinned . + /// + public IntPtr Pointer { get; private set; } + + /// + /// Disposes the instance by unpinning the array, and returning the pooled buffer when necessary. + /// + public void Dispose() + { + if (this.isDisposed) + { + return; + } + this.isDisposed = true; + this.UnPin(); + + if (this.isBufferRented) + { + ArrayPool.Return(this.Array, true); + } + + this.Array = null; + this.Count = 0; + + GC.SuppressFinalize(this); + } + + private void Pin() + { + this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned); + this.Pointer = this.handle.AddrOfPinnedObject(); + } + + private void UnPin() + { + if (this.Pointer == IntPtr.Zero || !this.handle.IsAllocated) + { + return; + } + this.handle.Free(); + this.Pointer = IntPtr.Zero; + } + + ~PinnedBuffer() + { + this.UnPin(); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelPool{TColor}.cs b/src/ImageSharp/Image/PixelPool{TColor}.cs index 8193600daf..ea6dad6b12 100644 --- a/src/ImageSharp/Image/PixelPool{TColor}.cs +++ b/src/ImageSharp/Image/PixelPool{TColor}.cs @@ -8,6 +8,7 @@ namespace ImageSharp using System; using System.Buffers; + // TODO: Consider refactoring this into a more general ClearPool, so we can use it in PinnedBuffer! /// /// Provides a resource pool that enables reusing instances of type . /// diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 413bd94515..f2081b9437 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -1,104 +1,132 @@ namespace ImageSharp.Tests.Colors { using System; + using System.Numerics; using Xunit; - - public class BulkPixelOperationsTests + + public abstract class BulkPixelOperationsTests + where TColor : struct, IPixel { - public class TypeParam + public class ColorPixels : BulkPixelOperationsTests { } + public class ArgbPixels : BulkPixelOperationsTests + { + } + public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; + [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackFromVector4(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackFromVector4(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackToVector4(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackToVector4(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackToXyzBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackToXyzBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackFromXyzBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackFromXyzBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackToXyzwBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackToXyzwBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackFromXyzwBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackFromXyzwBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackToZyxBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackToZyxBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackFromZyxBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackFromZyxBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackToZyxwBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackToZyxwBytes(int count) { throw new NotImplementedException(); } [Theory] - [InlineData(default(TypeParam))] - [InlineData(default(TypeParam))] - public virtual void PackFromZyxwBytes(TypeParam dummy) - where TColor : struct, IPixel + [MemberData(nameof(ArraySizesData))] + public virtual void PackFromZyxwBytes(int count) { throw new NotImplementedException(); } + + public class TestBuffers + { + internal static PinnedBuffer Vector4(int length) + { + Vector4[] result = new Vector4[length]; + Random rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + result[i] = GetVector(rnd); + } + + return new PinnedBuffer(result); + } + + internal static PinnedBuffer Pixel(int length) + { + TColor[] result = new TColor[length]; + + Random rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromVector4(v); + } + + return new PinnedBuffer(result); + } + + private static Vector4 GetVector(Random rnd) + { + return new Vector4( + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble() + ); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs new file mode 100644 index 0000000000..e0783f7165 --- /dev/null +++ b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs @@ -0,0 +1,69 @@ +namespace ImageSharp.Tests.Common +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using Xunit; + + public unsafe class PinnedBufferTests + { + public struct Foo + { + public int A; + + public double B; + } + + [Theory] + [InlineData(42)] + [InlineData(1111)] + public void ConstructWithOwnArray(int count) + { + using (PinnedBuffer buffer = new PinnedBuffer(count)) + { + Assert.NotNull(buffer.Array); + Assert.Equal(count, buffer.Count); + Assert.True(buffer.Array.Length >= count); + + VerifyPointer(buffer); + } + } + + [Theory] + [InlineData(42)] + [InlineData(1111)] + public void ConstructWithExistingArray(int count) + { + Foo[] array = new Foo[count]; + using (PinnedBuffer buffer = new PinnedBuffer(array)) + { + Assert.Equal(array, buffer.Array); + Assert.Equal(count, buffer.Count); + + VerifyPointer(buffer); + } + } + + [Fact] + public void GetArrayPointer() + { + Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } }; + + using (PinnedBuffer buffer = new PinnedBuffer(a)) + { + var arrayPtr = buffer.GetArrayPointer(); + + Assert.Equal(a, arrayPtr.Array); + Assert.Equal(0, arrayPtr.Offset); + Assert.Equal(buffer.Pointer, arrayPtr.PointerAtOffset); + } + } + + private static void VerifyPointer(PinnedBuffer buffer) + { + IntPtr ptr = (IntPtr)Unsafe.AsPointer(ref buffer.Array[0]); + Assert.Equal(ptr, buffer.Pointer); + } + } +} \ No newline at end of file From 61a2b2520d3c16cfe155a8a8e2211c0b9fa9bf2b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 3 Mar 2017 01:58:56 +0100 Subject: [PATCH 30/85] better tests --- .../Colors/BulkPixelOperationsTests.cs | 197 ++++++++++++++---- 1 file changed, 156 insertions(+), 41 deletions(-) diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index f2081b9437..441b9dacae 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -4,9 +4,8 @@ using System.Numerics; using Xunit; - - public abstract class BulkPixelOperationsTests - where TColor : struct, IPixel + + public abstract class BulkPixelOperationsTests { public class ColorPixels : BulkPixelOperationsTests { @@ -15,118 +14,234 @@ public class ArgbPixels : BulkPixelOperationsTests { } + } + public abstract class BulkPixelOperationsTests + where TColor : struct, IPixel + { public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackFromVector4(int count) + public void PackFromVector4(int count) { - throw new NotImplementedException(); + Vector4[] source = CreateVector4TestData(count); + TColor[] expected = new TColor[count]; + + for (int i = 0; i < count; i++) + { + expected[i].PackFromVector4(source[i]); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackFromVector4(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackToVector4(int count) + public void PackToVector4(int count) { - throw new NotImplementedException(); + TColor[] source = CreatePixelTestData(count); + Vector4[] expected = new Vector4[count]; + + for (int i = 0; i < count; i++) + { + expected[i] = source[i].ToVector4(); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackToVector4(s, d, count) + ); } + [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackToXyzBytes(int count) + public void PackFromXyzBytes(int count) { - throw new NotImplementedException(); + byte[] source = CreateByteTestData(count * 3); + TColor[] expected = new TColor[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromBytes(source[i3 + 0], source[i3 + 1], source[i3 + 2], 255); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackFromXyzBytes(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackFromXyzBytes(int count) + public void PackToXyzBytes(int count) { - throw new NotImplementedException(); + TColor[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + source[i].ToXyzBytes(expected, i3); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackToXyzBytes(s, d, count) + ); } + [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackToXyzwBytes(int count) + public void PackToXyzwBytes(int count) { throw new NotImplementedException(); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackFromXyzwBytes(int count) + public void PackFromXyzwBytes(int count) { throw new NotImplementedException(); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackToZyxBytes(int count) + public void PackToZyxBytes(int count) { throw new NotImplementedException(); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackFromZyxBytes(int count) + public void PackFromZyxBytes(int count) { throw new NotImplementedException(); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackToZyxwBytes(int count) + public void PackToZyxwBytes(int count) { throw new NotImplementedException(); } [Theory] [MemberData(nameof(ArraySizesData))] - public virtual void PackFromZyxwBytes(int count) + public void PackFromZyxwBytes(int count) { throw new NotImplementedException(); } - - public class TestBuffers + + private class TestBuffers : IDisposable + where TSource : struct + where TDest : struct { - internal static PinnedBuffer Vector4(int length) + public PinnedBuffer SourceBuffer { get; } + public PinnedBuffer ActualDestBuffer { get; } + public PinnedBuffer ExpectedDestBuffer { get; } + + public ArrayPointer Source => this.SourceBuffer.GetArrayPointer(); + public ArrayPointer ActualDest => this.ActualDestBuffer.GetArrayPointer(); + + public TestBuffers(TSource[] source, TDest[] expectedDest) + { + this.SourceBuffer = new PinnedBuffer(source); + this.ExpectedDestBuffer = new PinnedBuffer(expectedDest); + this.ActualDestBuffer = new PinnedBuffer(expectedDest.Length); + } + + public void Dispose() { - Vector4[] result = new Vector4[length]; - Random rnd = new Random(42); // Deterministic random values + this.SourceBuffer.Dispose(); + this.ActualDestBuffer.Dispose(); + this.ExpectedDestBuffer.Dispose(); + } - for (int i = 0; i < result.Length; i++) + public void Verify() + { + int count = this.ExpectedDestBuffer.Count; + TDest[] expected = this.ExpectedDestBuffer.Array; + TDest[] actual = this.ActualDestBuffer.Array; + for (int i = 0; i < count; i++) { - result[i] = GetVector(rnd); + Assert.Equal(expected[i], actual[i]); } + } + } - return new PinnedBuffer(result); + private static void TestOperation( + TSource[] source, + TDest[] expected, + Action, ArrayPointer, ArrayPointer> action) + where TSource : struct + where TDest : struct + { + using (var buffers = new TestBuffers(source, expected)) + { + action(BulkPixelOperations.Instance, buffers.Source, buffers.ActualDest); + buffers.Verify(); } + } - internal static PinnedBuffer Pixel(int length) + private static Vector4[] CreateVector4TestData(int length) + { + Vector4[] result = new Vector4[length]; + Random rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) { - TColor[] result = new TColor[length]; + result[i] = GetVector(rnd); + } + return result; + } - Random rnd = new Random(42); // Deterministic random values + private static TColor[] CreatePixelTestData(int length) + { + TColor[] result = new TColor[length]; - for (int i = 0; i < result.Length; i++) - { - Vector4 v = GetVector(rnd); - result[i].PackFromVector4(v); - } + Random rnd = new Random(42); // Deterministic random values - return new PinnedBuffer(result); + for (int i = 0; i < result.Length; i++) + { + Vector4 v = GetVector(rnd); + result[i].PackFromVector4(v); } - private static Vector4 GetVector(Random rnd) + return result; + } + + private static byte[] CreateByteTestData(int length) + { + byte[] result = new byte[length]; + Random rnd = new Random(42); // Deterministic random values + + for (int i = 0; i < result.Length; i++) { - return new Vector4( - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble(), - (float)rnd.NextDouble() - ); + result[i] = (byte)rnd.Next(255); } + return result; + } + + private static Vector4 GetVector(Random rnd) + { + return new Vector4( + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble(), + (float)rnd.NextDouble() + ); } } } \ No newline at end of file From 93f169372b89f1b516db41680127aff1d41d0898 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 3 Mar 2017 02:46:26 +0100 Subject: [PATCH 31/85] started implementing operations --- .../Colors/PackedPixel/BulkPixelOperations.cs | 58 ++++++++++++++++++- .../Common/Memory/ArrayPointer{T}.cs | 21 +++++++ .../Colors/BulkPixelOperationsTests.cs | 6 +- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 8 +-- 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs index c914b3921c..a0dceadedc 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs @@ -1,17 +1,34 @@ namespace ImageSharp { + using System; using System.Numerics; + using System.Runtime.CompilerServices; public unsafe class BulkPixelOperations where TColor : struct, IPixel { public static BulkPixelOperations Instance { get; } = default(TColor).BulkOperations; + + private static readonly int ColorSize = Unsafe.SizeOf(); internal virtual void PackFromVector4( ArrayPointer sourceVectors, ArrayPointer destColors, int count) { + Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; + byte* dp = (byte*)destColors; + + for (int i = 0; i < count; i++) + { + Vector4 v = Unsafe.Read(sp); + TColor c = default(TColor); + c.PackFromVector4(v); + Unsafe.Write(dp, c); + + sp++; + dp += ColorSize; + } } internal virtual void PackToVector4( @@ -19,16 +36,51 @@ ArrayPointer destVectors, int count) { + byte* sp = (byte*)sourceColors; + Vector4* dp = (Vector4*)destVectors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = Unsafe.Read(sp); + *dp = c.ToVector4(); + sp += ColorSize; + dp++; + } } - internal virtual void PackToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + internal virtual void PackFromXyzBytes( + ArrayPointer sourceBytes, + ArrayPointer destColors, + int count) { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[0], sp[1], sp[2], 255); + Unsafe.Write(dp, c); + sp += 3; + dp += ColorSize; + } } - internal virtual void PackFromXyzBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) + internal virtual void PackToXyzBytes( + ArrayPointer sourceColors, + ArrayPointer destBytes, int count) { - } + byte* sp = (byte*)sourceColors; + + byte[] dest = destBytes.Array; + for (int i = destBytes.Offset; i < destBytes.Offset + count*3; i+=3) + { + TColor c = Unsafe.Read(sp); + c.ToXyzBytes(dest, i); + } + } + internal virtual void PackToXyzwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { } diff --git a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs b/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs index 1ea7706d44..8f99327ba2 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs @@ -73,6 +73,7 @@ namespace ImageSharp /// /// The offset in number of elements /// The offseted (sliced) ArrayPointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ArrayPointer Slice(int offset) { ArrayPointer result = default(ArrayPointer); @@ -81,5 +82,25 @@ namespace ImageSharp result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * offset); return result; } + + /// + /// Convertes instance to a raw 'void*' pointer + /// + /// The to convert + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator void*(ArrayPointer arrayPointer) + { + return (void*)arrayPointer.PointerAtOffset; + } + + /// + /// Convertes instance to a raw 'byte*' pointer + /// + /// The to convert + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator byte* (ArrayPointer arrayPointer) + { + return (byte*)arrayPointer.PointerAtOffset; + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 441b9dacae..4725823107 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -7,12 +7,14 @@ public abstract class BulkPixelOperationsTests { - public class ColorPixels : BulkPixelOperationsTests + public class Color : BulkPixelOperationsTests { + public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; } - public class ArgbPixels : BulkPixelOperationsTests + public class Argb : BulkPixelOperationsTests { + public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 50e678bf08..12deda577f 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -38,10 +38,10 @@ namespace ImageSharp.Tests { const int ExecutionCount = 30; - if (!Vector.IsHardwareAccelerated) - { - throw new Exception("Vector.IsHardwareAccelerated == false! ('prefer32 bit' enabled?)"); - } + //if (!Vector.IsHardwareAccelerated) + //{ + // throw new Exception("Vector.IsHardwareAccelerated == false! ('prefer32 bit' enabled?)"); + //} string path = TestFile.GetPath(fileName); byte[] bytes = File.ReadAllBytes(path); From 5ae01f1fa8f3b70a9c5f4fa123cfbd3c72fd7c9a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 3 Mar 2017 03:05:06 +0100 Subject: [PATCH 32/85] fixed PackToXyzBytes --- src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs | 1 + tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj | 3 +++ tests/ImageSharp.Sandbox46/Program.cs | 3 --- .../Formats/Jpg/JpegProfilingBenchmarks.cs | 8 ++++---- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs index a0dceadedc..c1f6001af9 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs @@ -78,6 +78,7 @@ { TColor c = Unsafe.Read(sp); c.ToXyzBytes(dest, i); + sp += ColorSize; } } diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index d1b059f44b..ad436793d4 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -209,6 +209,9 @@ Benchmarks\PixelAccessorVirtualCopy.cs + + Tests\Colors\BulkPixelOperationsTests.cs + Tests\Drawing\PolygonTests.cs diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index f289ac2db2..3afd180941 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -49,9 +49,6 @@ namespace ImageSharp.Sandbox46 benchmark.Setup(); benchmark.CopyRawUnsafeInlined(); - benchmark.CopyArrayPointerUnsafe(); - benchmark.CopyArrayPointerVirtualUnsafe(); - benchmark.CopyArrayPointerVirtualMarshal(); benchmark.Cleanup(); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs index 12deda577f..50e678bf08 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs @@ -38,10 +38,10 @@ namespace ImageSharp.Tests { const int ExecutionCount = 30; - //if (!Vector.IsHardwareAccelerated) - //{ - // throw new Exception("Vector.IsHardwareAccelerated == false! ('prefer32 bit' enabled?)"); - //} + if (!Vector.IsHardwareAccelerated) + { + throw new Exception("Vector.IsHardwareAccelerated == false! ('prefer32 bit' enabled?)"); + } string path = TestFile.GetPath(fileName); byte[] bytes = File.ReadAllBytes(path); From 210cecb51d40d15f4d75818375c1f4ed87fea10a Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 4 Mar 2017 18:46:52 +0000 Subject: [PATCH 33/85] update SixLabors.Shapes --- src/ImageSharp.Drawing.Paths/project.json | 2 +- .../Drawing/SolidPolygonTests.cs | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing.Paths/project.json b/src/ImageSharp.Drawing.Paths/project.json index b761233c37..cca2f9bf9c 100644 --- a/src/ImageSharp.Drawing.Paths/project.json +++ b/src/ImageSharp.Drawing.Paths/project.json @@ -44,7 +44,7 @@ "ImageSharp.Drawing": { "target": "project" }, - "SixLabors.Shapes": "0.1.0-alpha0006", + "SixLabors.Shapes": "0.1.0-alpha0007", "StyleCop.Analyzers": { "version": "1.0.0", "type": "build" diff --git a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs index 1d3ead81f2..9c6c6d2342 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs @@ -242,5 +242,32 @@ namespace ImageSharp.Tests.Drawing } } } + + [Fact] + public void ImageShouldBeOverlayedBySquareWithCornerClipped() + { + string path = this.CreateOutputDirectory("Drawing", "FilledPolygons"); + + var config = Configuration.CreateDefaultInstance(); + config.ParallelOptions.MaxDegreeOfParallelism = 1; + using (Image image = new Image(200, 200, config)) + { + using (FileStream output = File.OpenWrite($"{path}/clipped-corner.png")) + { + image + .Fill(Color.Blue) + .FillPolygon(Color.HotPink, new[] + { + new Vector2( 8, 8 ), + new Vector2( 64, 8 ), + new Vector2( 64, 64 ), + new Vector2( 120, 64 ), + new Vector2( 120, 120 ), + new Vector2( 8, 120 ) + } ) + .Save(output); + } + } + } } } From 1d6dae9462b4f75a8f36b9beeae7a6542944d299 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Mar 2017 00:47:40 +0100 Subject: [PATCH 34/85] default BulkPixelOperations passing --- .../Colors/PackedPixel/BulkPixelOperations.cs | 75 ++++++++++-- .../Colors/BulkPixelOperationsTests.cs | 109 +++++++++++++++--- 2 files changed, 162 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs index c1f6001af9..ffa28fc132 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs @@ -71,7 +71,6 @@ ArrayPointer destBytes, int count) { byte* sp = (byte*)sourceColors; - byte[] dest = destBytes.Array; for (int i = destBytes.Offset; i < destBytes.Offset + count*3; i+=3) @@ -81,29 +80,89 @@ sp += ColorSize; } } - - internal virtual void PackToXyzwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) - { - } internal virtual void PackFromXyzwBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]); + Unsafe.Write(dp, c); + sp += 4; + dp += ColorSize; + } } - - internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + + internal virtual void PackToXyzwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) + { + TColor c = Unsafe.Read(sp); + c.ToXyzwBytes(dest, i); + sp += ColorSize; + } } internal virtual void PackFromZyxBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[2], sp[1], sp[0], 255); + Unsafe.Write(dp, c); + sp += 3; + dp += ColorSize; + } } - internal virtual void PackToZyxwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) + { + TColor c = Unsafe.Read(sp); + c.ToZyxBytes(dest, i); + sp += ColorSize; + } } internal virtual void PackFromZyxwBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]); + Unsafe.Write(dp, c); + sp += 4; + dp += ColorSize; + } + } + + internal virtual void PackToZyxwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) + { + TColor c = Unsafe.Read(sp); + c.ToZyxwBytes(dest, i); + sp += ColorSize; + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 4725823107..3682aa78a3 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -21,7 +21,7 @@ public abstract class BulkPixelOperationsTests where TColor : struct, IPixel { - public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; + protected static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; [Theory] [MemberData(nameof(ArraySizesData))] @@ -103,48 +103,129 @@ ); } - [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToXyzwBytes(int count) + public void PackFromXyzwBytes(int count) { - throw new NotImplementedException(); + byte[] source = CreateByteTestData(count * 4); + TColor[] expected = new TColor[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromBytes(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3]); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackFromXyzwBytes(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromXyzwBytes(int count) + public void PackToXyzwBytes(int count) { - throw new NotImplementedException(); + TColor[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToXyzwBytes(expected, i4); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackToXyzwBytes(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToZyxBytes(int count) + public void PackFromZyxBytes(int count) { - throw new NotImplementedException(); + byte[] source = CreateByteTestData(count * 3); + TColor[] expected = new TColor[count]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + + expected[i].PackFromBytes(source[i3 + 2], source[i3 + 1], source[i3 + 0], 255); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackFromZyxBytes(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromZyxBytes(int count) + public void PackToZyxBytes(int count) { - throw new NotImplementedException(); + TColor[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 3]; + + for (int i = 0; i < count; i++) + { + int i3 = i * 3; + source[i].ToZyxBytes(expected, i3); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackToZyxBytes(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToZyxwBytes(int count) + public void PackFromZyxwBytes(int count) { - throw new NotImplementedException(); + byte[] source = CreateByteTestData(count * 4); + TColor[] expected = new TColor[count]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + + expected[i].PackFromBytes(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3]); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackFromZyxwBytes(s, d, count) + ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackFromZyxwBytes(int count) + public void PackToZyxwBytes(int count) { - throw new NotImplementedException(); + TColor[] source = CreatePixelTestData(count); + byte[] expected = new byte[count * 4]; + + for (int i = 0; i < count; i++) + { + int i4 = i * 4; + source[i].ToZyxwBytes(expected, i4); + } + + TestOperation( + source, + expected, + (ops, s, d) => ops.PackToZyxwBytes(s, d, count) + ); } + private class TestBuffers : IDisposable where TSource : struct From 1b3a94f3706f89f2319916aef7aebc082aa6f55a Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 4 Mar 2017 18:34:43 +0000 Subject: [PATCH 35/85] render using sixlabors.fonts --- ImageSharp.sln | 7 + NuGet.config | 1 + src/ImageSharp.Drawing.Text/DrawText.cs | 204 ++++++++++++++++++ src/ImageSharp.Drawing.Text/GlyphBuilder.cs | 126 +++++++++++ .../ImageSharp.Drawing.Text.xproj | 25 +++ .../Properties/AssemblyInfo.cs | 6 + .../TextGraphicsOptions.cs | 68 ++++++ src/ImageSharp.Drawing.Text/project.json | 95 ++++++++ .../ImageSharp.Tests/Drawing/Text/DrawText.cs | 194 +++++++++++++++++ .../Drawing/Text/GlyphBuilder.cs | 68 ++++++ .../Drawing/Text/OutputText.cs | 41 ++++ tests/ImageSharp.Tests/TestFont.cs | 90 ++++++++ .../TestFonts/SixLaborsSampleAB.woff | Bin 0 -> 1352 bytes tests/ImageSharp.Tests/project.json | 3 + 14 files changed, 928 insertions(+) create mode 100644 src/ImageSharp.Drawing.Text/DrawText.cs create mode 100644 src/ImageSharp.Drawing.Text/GlyphBuilder.cs create mode 100644 src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.xproj create mode 100644 src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs create mode 100644 src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs create mode 100644 src/ImageSharp.Drawing.Text/project.json create mode 100644 tests/ImageSharp.Tests/Drawing/Text/DrawText.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs create mode 100644 tests/ImageSharp.Tests/Drawing/Text/OutputText.cs create mode 100644 tests/ImageSharp.Tests/TestFont.cs create mode 100644 tests/ImageSharp.Tests/TestFonts/SixLaborsSampleAB.woff diff --git a/ImageSharp.sln b/ImageSharp.sln index 503a5b8601..1bcea0b929 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -68,6 +68,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tes EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Drawing.Paths", "src\ImageSharp.Drawing.Paths\ImageSharp.Drawing.Paths.xproj", "{E5BD4F96-28A8-410C-8B63-1C5731948549}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ImageSharp.Drawing.Text", "src\ImageSharp.Drawing.Text\ImageSharp.Drawing.Text.xproj", "{329D7698-65BC-48AD-A16F-428682964493}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -122,6 +124,10 @@ Global {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|Any CPU.Build.0 = Debug|Any CPU {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.Build.0 = Release|Any CPU + {329D7698-65BC-48AD-A16F-428682964493}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {329D7698-65BC-48AD-A16F-428682964493}.Debug|Any CPU.Build.0 = Debug|Any CPU + {329D7698-65BC-48AD-A16F-428682964493}.Release|Any CPU.ActiveCfg = Release|Any CPU + {329D7698-65BC-48AD-A16F-428682964493}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -140,5 +146,6 @@ Global {9E574A07-F879-4811-9C41-5CBDC6BAFDB7} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {E5BD4F96-28A8-410C-8B63-1C5731948549} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} + {329D7698-65BC-48AD-A16F-428682964493} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} EndGlobalSection EndGlobal diff --git a/NuGet.config b/NuGet.config index b2c967cc97..322105d4d4 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,6 +1,7 @@  + diff --git a/src/ImageSharp.Drawing.Text/DrawText.cs b/src/ImageSharp.Drawing.Text/DrawText.cs new file mode 100644 index 0000000000..486aa6e40f --- /dev/null +++ b/src/ImageSharp.Drawing.Text/DrawText.cs @@ -0,0 +1,204 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System.Numerics; + + using Drawing; + using Drawing.Brushes; + using Drawing.Pens; + + using SixLabors.Fonts; + using System.Linq; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Draws the text onto the the image filled via the brush. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The color. + /// The location. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, TColor color, Vector2 location) + where TColor : struct, IPixel + { + return source.DrawText(text, font, color, location, TextGraphicsOptions.Default); + } + + /// + /// Draws the text onto the the image filled via the brush. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The color. + /// The location. + /// The options. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, TColor color, Vector2 location, TextGraphicsOptions options) + where TColor : struct, IPixel + { + return source.DrawText(text, font, Brushes.Solid(color), null, location, options); + } + + /// + /// Draws the text onto the the image filled via the brush. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The brush. + /// The location. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, IBrush brush, Vector2 location) + where TColor : struct, IPixel + { + return source.DrawText(text, font, brush, location, TextGraphicsOptions.Default); + } + + /// + /// Draws the text onto the the image filled via the brush. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The brush. + /// The location. + /// The options. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, IBrush brush, Vector2 location, TextGraphicsOptions options) + where TColor : struct, IPixel + { + return source.DrawText(text, font, brush, null, location, options); + } + + /// + /// Draws the text onto the the image outlined via the pen. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The pen. + /// The location. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, IPen pen, Vector2 location) + where TColor : struct, IPixel + { + return source.DrawText(text, font, pen, location, TextGraphicsOptions.Default); + } + + /// + /// Draws the text onto the the image outlined via the pen. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The pen. + /// The location. + /// The options. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, IPen pen, Vector2 location, TextGraphicsOptions options) + where TColor : struct, IPixel + { + return source.DrawText(text, font, null, pen, location, options); + } + + /// + /// Draws the text onto the the image filled via the brush then outlined via the pen. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The brush. + /// The pen. + /// The location. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, Vector2 location) + where TColor : struct, IPixel + { + return source.DrawText(text, font, brush, pen, location, TextGraphicsOptions.Default); + } + + /// + /// Draws the text onto the the image filled via the brush then outlined via the pen. + /// + /// The type of the color. + /// The image this method extends. + /// The text. + /// The font. + /// The brush. + /// The pen. + /// The location. + /// The options. + /// + /// The . + /// + public static Image DrawText(this Image source, string text, Font font, IBrush brush, IPen pen, Vector2 location, TextGraphicsOptions options) + where TColor : struct, IPixel + { + GlyphBuilder glyphBuilder = new GlyphBuilder(location); + + TextRenderer renderer = new TextRenderer(glyphBuilder); + + Vector2 dpi = new Vector2((float)source.MetaData.HorizontalResolution, (float)source.MetaData.VerticalResolution); + FontSpan style = new FontSpan(font) + { + ApplyKerning = options.ApplyKerning, + TabWidth = options.TabWidth + }; + + renderer.RenderText(text, style, dpi); + + System.Collections.Generic.IEnumerable shapesToDraw = glyphBuilder.Paths; + + GraphicsOptions pathOptions = (GraphicsOptions)options; + if (brush != null) + { + foreach (SixLabors.Shapes.IPath s in shapesToDraw) + { + source.Fill(brush, s, pathOptions); + } + } + + if (pen != null) + { + foreach (SixLabors.Shapes.IPath s in shapesToDraw) + { + source.Draw(pen, s, pathOptions); + } + } + + return source; + } + } +} diff --git a/src/ImageSharp.Drawing.Text/GlyphBuilder.cs b/src/ImageSharp.Drawing.Text/GlyphBuilder.cs new file mode 100644 index 0000000000..ac5d01de72 --- /dev/null +++ b/src/ImageSharp.Drawing.Text/GlyphBuilder.cs @@ -0,0 +1,126 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + using System.Collections.Generic; + using System.Numerics; + + using SixLabors.Fonts; + using SixLabors.Shapes; + + /// + /// rendering surface that Fonts can use to generate Shapes. + /// + internal class GlyphBuilder : IGlyphRenderer + { + private readonly PathBuilder builder = new PathBuilder(); + private readonly List paths = new List(); + private Vector2 currentPoint = default(Vector2); + + /// + /// Initializes a new instance of the class. + /// + public GlyphBuilder() + : this(Vector2.Zero) + { + // glyphs are renderd realative to bottom left so invert the Y axis to allow it to render on top left origin surface + this.builder = new PathBuilder(); + } + + /// + /// Initializes a new instance of the class. + /// + /// The origin. + public GlyphBuilder(Vector2 origin) + { + this.builder = new PathBuilder(); + this.builder.SetOrigin(origin); + } + + /// + /// Gets the paths that have been rendered by this. + /// + public IEnumerable Paths => this.paths; + + /// + /// Begins the glyph. + /// + void IGlyphRenderer.BeginGlyph() + { + this.builder.Clear(); + } + + /// + /// Begins the figure. + /// + void IGlyphRenderer.BeginFigure() + { + this.builder.StartFigure(); + } + + /// + /// Draws a cubic bezier from the current point to the + /// + /// The second control point. + /// The third control point. + /// The point. + void IGlyphRenderer.CubicBezierTo(Vector2 secondControlPoint, Vector2 thirdControlPoint, Vector2 point) + { + this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point); + this.currentPoint = point; + } + + /// + /// Ends the glyph. + /// + void IGlyphRenderer.EndGlyph() + { + this.paths.Add(this.builder.Build()); + } + + /// + /// Ends the figure. + /// + void IGlyphRenderer.EndFigure() + { + this.builder.CloseFigure(); + } + + /// + /// Draws a line from the current point to the . + /// + /// The point. + void IGlyphRenderer.LineTo(Vector2 point) + { + this.builder.AddLine(this.currentPoint, point); + this.currentPoint = point; + } + + /// + /// Moves to current point to the supplied vector. + /// + /// The point. + void IGlyphRenderer.MoveTo(Vector2 point) + { + this.builder.StartFigure(); + this.currentPoint = point; + } + + /// + /// Draws a quadratics bezier from the current point to the + /// + /// The second control point. + /// The point. + void IGlyphRenderer.QuadraticBezierTo(Vector2 secondControlPoint, Vector2 point) + { + Vector2 c1 = (((secondControlPoint - this.currentPoint) * 2) / 3) + this.currentPoint; + Vector2 c2 = (((secondControlPoint - point) * 2) / 3) + point; + + this.builder.AddBezier(this.currentPoint, c1, c2, point); + this.currentPoint = point; + } + } +} diff --git a/src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.xproj b/src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.xproj new file mode 100644 index 0000000000..4dfb394cfb --- /dev/null +++ b/src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.xproj @@ -0,0 +1,25 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 329d7698-65bc-48ad-a16f-428682964493 + ImageSharp.Drawing + .\obj + .\bin\ + v4.5.1 + + + 2.0 + + + True + + + + + + \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs b/src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..fba25a9dba --- /dev/null +++ b/src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +// Common values read from `AssemblyInfo.Common.cs` diff --git a/src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs new file mode 100644 index 0000000000..e707ef5e50 --- /dev/null +++ b/src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs @@ -0,0 +1,68 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Drawing +{ + /// + /// Options for influencing the drawing functions. + /// + public struct TextGraphicsOptions + { + /// + /// Represents the default . + /// + public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true); + + /// + /// Whether antialiasing should be applied. + /// + public bool Antialias; + + /// + /// Whether the text should be drawing with kerning enabled. + /// + public bool ApplyKerning; + + /// + /// The number of space widths a tab should lock to. + /// + public float TabWidth; + + /// + /// Initializes a new instance of the struct. + /// + /// If set to true [enable antialiasing]. + public TextGraphicsOptions(bool enableAntialiasing) + { + this.Antialias = enableAntialiasing; + this.ApplyKerning = true; + this.TabWidth = 4; + } + + /// + /// Performs an implicit conversion from to . + /// + /// The options. + /// + /// The result of the conversion. + /// + public static implicit operator TextGraphicsOptions(GraphicsOptions options) + { + return new TextGraphicsOptions(options.Antialias); + } + + /// + /// Performs an explicit conversion from to . + /// + /// The options. + /// + /// The result of the conversion. + /// + public static explicit operator GraphicsOptions(TextGraphicsOptions options) + { + return new GraphicsOptions(options.Antialias); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Text/project.json b/src/ImageSharp.Drawing.Text/project.json new file mode 100644 index 0000000000..f446f91199 --- /dev/null +++ b/src/ImageSharp.Drawing.Text/project.json @@ -0,0 +1,95 @@ +{ + "version": "1.0.0-alpha2-*", + "title": "ImageSharp.Drawing.Text", + "description": "A cross-platform library for the processing of image files; written in C#", + "authors": [ + "James Jackson-South and contributors" + ], + "packOptions": { + "owners": [ + "James Jackson-South and contributors" + ], + "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", + "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", + "iconUrl": "https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png", + "requireLicenseAcceptance": false, + "repository": { + "type": "git", + "url": "https://github.com/JimBobSquarePants/ImageSharp" + }, + "tags": [ + "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" + ] + }, + "buildOptions": { + "allowUnsafe": true, + "xmlDoc": true, + "additionalArguments": [ "/additionalfile:../Shared/stylecop.json", "/ruleset:../../ImageSharp.ruleset" ], + "compile": [ + "../Shared/*.cs" + ] + }, + "configurations": { + "Release": { + "buildOptions": { + "warningsAsErrors": true, + "optimize": true + } + } + }, + "dependencies": { + "ImageSharp": { + "target": "project" + }, + "SixLabors.Fonts": "0.1.0-ci0041", + "ImageSharp.Drawing.Paths": { + "target": "project" + }, + "StyleCop.Analyzers": { + "version": "1.0.0", + "type": "build" + }, + "System.Buffers": "4.0.0", + "System.Runtime.CompilerServices.Unsafe": "4.0.0" + }, + "frameworks": { + "netstandard1.1": { + "dependencies": { + "System.Collections": "4.0.11", + "System.Diagnostics.Debug": "4.0.11", + "System.Diagnostics.Tools": "4.0.1", + "System.IO": "4.1.0", + "System.IO.Compression": "4.1.0", + "System.Linq": "4.1.0", + "System.Numerics.Vectors": "4.1.1", + "System.ObjectModel": "4.0.12", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime.Extensions": "4.1.0", + "System.Runtime.InteropServices": "4.1.0", + "System.Runtime.Numerics": "4.0.1", + "System.Text.Encoding.Extensions": "4.0.11", + "System.Threading": "4.0.11", + "System.Threading.Tasks": "4.0.11", + "System.Threading.Tasks.Parallel": "4.0.1" + } + }, + "net45": { + "dependencies": { + "System.Numerics.Vectors": "4.1.1", + "System.Threading.Tasks.Parallel": "4.0.0" + }, + "frameworkAssemblies": { + "System.Runtime": { "type": "build" } + } + }, + "net461": { + "dependencies": { + "System.Threading.Tasks.Parallel": "4.0.0" + }, + "frameworkAssemblies": { + "System.Runtime": { "type": "build" }, + "System.Numerics": "4.0.0.0" + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs new file mode 100644 index 0000000000..2a2cb8a075 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Text/DrawText.cs @@ -0,0 +1,194 @@ + +namespace ImageSharp.Tests.Drawing.Text +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + using SixLabors.Fonts; + using Paths; + + public class DrawText : IDisposable + { + Color color = Color.HotPink; + SolidBrush brush = Brushes.Solid(Color.HotPink); + IPath path = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] { + new Vector2(10,10), + new Vector2(20,10), + new Vector2(20,10), + new Vector2(30,10), + })); + private ProcessorWatchingImage img; + private readonly FontCollection FontCollection; + private readonly Font Font; + + public DrawText() + { + this.FontCollection = new FontCollection(); + this.Font = FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")); + this.img = new ProcessorWatchingImage(10, 10); + } + + public void Dispose() + { + img.Dispose(); + } + + [Fact] + public void FillsForEachACharachterWhenBrushSetAndNotPen() + { + img.DrawText("123", this.Font, Brushes.Solid(Color.Red), null, Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + [Fact] + public void FillsForEachACharachterWhenBrushSetAndNotPenDefaultOptions() + { + img.DrawText("123", this.Font, Brushes.Solid(Color.Red), null, Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + + [Fact] + public void FillsForEachACharachterWhenBrushSet() + { + img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + [Fact] + public void FillsForEachACharachterWhenBrushSetDefaultOptions() + { + img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + [Fact] + public void FillsForEachACharachterWhenColorSet() + { + img.DrawText("123", this.Font, Color.Red, Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + SolidBrush brush = Assert.IsType>(processor.Brush); + Assert.Equal(Color.Red, brush.Color); + } + + [Fact] + public void FillsForEachACharachterWhenColorSetDefaultOptions() + { + img.DrawText("123", this.Font, Color.Red, Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); + Assert.IsType>(img.ProcessorApplications[0].processor); + FillRegionProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor); + + SolidBrush brush = Assert.IsType>(processor.Brush); + Assert.Equal(Color.Red, brush.Color); + } + + [Fact] + public void DrawForEachACharachterWhenPenSetAndNotBrush() + { + img.DrawText("123", this.Font, null, Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + [Fact] + public void DrawForEachACharachterWhenPenSetAndNotBrushDefaultOptions() + { + img.DrawText("123", this.Font, null, Pens.Dash(Color.Red, 1), Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + + [Fact] + public void DrawForEachACharachterWhenPenSet() + { + img.DrawText("123", this.Font, Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + [Fact] + public void DrawForEachACharachterWhenPenSetDefaultOptions() + { + img.DrawText("123", this.Font, Pens.Dash(Color.Red, 1), Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(3, img.ProcessorApplications.Count); // 3 fills where applied + Assert.IsType>(img.ProcessorApplications[0].processor); + } + + [Fact] + public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSet() + { + img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(6, img.ProcessorApplications.Count); + } + + [Fact] + public void DrawForEachACharachterWhenPenSetAndFillFroEachWhenBrushSetDefaultOptions() + { + img.DrawText("123", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(6, img.ProcessorApplications.Count); + } + + [Fact] + public void BrushAppliesBeforPen() + { + img.DrawText("1", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero, new TextGraphicsOptions(true)); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(2, img.ProcessorApplications.Count); + Assert.IsType>(img.ProcessorApplications[0].processor); + Assert.IsType>(img.ProcessorApplications[1].processor); + } + + [Fact] + public void BrushAppliesBeforPenDefaultOptions() + { + img.DrawText("1", this.Font, Brushes.Solid(Color.Red), Pens.Dash(Color.Red, 1), Vector2.Zero); + + Assert.NotEmpty(img.ProcessorApplications); + Assert.Equal(2, img.ProcessorApplications.Count); + Assert.IsType>(img.ProcessorApplications[0].processor); + Assert.IsType>(img.ProcessorApplications[1].processor); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs b/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs new file mode 100644 index 0000000000..1faa5edd37 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs @@ -0,0 +1,68 @@ + +namespace ImageSharp.Tests.Drawing.Text +{ + using ImageSharp.Drawing; + using SixLabors.Fonts; + using System; + using System.Collections.Generic; + using System.Linq; + using System.Numerics; + using System.Threading.Tasks; + using Xunit; + + public class GlyphBuilderTests + { + [Fact] + public void OriginUsed() + { + // Y axis is inverted as it expects to be drawing for bottom left + var fullBuilder = new GlyphBuilder(new System.Numerics.Vector2(10, 99)); + IGlyphRenderer builder = fullBuilder; + + builder.BeginGlyph(); + builder.BeginFigure(); + builder.MoveTo(new Vector2(0, 0)); + builder.LineTo(new Vector2(0, 10)); // becomes 0, -10 + + builder.CubicBezierTo( + new Vector2(15, 15), // control point - will not be in the final point collection + new Vector2(15, 10), // control point - will not be in the final point collection + new Vector2(10, 10));// becomes 10, -10 + + builder.QuadraticBezierTo( + new Vector2(10, 5), // control point - will not be in the final point collection + new Vector2(10, 0)); + + builder.EndFigure(); + builder.EndGlyph(); + + var points = fullBuilder.Paths.Single().Flatten().Single().Points; + + Assert.Contains(new Vector2(10, 99), points); + Assert.Contains(new Vector2(10, 109), points); + Assert.Contains(new Vector2(20, 99), points); + Assert.Contains(new Vector2(20, 109), points); + } + + [Fact] + public void EachGlypeCausesNewPath() + { + // Y axis is inverted as it expects to be drawing for bottom left + GlyphBuilder fullBuilder = new GlyphBuilder(); + IGlyphRenderer builder = fullBuilder; + for (var i = 0; i < 10; i++) + { + builder.BeginGlyph(); + builder.BeginFigure(); + builder.MoveTo(new Vector2(0, 0)); + builder.LineTo(new Vector2(0, 10)); // becomes 0, -10 + builder.LineTo(new Vector2(10, 10));// becomes 10, -10 + builder.LineTo(new Vector2(10, 0)); + builder.EndFigure(); + builder.EndGlyph(); + } + + Assert.Equal(10, fullBuilder.Paths.Count()); + } + } +} diff --git a/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs b/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs new file mode 100644 index 0000000000..ae007727a5 --- /dev/null +++ b/tests/ImageSharp.Tests/Drawing/Text/OutputText.cs @@ -0,0 +1,41 @@ + +namespace ImageSharp.Tests.Drawing.Text +{ + using System; + using System.IO; + using ImageSharp; + using ImageSharp.Drawing.Brushes; + using Processing; + using System.Collections.Generic; + using Xunit; + using ImageSharp.Drawing; + using System.Numerics; + using SixLabors.Shapes; + using ImageSharp.Drawing.Processors; + using ImageSharp.Drawing.Pens; + using SixLabors.Fonts; + + public class OutputText : FileTestBase + { + private readonly FontCollection FontCollection; + private readonly Font Font; + + public OutputText() + { + this.FontCollection = new FontCollection(); + this.Font = FontCollection.Install(TestFontUtilities.GetPath("SixLaborsSampleAB.woff")); + } + + [Fact] + public void DrawAB() + { + //draws 2 overlapping triangle glyphs twice 1 set on each line + using (var img = new Image(100, 200)) + { + img.Fill(Color.DarkBlue) + .DrawText("AB\nAB", new Font(this.Font, 50), Color.Red, new Vector2(0, 0)); + img.Save($"{this.CreateOutputDirectory("Drawing", "Text")}/AB.png"); + } + } + } +} diff --git a/tests/ImageSharp.Tests/TestFont.cs b/tests/ImageSharp.Tests/TestFont.cs new file mode 100644 index 0000000000..3a5bb2b2c1 --- /dev/null +++ b/tests/ImageSharp.Tests/TestFont.cs @@ -0,0 +1,90 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using System; + using System.Collections.Concurrent; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Reflection; + + /// + /// A test image file. + /// + public static class TestFontUtilities + { + /// + /// The formats directory. + /// + private static readonly string FormatsDirectory = GetFontsDirectory(); + + /// + /// Gets the full qualified path to the file. + /// + /// + /// The file path. + /// + /// + /// The . + /// + public static string GetPath(string file) + { + return Path.Combine(FormatsDirectory, file); + } + + /// + /// Gets the correct path to the formats directory. + /// + /// + /// The . + /// + private static string GetFontsDirectory() + { + List directories = new List< string > { + "TestFonts/", // Here for code coverage tests. + "tests/ImageSharp.Tests/TestFonts/", // from travis/build script + "../../../ImageSharp.Tests/TestFonts/", // from Sandbox46 + "../../../../TestFonts/" + }; + + directories = directories.SelectMany(x => new[] + { + Path.GetFullPath(x) + }).ToList(); + + AddFormatsDirectoryFromTestAssebmlyPath(directories); + + var directory = directories.FirstOrDefault(x => Directory.Exists(x)); + + if(directory != null) + { + return directory; + } + + throw new System.Exception($"Unable to find Fonts directory at any of these locations [{string.Join(", ", directories)}]"); + } + + /// + /// The path returned by Path.GetFullPath(x) can be relative to dotnet framework directory + /// in certain scenarios like dotTrace test profiling. + /// This method calculates and adds the format directory based on the ImageSharp.Tests assembly location. + /// + /// The directories list + private static void AddFormatsDirectoryFromTestAssebmlyPath(List directories) + { + string assemblyLocation = typeof(TestFile).GetTypeInfo().Assembly.Location; + assemblyLocation = Path.GetDirectoryName(assemblyLocation); + + if (assemblyLocation != null) + { + string dirFromAssemblyLocation = Path.Combine(assemblyLocation, "../../../TestFonts/"); + dirFromAssemblyLocation = Path.GetFullPath(dirFromAssemblyLocation); + directories.Add(dirFromAssemblyLocation); + } + } + } +} diff --git a/tests/ImageSharp.Tests/TestFonts/SixLaborsSampleAB.woff b/tests/ImageSharp.Tests/TestFonts/SixLaborsSampleAB.woff new file mode 100644 index 0000000000000000000000000000000000000000..277749dfb19f13eaa020c9e823b76e5a91cf6d49 GIT binary patch literal 1352 zcmZuweM}Qc6rXLoYxyV?DB22##Z=Vus~{3g#k2&9U;{;jLy5ZELR%H23MwKhs}&F| zQ9!LxQ4uKuQ9vtP@~DA#V{0MMKoM$zko!Og&|SzTOz;g$YmIAeAn8$W#H-(0Xy0qyTnb05Z0dpY& zz#gzY3sK_9IBrp#Q1%me=FV{k!h+*OE|9X#(M!7Ng_3>Zm43or4{yU(D}eW5AGY|4oW5X^JVlZcI=vhhqsJe48+$4^ z*bEHK6TCGXO6RUKD7oSIHbd%JWo{Xb?g7k$4zEEL(%aR*IxOdi2gd)J6Nm-X^P}fJ zS&Fo*Ja#4c$i&UdeE)%`r7wmmnA!x!&e-z>r$(3}y=$jy(?tBJ2bad zjW3f;9Ba3F_2;Fd6BbN^u(`KqA5TI(RO=Tf4zwZW5jOu@x(LjhX3rVNg{t$Nw~EP9 ziGd{DJZNutk9lSx=%6-GdXiJH`}F0~Sa#3zsrE^#obnW_W+!g*PzEGUex}|~wY(4a zQZF1j=`7Tun#%e2XZmff;$jH~z1S@XL-M?(MrumtPZ_5~jD&M&nPc*Z%AE)Ztxj>b zQh&oQj{2ZnfRCsiDQ=;^`m+|yGqJm~&WyR1+$mvZ@F>t5BKz?U7}+Ul`qn={7>64w z#wLTd@R~Pp#g^{a6p7%uAyT*XyAvukPP>MI(V-b8SmVF_F1CKnBS}*+>`751W5Hp^ zU=Y(vdtzTNQRmX7ZW!h#!eaO?3`HcH1!j8EY`=rO+Z;F}0JC2h1EAAKVa(iI_rO+A z&?AUidPy zW%He9ANBjS=`Te?ljSR7)-A3jkDb|ZJm*hc`Hk|%`b+B3#qU?H75#=@*)-ukdijTs zP5Xy^UL<`j-g>aF<5j!4YjgZbuJirAtCdgu2A)P2A-+OO!2$2pU1C|NyX239`3)O& zA^A&6-%agnAJoKOoL957v#M^+yoA`=yElLDXs>IjS~uhCBgvQiQdys++j`;6Td8%Z zCWkR=;V;JO+u7q+tr4%=np&4v6?eW%*gYXJ2At*jYadjMn3!(i5py5Q6ITs?PC99A zt1#YgR2fW8MZ-}QJvsNr_#W&p-od`IRSv<9>Q~7+uVOdr(JislQO*1!bLr_*NrC4s zW=xOY73rm_{EnW?N{cD*`|J&F{cDGH*5+x@_&jf+y$1?#grc}yUOnQ%S21c7Dmfuf O(Gpq|B>YSp1mGVP7wVk= literal 0 HcmV?d00001 diff --git a/tests/ImageSharp.Tests/project.json b/tests/ImageSharp.Tests/project.json index 3761bb3858..7c67a5c706 100644 --- a/tests/ImageSharp.Tests/project.json +++ b/tests/ImageSharp.Tests/project.json @@ -31,6 +31,9 @@ "ImageSharp.Drawing.Paths": { "target": "project" }, + "ImageSharp.Drawing.Text": { + "target": "project" + }, "ImageSharp.Formats.Png": { "target": "project" }, From 2bbf85ae91cec7c4045ef18ecc8925f60363befc Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 5 Mar 2017 15:24:03 +0000 Subject: [PATCH 36/85] move to alpha release --- NuGet.config | 1 - src/ImageSharp.Drawing.Text/DrawText.cs | 1 - src/ImageSharp.Drawing.Text/project.json | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/NuGet.config b/NuGet.config index 322105d4d4..b2c967cc97 100644 --- a/NuGet.config +++ b/NuGet.config @@ -1,7 +1,6 @@  - diff --git a/src/ImageSharp.Drawing.Text/DrawText.cs b/src/ImageSharp.Drawing.Text/DrawText.cs index 486aa6e40f..28781fab22 100644 --- a/src/ImageSharp.Drawing.Text/DrawText.cs +++ b/src/ImageSharp.Drawing.Text/DrawText.cs @@ -12,7 +12,6 @@ namespace ImageSharp using Drawing.Pens; using SixLabors.Fonts; - using System.Linq; /// /// Extension methods for the type. diff --git a/src/ImageSharp.Drawing.Text/project.json b/src/ImageSharp.Drawing.Text/project.json index f446f91199..66d0e7d269 100644 --- a/src/ImageSharp.Drawing.Text/project.json +++ b/src/ImageSharp.Drawing.Text/project.json @@ -41,7 +41,7 @@ "ImageSharp": { "target": "project" }, - "SixLabors.Fonts": "0.1.0-ci0041", + "SixLabors.Fonts": "0.1.0-alpha0001", "ImageSharp.Drawing.Paths": { "target": "project" }, From 26b1715bf8854c5d15a3cce98116980075039684 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Mar 2017 17:56:30 +0100 Subject: [PATCH 37/85] PixelAccessor and PixelArea using PinnedBuffer --- .../Colors/PackedPixel/BulkPixelOperations.cs | 168 ------------ .../BulkPixelOperations{TColor}.cs | 256 ++++++++++++++++++ .../Common/Memory/ArrayPointer{T}.cs | 32 +-- src/ImageSharp/Common/Memory/PinnedBuffer.cs | 89 ++++-- .../Common/Memory/PixelDataPool{T}.cs | 60 ++++ src/ImageSharp/Image/ImageBase{TColor}.cs | 10 +- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 139 ++++------ src/ImageSharp/Image/PixelArea{TColor}.cs | 108 ++------ src/ImageSharp/Image/PixelPool{TColor}.cs | 43 --- .../ImageSharp.Sandbox46.csproj | 6 + .../Common/PinnedBufferTests.cs | 25 ++ .../ImageSharp.Tests/Image/PixelPoolTests.cs | 49 +++- 12 files changed, 552 insertions(+), 433 deletions(-) delete mode 100644 src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs create mode 100644 src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs create mode 100644 src/ImageSharp/Common/Memory/PixelDataPool{T}.cs delete mode 100644 src/ImageSharp/Image/PixelPool{TColor}.cs diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs deleted file mode 100644 index ffa28fc132..0000000000 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations.cs +++ /dev/null @@ -1,168 +0,0 @@ -namespace ImageSharp -{ - using System; - using System.Numerics; - using System.Runtime.CompilerServices; - - public unsafe class BulkPixelOperations - where TColor : struct, IPixel - { - public static BulkPixelOperations Instance { get; } = default(TColor).BulkOperations; - - private static readonly int ColorSize = Unsafe.SizeOf(); - - internal virtual void PackFromVector4( - ArrayPointer sourceVectors, - ArrayPointer destColors, - int count) - { - Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; - byte* dp = (byte*)destColors; - - for (int i = 0; i < count; i++) - { - Vector4 v = Unsafe.Read(sp); - TColor c = default(TColor); - c.PackFromVector4(v); - Unsafe.Write(dp, c); - - sp++; - dp += ColorSize; - } - } - - internal virtual void PackToVector4( - ArrayPointer sourceColors, - ArrayPointer destVectors, - int count) - { - byte* sp = (byte*)sourceColors; - Vector4* dp = (Vector4*)destVectors.PointerAtOffset; - - for (int i = 0; i < count; i++) - { - TColor c = Unsafe.Read(sp); - *dp = c.ToVector4(); - sp += ColorSize; - dp++; - } - } - - internal virtual void PackFromXyzBytes( - ArrayPointer sourceBytes, - ArrayPointer destColors, - int count) - { - byte* sp = (byte*)sourceBytes; - byte* dp = (byte*)destColors.PointerAtOffset; - - for (int i = 0; i < count; i++) - { - TColor c = default(TColor); - c.PackFromBytes(sp[0], sp[1], sp[2], 255); - Unsafe.Write(dp, c); - sp += 3; - dp += ColorSize; - } - } - - internal virtual void PackToXyzBytes( - ArrayPointer sourceColors, - ArrayPointer destBytes, int count) - { - byte* sp = (byte*)sourceColors; - byte[] dest = destBytes.Array; - - for (int i = destBytes.Offset; i < destBytes.Offset + count*3; i+=3) - { - TColor c = Unsafe.Read(sp); - c.ToXyzBytes(dest, i); - sp += ColorSize; - } - } - - internal virtual void PackFromXyzwBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) - { - byte* sp = (byte*)sourceBytes; - byte* dp = (byte*)destColors.PointerAtOffset; - - for (int i = 0; i < count; i++) - { - TColor c = default(TColor); - c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]); - Unsafe.Write(dp, c); - sp += 4; - dp += ColorSize; - } - } - - internal virtual void PackToXyzwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) - { - byte* sp = (byte*)sourceColors; - byte[] dest = destBytes.Array; - - for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) - { - TColor c = Unsafe.Read(sp); - c.ToXyzwBytes(dest, i); - sp += ColorSize; - } - } - - internal virtual void PackFromZyxBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) - { - byte* sp = (byte*)sourceBytes; - byte* dp = (byte*)destColors.PointerAtOffset; - - for (int i = 0; i < count; i++) - { - TColor c = default(TColor); - c.PackFromBytes(sp[2], sp[1], sp[0], 255); - Unsafe.Write(dp, c); - sp += 3; - dp += ColorSize; - } - } - - internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) - { - byte* sp = (byte*)sourceColors; - byte[] dest = destBytes.Array; - - for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) - { - TColor c = Unsafe.Read(sp); - c.ToZyxBytes(dest, i); - sp += ColorSize; - } - } - - internal virtual void PackFromZyxwBytes(ArrayPointer sourceBytes, ArrayPointer destColors, int count) - { - byte* sp = (byte*)sourceBytes; - byte* dp = (byte*)destColors.PointerAtOffset; - - for (int i = 0; i < count; i++) - { - TColor c = default(TColor); - c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]); - Unsafe.Write(dp, c); - sp += 4; - dp += ColorSize; - } - } - - internal virtual void PackToZyxwBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) - { - byte* sp = (byte*)sourceColors; - byte[] dest = destBytes.Array; - - for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) - { - TColor c = Unsafe.Read(sp); - c.ToZyxwBytes(dest, i); - sp += ColorSize; - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs new file mode 100644 index 0000000000..557d59a16c --- /dev/null +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs @@ -0,0 +1,256 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System.Numerics; + using System.Runtime.CompilerServices; + + /// + /// A stateless class implementing Strategy Pattern for batched pixel-data conversion operations + /// for pixel buffers of type . + /// + /// The pixel format. + public unsafe class BulkPixelOperations + where TColor : struct, IPixel + { + /// + /// The size of in bytes + /// + private static readonly int ColorSize = Unsafe.SizeOf(); + + /// + /// Gets the global instance for the pixel type + /// + public static BulkPixelOperations Instance { get; } = default(TColor).BulkOperations; + + /// + /// Bulk version of + /// + /// The to the source vectors. + /// The to the destination colors. + /// The number of pixels to convert. + internal virtual void PackFromVector4( + ArrayPointer sourceVectors, + ArrayPointer destColors, + int count) + { + Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; + byte* dp = (byte*)destColors; + + for (int i = 0; i < count; i++) + { + Vector4 v = Unsafe.Read(sp); + TColor c = default(TColor); + c.PackFromVector4(v); + Unsafe.Write(dp, c); + + sp++; + dp += ColorSize; + } + } + + /// + /// Bulk version of . + /// + /// The to the source colors. + /// The to the destination vectors. + /// The number of pixels to convert. + internal virtual void PackToVector4( + ArrayPointer sourceColors, + ArrayPointer destVectors, + int count) + { + byte* sp = (byte*)sourceColors; + Vector4* dp = (Vector4*)destVectors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = Unsafe.Read(sp); + *dp = c.ToVector4(); + sp += ColorSize; + dp++; + } + } + + /// + /// Bulk version of that converts data in . + /// + /// + /// + /// + internal virtual void PackFromXyzBytes( + ArrayPointer sourceBytes, + ArrayPointer destColors, + int count) + { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[0], sp[1], sp[2], 255); + Unsafe.Write(dp, c); + sp += 3; + dp += ColorSize; + } + } + + /// + /// Bulk version of . + /// + /// + /// + /// + internal virtual void PackToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) + { + TColor c = Unsafe.Read(sp); + c.ToXyzBytes(dest, i); + sp += ColorSize; + } + } + + /// + /// Bulk version of that converts data in . + /// + /// + /// + /// + internal virtual void PackFromXyzwBytes( + ArrayPointer sourceBytes, + ArrayPointer destColors, + int count) + { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]); + Unsafe.Write(dp, c); + sp += 4; + dp += ColorSize; + } + } + + /// + /// Bulk version of . + /// + /// + /// + /// + internal virtual void PackToXyzwBytes( + ArrayPointer sourceColors, + ArrayPointer destBytes, + int count) + { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) + { + TColor c = Unsafe.Read(sp); + c.ToXyzwBytes(dest, i); + sp += ColorSize; + } + } + + /// + /// Bulk version of that converts data in . + /// + /// + /// + /// + internal virtual void PackFromZyxBytes( + ArrayPointer sourceBytes, + ArrayPointer destColors, + int count) + { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[2], sp[1], sp[0], 255); + Unsafe.Write(dp, c); + sp += 3; + dp += ColorSize; + } + } + + /// + /// Bulk version of . + /// + /// + /// + /// + internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) + { + TColor c = Unsafe.Read(sp); + c.ToZyxBytes(dest, i); + sp += ColorSize; + } + } + + /// + /// Bulk version of that converts data in . + /// + /// + /// + /// + internal virtual void PackFromZyxwBytes( + ArrayPointer sourceBytes, + ArrayPointer destColors, + int count) + { + byte* sp = (byte*)sourceBytes; + byte* dp = (byte*)destColors.PointerAtOffset; + + for (int i = 0; i < count; i++) + { + TColor c = default(TColor); + c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]); + Unsafe.Write(dp, c); + sp += 4; + dp += ColorSize; + } + } + + /// + /// Bulk version of . + /// + /// + /// + /// + internal virtual void PackToZyxwBytes( + ArrayPointer sourceColors, + ArrayPointer destBytes, + int count) + { + byte* sp = (byte*)sourceColors; + byte[] dest = destBytes.Array; + + for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) + { + TColor c = Unsafe.Read(sp); + c.ToZyxwBytes(dest, i); + sp += ColorSize; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs b/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs index 8f99327ba2..e0b728095e 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs @@ -68,27 +68,12 @@ namespace ImageSharp /// public IntPtr PointerAtOffset { get; private set; } - /// - /// Forms a slice out of the given ArrayPointer, beginning at 'offset'. - /// - /// The offset in number of elements - /// The offseted (sliced) ArrayPointer - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArrayPointer Slice(int offset) - { - ArrayPointer result = default(ArrayPointer); - result.Array = this.Array; - result.Offset = this.Offset + offset; - result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * offset); - return result; - } - /// /// Convertes instance to a raw 'void*' pointer /// /// The to convert [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator void*(ArrayPointer arrayPointer) + public static explicit operator void* (ArrayPointer arrayPointer) { return (void*)arrayPointer.PointerAtOffset; } @@ -102,5 +87,20 @@ namespace ImageSharp { return (byte*)arrayPointer.PointerAtOffset; } + + /// + /// Forms a slice out of the given ArrayPointer, beginning at 'offset'. + /// + /// The offset in number of elements + /// The offseted (sliced) ArrayPointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ArrayPointer Slice(int offset) + { + ArrayPointer result = default(ArrayPointer); + result.Array = this.Array; + result.Offset = this.Offset + offset; + result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * offset); + return result; + } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer.cs b/src/ImageSharp/Common/Memory/PinnedBuffer.cs index c6e0c7c6f9..201d93b56a 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer.cs @@ -5,25 +5,23 @@ namespace ImageSharp using System.Runtime.InteropServices; /// - /// Manages a pinned buffer of 'T' as a Disposable resource. + /// Manages a pinned buffer of value type data 'T' as a Disposable resource. /// The backing array is either pooled or comes from the outside. - /// TODO: Should replace the pinning/dispose logic in several classes like or ! /// /// The value type. internal class PinnedBuffer : IDisposable where T : struct { + /// + /// A handle that allows to access the managed as an unmanaged memory by pinning. + /// private GCHandle handle; - private bool isBufferRented; - - private bool isDisposed; - /// - /// TODO: Consider reusing functionality of + /// A value indicating wether this instance should return the array to the pool. /// - private static readonly ArrayPool ArrayPool = ArrayPool.Create(); - + private bool isPoolingOwner; + /// /// Initializes a new instance of the class. /// @@ -31,8 +29,8 @@ namespace ImageSharp public PinnedBuffer(int count) { this.Count = count; - this.Array = ArrayPool.Rent(count); - this.isBufferRented = true; + this.Array = PixelDataPool.Rent(count); + this.isPoolingOwner = true; this.Pin(); } @@ -48,7 +46,34 @@ namespace ImageSharp } /// - /// The count of "relevant" elements. Usually be smaller than 'Array.Length' when is pooled. + /// Initializes a new instance of the class. + /// + /// The count of "relevant" elements in 'array'. + /// The array to pin. + public PinnedBuffer(int count, T[] array) + { + if (array.Length < count) + { + throw new ArgumentException("Can't initialize a PinnedBuffer with array.Length < count", nameof(array)); + } + this.Count = count; + this.Array = array; + this.Pin(); + } + + ~PinnedBuffer() + { + this.UnPin(); + } + + /// + /// Gets a value indicating whether this instance is disposed, or has lost ownership of . + /// + public bool IsDisposedOrLostArrayOwnership { get; private set; } + + + /// + /// Gets the count of "relevant" elements. Usually be smaller than 'Array.Length' when is pooled. /// public int Count { get; private set; } @@ -58,7 +83,7 @@ namespace ImageSharp public T[] Array { get; private set; } /// - /// Pointer to the pinned . + /// Gets a pointer to the pinned . /// public IntPtr Pointer { get; private set; } @@ -67,16 +92,16 @@ namespace ImageSharp /// public void Dispose() { - if (this.isDisposed) + if (this.IsDisposedOrLostArrayOwnership) { return; } - this.isDisposed = true; + this.IsDisposedOrLostArrayOwnership = true; this.UnPin(); - if (this.isBufferRented) + if (this.isPoolingOwner) { - ArrayPool.Return(this.Array, true); + PixelDataPool.Return(this.Array); } this.Array = null; @@ -85,12 +110,37 @@ namespace ImageSharp GC.SuppressFinalize(this); } + /// + /// Unpins and makes the object "quasi-disposed" so the array is no longer owned by this object. + /// If is rented, it's the callers responsibility to return it to it's pool. (Most likely ) + /// + /// The unpinned + public T[] UnPinAndTakeArrayOwnership() + { + if (this.IsDisposedOrLostArrayOwnership) + { + throw new InvalidOperationException("UnPinAndTakeArrayOwnership() is invalid: either PinnedBuffer is disposed or UnPinAndTakeArrayOwnership() has been called multiple times!"); + } + + this.IsDisposedOrLostArrayOwnership = true; + this.UnPin(); + T[] array = this.Array; + this.Array = null; + return array; + } + + /// + /// Pins . + /// private void Pin() { this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned); this.Pointer = this.handle.AddrOfPinnedObject(); } + /// + /// Unpins . + /// private void UnPin() { if (this.Pointer == IntPtr.Zero || !this.handle.IsAllocated) @@ -100,10 +150,5 @@ namespace ImageSharp this.handle.Free(); this.Pointer = IntPtr.Zero; } - - ~PinnedBuffer() - { - this.UnPin(); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs new file mode 100644 index 0000000000..f6f6a10425 --- /dev/null +++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs @@ -0,0 +1,60 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System; + using System.Buffers; + + /// + /// Provides a resource pool that enables reusing instances of value type arrays . + /// will always return arrays initialized with 'default(T)' + /// + /// The value type. + public static class PixelDataPool + where T : struct + { + /// + /// The used to pool data. + /// + private static readonly ArrayPool ArrayPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); + + /// + /// Rents the pixel array from the pool. + /// + /// The minimum length of the array to return. + /// The + public static T[] Rent(int minimumLength) + { + return ArrayPool.Rent(minimumLength); + } + + /// + /// Returns the rented pixel array back to the pool. + /// + /// The array to return to the buffer pool. + public static void Return(T[] array) + { + ArrayPool.Return(array, true); + } + + /// + /// Heuristically calculates a reasonable maxArrayLength value for the backing . + /// + /// The maxArrayLength value + internal static int CalculateMaxArrayLength() + { + if (typeof(IPixel).IsAssignableFrom(typeof(T))) + { + const int MaximumExpectedImageSize = 16384; + return MaximumExpectedImageSize * MaximumExpectedImageSize; + } + else + { + return int.MaxValue; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index e4b4485c7f..9bd760805a 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -162,13 +162,15 @@ namespace ImageSharp internal void SwapPixelsBuffers(PixelAccessor pixelSource) { Guard.NotNull(pixelSource, nameof(pixelSource)); - Guard.IsTrue(pixelSource.PooledMemory, nameof(pixelSource.PooledMemory), "pixelSource must be using pooled memory"); + + // TODO: This check was useful. We can introduce a bool PixelAccessor.IsBoundToImage to re-introduce it. + // Guard.IsTrue(pixelSource.PooledMemory, nameof(pixelSource.PooledMemory), "pixelSource must be using pooled memory"); int newWidth = pixelSource.Width; int newHeight = pixelSource.Height; // Push my memory into the accessor (which in turn unpins the old puffer ready for the images use) - TColor[] newPixels = pixelSource.ReturnCurrentPixelsAndReplaceThemInternally(this.Width, this.Height, this.pixelBuffer, true); + TColor[] newPixels = pixelSource.ReturnCurrentPixelsAndReplaceThemInternally(this.Width, this.Height, this.pixelBuffer); this.Width = newWidth; this.Height = newHeight; this.pixelBuffer = newPixels; @@ -222,7 +224,7 @@ namespace ImageSharp ///
private void RentPixels() { - this.pixelBuffer = PixelPool.RentPixels(this.Width * this.Height); + this.pixelBuffer = PixelDataPool.Rent(this.Width * this.Height); } /// @@ -230,7 +232,7 @@ namespace ImageSharp /// private void ReturnPixels() { - PixelPool.ReturnPixels(this.pixelBuffer); + PixelDataPool.Return(this.pixelBuffer); this.pixelBuffer = null; } } diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index b31ada10bb..3a3f0f5c7e 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -18,21 +18,11 @@ namespace ImageSharp public unsafe class PixelAccessor : IDisposable where TColor : struct, IPixel { - /// - /// The pointer to the pixel buffer. - /// - private IntPtr dataPointer; - /// /// The position of the first pixel in the image. /// private byte* pixelsBase; - - /// - /// Provides a way to access the pixels from unmanaged memory. - /// - private GCHandle pixelsHandle; - + /// /// A value indicating whether this instance of the given entity has been disposed. /// @@ -45,9 +35,9 @@ namespace ImageSharp private bool isDisposed; /// - /// The pixel buffer + /// The containing the pixel data. /// - private TColor[] pixelBuffer; + private PinnedBuffer pixelBuffer; /// /// Initializes a new instance of the class. @@ -59,7 +49,7 @@ namespace ImageSharp Guard.MustBeGreaterThan(image.Width, 0, "image width"); Guard.MustBeGreaterThan(image.Height, 0, "image height"); - this.SetPixelBufferUnsafe(image.Width, image.Height, image.Pixels, false); + this.SetPixelBufferUnsafe(image.Width, image.Height, image.Pixels); this.ParallelOptions = image.Configuration.ParallelOptions; } @@ -70,7 +60,7 @@ namespace ImageSharp /// The height of the image represented by the pixel buffer. /// The pixel buffer. public PixelAccessor(int width, int height, TColor[] pixels) - : this(width, height, pixels, false) + : this(width, height, new PinnedBuffer(width * height, pixels)) { } @@ -80,7 +70,7 @@ namespace ImageSharp /// The width of the image represented by the pixel buffer. /// The height of the image represented by the pixel buffer. public PixelAccessor(int width, int height) - : this(width, height, PixelPool.RentPixels(width * height), true) + : this(width, height, new PinnedBuffer(width * height)) { } @@ -90,19 +80,18 @@ namespace ImageSharp /// The width of the image represented by the pixel buffer. /// The height of the image represented by the pixel buffer. /// The pixel buffer. - /// if set to true then the is from the thus should be returned once disposed. - private PixelAccessor(int width, int height, TColor[] pixels, bool pooledMemory) + private PixelAccessor(int width, int height, PinnedBuffer pixels) { Guard.NotNull(pixels, nameof(pixels)); Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - if (!(pixels.Length >= width * height)) - { - throw new ArgumentException($"Pixel array must have the length of at least {width * height}."); - } + //if (!(pixels.Length >= width * height)) + //{ + // throw new ArgumentException($"Pixel array must have the length of at least {width * height}."); + //} - this.SetPixelBufferUnsafe(width, height, pixels, pooledMemory); + this.SetPixelBufferUnsafe(width, height, pixels); this.ParallelOptions = Configuration.Default.ParallelOptions; } @@ -114,21 +103,16 @@ namespace ImageSharp { this.Dispose(); } - - /// - /// Gets a value indicating whether the current pixel buffer is from a pooled source. - /// - public bool PooledMemory { get; private set; } - + /// /// Gets the pixel buffer array. /// - public TColor[] PixelBuffer => this.pixelBuffer; + public TColor[] PixelBuffer => this.pixelBuffer.Array; /// /// Gets the pointer to the pixel buffer. /// - public IntPtr DataPointer => this.dataPointer; + public IntPtr DataPointer => this.pixelBuffer.Pointer; /// /// Gets the size of a single pixel in the number of bytes. @@ -246,24 +230,18 @@ namespace ImageSharp { return; } - - this.UnPinPixels(); - + // Note disposing is done. this.isDisposed = true; + this.pixelBuffer.Dispose(); + // This object will be cleaned up by the Dispose method. // Therefore, you should call GC.SuppressFinalize to // take this object off the finalization queue // and prevent finalization code for this object // from executing a second time. GC.SuppressFinalize(this); - - if (this.PooledMemory) - { - PixelPool.ReturnPixels(this.pixelBuffer); - this.pixelBuffer = null; - } } /// @@ -280,13 +258,12 @@ namespace ImageSharp /// The width. /// The height. /// The pixels. - /// If set to true this indicates that the pixel buffer is from a pooled source. /// Returns the old pixel data thats has gust been replaced. - /// If is true then caller is responsible for ensuring is called. - internal TColor[] ReturnCurrentPixelsAndReplaceThemInternally(int width, int height, TColor[] pixels, bool pooledMemory) + /// If is true then caller is responsible for ensuring is called. + internal TColor[] ReturnCurrentPixelsAndReplaceThemInternally(int width, int height, TColor[] pixels) { - TColor[] oldPixels = this.pixelBuffer; - this.SetPixelBufferUnsafe(width, height, pixels, pooledMemory); + TColor[] oldPixels = this.pixelBuffer.UnPinAndTakeArrayOwnership(); + this.SetPixelBufferUnsafe(width, height, pixels); return oldPixels; } @@ -514,53 +491,57 @@ namespace ImageSharp return this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf()); } + private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels) + { + this.SetPixelBufferUnsafe(width, height, new PinnedBuffer(width * height, pixels)); + } + /// /// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!! /// /// The width. /// The height. - /// The pixels. - /// If set to true this indicates that the pixel buffer is from a pooled source. - private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels, bool pooledMemory) + /// The pixel buffer + private void SetPixelBufferUnsafe(int width, int height, PinnedBuffer pixels) { this.pixelBuffer = pixels; - this.PooledMemory = pooledMemory; + this.pixelsBase = (byte*)pixels.Pointer; + this.Width = width; this.Height = height; - this.PinPixels(); this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; } - /// - /// Pins the pixels data. - /// - private void PinPixels() - { - // unpin any old pixels just incase - this.UnPinPixels(); - - this.pixelsHandle = GCHandle.Alloc(this.pixelBuffer, GCHandleType.Pinned); - this.dataPointer = this.pixelsHandle.AddrOfPinnedObject(); - this.pixelsBase = (byte*)this.dataPointer.ToPointer(); - } - - /// - /// Unpins pixels data. - /// - private void UnPinPixels() - { - if (this.pixelsBase != null) - { - if (this.pixelsHandle.IsAllocated) - { - this.pixelsHandle.Free(); - } - - this.dataPointer = IntPtr.Zero; - this.pixelsBase = null; - } - } + ///// + ///// Pins the pixels data. + ///// + //private void PinPixels() + //{ + // // unpin any old pixels just incase + // this.UnPinPixels(); + + // this.pixelsHandle = GCHandle.Alloc(this.pixelBuffer, GCHandleType.Pinned); + // this.dataPointer = this.pixelsHandle.AddrOfPinnedObject(); + // this.pixelsBase = (byte*)this.dataPointer.ToPointer(); + //} + + ///// + ///// Unpins pixels data. + ///// + //private void UnPinPixels() + //{ + // if (this.pixelsBase != null) + // { + // if (this.pixelsHandle.IsAllocated) + // { + // this.pixelsHandle.Free(); + // } + + // this.dataPointer = IntPtr.Zero; + // this.pixelsBase = null; + // } + //} /// /// Copy an area of pixels to the image. diff --git a/src/ImageSharp/Image/PixelArea{TColor}.cs b/src/ImageSharp/Image/PixelArea{TColor}.cs index 77b648ca56..25840167eb 100644 --- a/src/ImageSharp/Image/PixelArea{TColor}.cs +++ b/src/ImageSharp/Image/PixelArea{TColor}.cs @@ -18,21 +18,6 @@ namespace ImageSharp public sealed unsafe class PixelArea : IDisposable where TColor : struct, IPixel { - /// - /// True if was rented from by the constructor - /// - private readonly bool isBufferRented; - - /// - /// Provides a way to access the pixels from unmanaged memory. - /// - private readonly GCHandle pixelsHandle; - - /// - /// The pointer to the pixel buffer. - /// - private IntPtr dataPointer; - /// /// A value indicating whether this instance of the given entity has been disposed. /// @@ -44,6 +29,11 @@ namespace ImageSharp /// private bool isDisposed; + /// + /// The underlying buffer containing the raw pixel data. + /// + private PinnedBuffer byteBuffer; + /// /// Initializes a new instance of the class. /// @@ -76,14 +66,11 @@ namespace ImageSharp this.Height = height; this.ComponentOrder = componentOrder; this.RowStride = width * GetComponentCount(componentOrder); - this.Bytes = bytes; - this.Length = bytes.Length; - this.isBufferRented = false; - this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned); + this.Length = bytes.Length; // TODO: Is this the right value for Length? - // TODO: Why is Resharper warning us about an impure method call? - this.dataPointer = this.pixelsHandle.AddrOfPinnedObject(); - this.PixelBase = (byte*)this.dataPointer.ToPointer(); + this.byteBuffer = new PinnedBuffer(bytes); + + this.PixelBase = (byte*)this.byteBuffer.Pointer; } /// @@ -132,27 +119,15 @@ namespace ImageSharp this.ComponentOrder = componentOrder; this.RowStride = (width * GetComponentCount(componentOrder)) + padding; this.Length = this.RowStride * height; - this.Bytes = BytesPool.Rent(this.Length); - this.isBufferRented = true; - this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned); - // TODO: Why is Resharper warning us about an impure method call? - this.dataPointer = this.pixelsHandle.AddrOfPinnedObject(); - this.PixelBase = (byte*)this.dataPointer.ToPointer(); + this.byteBuffer = new PinnedBuffer(this.Length); + this.PixelBase = (byte*)this.byteBuffer.Pointer; } - - /// - /// Finalizes an instance of the class. - /// - ~PixelArea() - { - this.Dispose(false); - } - + /// /// Gets the data in bytes. /// - public byte[] Bytes { get; } + public byte[] Bytes => this.byteBuffer.Array; /// /// Gets the length of the buffer. @@ -167,7 +142,7 @@ namespace ImageSharp /// /// Gets the pointer to the pixel buffer. /// - public IntPtr DataPointer => this.dataPointer; + public IntPtr DataPointer => this.byteBuffer.Pointer; /// /// Gets the height. @@ -188,26 +163,19 @@ namespace ImageSharp /// Gets the width. /// public int Width { get; } - - /// - /// Gets the pool used to rent bytes, when it's not coming from an external source. - /// - // TODO: Use own pool? - private static ArrayPool BytesPool => ArrayPool.Shared; - + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - this.Dispose(true); + if (this.isDisposed) + { + return; + } - // This object will be cleaned up by the Dispose method. - // Therefore, you should call GC.SuppressFinalize to - // take this object off the finalization queue - // and prevent finalization code for this object - // from executing a second time. - GC.SuppressFinalize(this); + this.byteBuffer.Dispose(); + this.isDisposed = true; } /// @@ -281,38 +249,6 @@ namespace ImageSharp nameof(bytes), $"Invalid byte array length. Length {bytes.Length}; Should be {requiredLength}."); } - } - - /// - /// Disposes the object and frees resources for the Garbage Collector. - /// - /// If true, the object gets disposed. - private void Dispose(bool disposing) - { - if (this.isDisposed) - { - return; - } - - if (this.PixelBase == null) - { - return; - } - - if (this.pixelsHandle.IsAllocated) - { - this.pixelsHandle.Free(); - } - - if (disposing && this.isBufferRented) - { - BytesPool.Return(this.Bytes); - } - - this.dataPointer = IntPtr.Zero; - this.PixelBase = null; - - this.isDisposed = true; - } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelPool{TColor}.cs b/src/ImageSharp/Image/PixelPool{TColor}.cs deleted file mode 100644 index ea6dad6b12..0000000000 --- a/src/ImageSharp/Image/PixelPool{TColor}.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - using System.Buffers; - - // TODO: Consider refactoring this into a more general ClearPool, so we can use it in PinnedBuffer! - /// - /// Provides a resource pool that enables reusing instances of type . - /// - /// The pixel format. - public static class PixelPool - where TColor : struct, IPixel - { - /// - /// The used to pool data. TODO: Choose sensible default size and count - /// - private static readonly ArrayPool ArrayPool = ArrayPool.Create(int.MaxValue, 50); - - /// - /// Rents the pixel array from the pool. - /// - /// The minimum length of the array to return. - /// The - public static TColor[] RentPixels(int minimumLength) - { - return ArrayPool.Rent(minimumLength); - } - - /// - /// Returns the rented pixel array back to the pool. - /// - /// The array to return to the buffer pool. - public static void ReturnPixels(TColor[] array) - { - ArrayPool.Return(array, true); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index ad436793d4..094eedb180 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -212,6 +212,9 @@ Tests\Colors\BulkPixelOperationsTests.cs + + Tests\Common\PinnedBufferTests.cs + Tests\Drawing\PolygonTests.cs @@ -248,6 +251,9 @@ Tests\Formats\Jpg\YCbCrImageTests.cs + + Tests\Image\PixelPoolTests.cs + Tests\MetaData\ImagePropertyTests.cs diff --git a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs index e0783f7165..c5eb2a5103 100644 --- a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs +++ b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs @@ -22,6 +22,7 @@ { using (PinnedBuffer buffer = new PinnedBuffer(count)) { + Assert.False(buffer.IsDisposedOrLostArrayOwnership); Assert.NotNull(buffer.Array); Assert.Equal(count, buffer.Count); Assert.True(buffer.Array.Length >= count); @@ -38,6 +39,7 @@ Foo[] array = new Foo[count]; using (PinnedBuffer buffer = new PinnedBuffer(array)) { + Assert.False(buffer.IsDisposedOrLostArrayOwnership); Assert.Equal(array, buffer.Array); Assert.Equal(count, buffer.Count); @@ -45,6 +47,15 @@ } } + [Fact] + public void Dispose() + { + PinnedBuffer buffer = new PinnedBuffer(42); + buffer.Dispose(); + + Assert.True(buffer.IsDisposedOrLostArrayOwnership); + } + [Fact] public void GetArrayPointer() { @@ -60,6 +71,20 @@ } } + [Fact] + public void UnPinAndTakeArrayOwnership() + { + Foo[] data = null; + using (PinnedBuffer buffer = new PinnedBuffer(42)) + { + data = buffer.UnPinAndTakeArrayOwnership(); + Assert.True(buffer.IsDisposedOrLostArrayOwnership); + } + + Assert.NotNull(data); + Assert.True(data.Length >= 42); + } + private static void VerifyPointer(PinnedBuffer buffer) { IntPtr ptr = (IntPtr)Unsafe.AsPointer(ref buffer.Array[0]); diff --git a/tests/ImageSharp.Tests/Image/PixelPoolTests.cs b/tests/ImageSharp.Tests/Image/PixelPoolTests.cs index 0b762cf7c3..001785d60c 100644 --- a/tests/ImageSharp.Tests/Image/PixelPoolTests.cs +++ b/tests/ImageSharp.Tests/Image/PixelPoolTests.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -10,54 +10,54 @@ namespace ImageSharp.Tests using Xunit; /// - /// Tests the class. + /// Tests the class. /// - public class PixelPoolTests + public class PixelDataPoolTests { [Fact] - public void PixelPoolRentsMinimumSize() + public void PixelDataPoolRentsMinimumSize() { - Color[] pixels = PixelPool.RentPixels(1024); + Color[] pixels = PixelDataPool.Rent(1024); Assert.True(pixels.Length >= 1024); } [Fact] - public void PixelPoolRentsEmptyArray() + public void PixelDataPoolRentsEmptyArray() { for (int i = 16; i < 1024; i += 16) { - Color[] pixels = PixelPool.RentPixels(i); + Color[] pixels = PixelDataPool.Rent(i); Assert.True(pixels.All(p => p == default(Color))); - PixelPool.ReturnPixels(pixels); + PixelDataPool.Return(pixels); } for (int i = 16; i < 1024; i += 16) { - Color[] pixels = PixelPool.RentPixels(i); + Color[] pixels = PixelDataPool.Rent(i); Assert.True(pixels.All(p => p == default(Color))); - PixelPool.ReturnPixels(pixels); + PixelDataPool.Return(pixels); } } [Fact] - public void PixelPoolDoesNotThrowWhenReturningNonPooled() + public void PixelDataPoolDoesNotThrowWhenReturningNonPooled() { Color[] pixels = new Color[1024]; - PixelPool.ReturnPixels(pixels); + PixelDataPool.Return(pixels); Assert.True(pixels.Length >= 1024); } [Fact] - public void PixelPoolCleansRentedArray() + public void PixelDataPoolCleansRentedArray() { - Color[] pixels = PixelPool.RentPixels(256); + Color[] pixels = PixelDataPool.Rent(256); for (int i = 0; i < pixels.Length; i++) { @@ -66,9 +66,28 @@ namespace ImageSharp.Tests Assert.True(pixels.All(p => p == Color.Azure)); - PixelPool.ReturnPixels(pixels); + PixelDataPool.Return(pixels); Assert.True(pixels.All(p => p == default(Color))); } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void CalculateMaxArrayLength(bool isRawData) + { + int max = isRawData ? PixelDataPool.CalculateMaxArrayLength() + : PixelDataPool.CalculateMaxArrayLength(); + + Assert.Equal(max < int.MaxValue, !isRawData); + } + + [Fact] + public void RentNonIPixelData() + { + byte[] data = PixelDataPool.Rent(16384); + + Assert.True(data.Length >= 16384); + } } } \ No newline at end of file From 6132d8fa4cfe879f1679bfe544547863e746bde8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Mar 2017 18:18:09 +0100 Subject: [PATCH 38/85] cleanup & stylecop --- .../BulkPixelOperations{TColor}.cs | 56 +++++++++---------- .../Colors/PackedPixel/HalfVector2.cs | 2 +- .../Colors/PackedPixel/NormalizedByte4.cs | 2 +- src/ImageSharp/Common/Memory/ArrayPointer.cs | 34 +++++++++++ .../Common/Memory/ArrayPointer{T}.cs | 4 +- .../{PinnedBuffer.cs => PinnedBuffer{T}.cs} | 16 +++++- .../Common/Memory/PixelDataPool{T}.cs | 2 +- src/ImageSharp/Image/ImageBase{TColor}.cs | 4 +- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 41 +------------- src/ImageSharp/Image/PixelArea{TColor}.cs | 7 +-- .../Colors/BulkPixelOperationsTests.cs | 5 +- 11 files changed, 92 insertions(+), 81 deletions(-) rename src/ImageSharp/Common/Memory/{PinnedBuffer.cs => PinnedBuffer{T}.cs} (93%) diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs index 557d59a16c..31f872e42a 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs @@ -78,9 +78,9 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// - /// - /// + /// The to the source bytes. + /// The to the destination colors. + /// The number of pixels to convert. internal virtual void PackFromXyzBytes( ArrayPointer sourceBytes, ArrayPointer destColors, @@ -102,15 +102,15 @@ namespace ImageSharp /// /// Bulk version of . /// - /// - /// - /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. internal virtual void PackToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; - for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) + for (int i = destBytes.Offset; i < destBytes.Offset + (count * 3); i += 3) { TColor c = Unsafe.Read(sp); c.ToXyzBytes(dest, i); @@ -121,9 +121,9 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// - /// - /// + /// The to the source bytes. + /// The to the destination colors. + /// The number of pixels to convert. internal virtual void PackFromXyzwBytes( ArrayPointer sourceBytes, ArrayPointer destColors, @@ -145,9 +145,9 @@ namespace ImageSharp /// /// Bulk version of . /// - /// - /// - /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. internal virtual void PackToXyzwBytes( ArrayPointer sourceColors, ArrayPointer destBytes, @@ -156,7 +156,7 @@ namespace ImageSharp byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; - for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) + for (int i = destBytes.Offset; i < destBytes.Offset + (count * 4); i += 4) { TColor c = Unsafe.Read(sp); c.ToXyzwBytes(dest, i); @@ -167,9 +167,9 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// - /// - /// + /// The to the source bytes. + /// The to the destination colors. + /// The number of pixels to convert. internal virtual void PackFromZyxBytes( ArrayPointer sourceBytes, ArrayPointer destColors, @@ -191,15 +191,15 @@ namespace ImageSharp /// /// Bulk version of . /// - /// - /// - /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; - for (int i = destBytes.Offset; i < destBytes.Offset + count * 3; i += 3) + for (int i = destBytes.Offset; i < destBytes.Offset + (count * 3); i += 3) { TColor c = Unsafe.Read(sp); c.ToZyxBytes(dest, i); @@ -210,9 +210,9 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// - /// - /// + /// The to the source bytes. + /// The to the destination colors. + /// The number of pixels to convert. internal virtual void PackFromZyxwBytes( ArrayPointer sourceBytes, ArrayPointer destColors, @@ -234,9 +234,9 @@ namespace ImageSharp /// /// Bulk version of . /// - /// - /// - /// + /// The to the source colors. + /// The to the destination bytes. + /// The number of pixels to convert. internal virtual void PackToZyxwBytes( ArrayPointer sourceColors, ArrayPointer destBytes, @@ -245,7 +245,7 @@ namespace ImageSharp byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; - for (int i = destBytes.Offset; i < destBytes.Offset + count * 4; i += 4) + for (int i = destBytes.Offset; i < destBytes.Offset + (count * 4); i += 4) { TColor c = Unsafe.Read(sp); c.ToZyxwBytes(dest, i); diff --git a/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs b/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs index 778f86e0f6..68cb427356 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs @@ -45,7 +45,7 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - + /// public BulkPixelOperations BulkOperations => new BulkPixelOperations(); diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs index cba3f0e863..4511060e48 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs @@ -52,7 +52,7 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - + /// public BulkPixelOperations BulkOperations => new BulkPixelOperations(); diff --git a/src/ImageSharp/Common/Memory/ArrayPointer.cs b/src/ImageSharp/Common/Memory/ArrayPointer.cs index 56cae35a45..342eaa6c87 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer.cs +++ b/src/ImageSharp/Common/Memory/ArrayPointer.cs @@ -1,3 +1,8 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + namespace ImageSharp { using System.Runtime.CompilerServices; @@ -7,6 +12,12 @@ namespace ImageSharp /// internal static class ArrayPointer { + /// + /// Gets an to the beginning of the raw data in 'buffer'. + /// + /// The element type + /// The input + /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe ArrayPointer GetArrayPointer(this PinnedBuffer buffer) where T : struct @@ -14,6 +25,13 @@ namespace ImageSharp return new ArrayPointer(buffer.Array, (void*)buffer.Pointer); } + /// + /// Copy 'count' number of elements of the same type from 'source' to 'dest' + /// + /// The element type. + /// The input + /// The destination . + /// The number of elements to copy [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int count) where T : struct @@ -21,6 +39,13 @@ namespace ImageSharp Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(count)); } + /// + /// Copy 'countInSource' elements of from 'source' into the raw byte buffer 'destination'. + /// + /// The element type. + /// The source buffer of elements to copy from. + /// The destination buffer. + /// The number of elements to copy from 'source' [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int countInSource) where T : struct @@ -28,6 +53,13 @@ namespace ImageSharp Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInSource)); } + /// + /// Copy 'countInDest' number of elements into 'dest' from a raw byte buffer defined by 'source'. + /// + /// The element type. + /// The raw source buffer to copy from"/> + /// The destination buffer"/> + /// The number of elements to copy. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int countInDest) where T : struct @@ -38,6 +70,7 @@ namespace ImageSharp /// /// Gets the size of `count` elements in bytes. /// + /// The element type. /// The count of the elements /// The size in bytes as int [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -47,6 +80,7 @@ namespace ImageSharp /// /// Gets the size of `count` elements in bytes as UInt32 /// + /// The element type. /// The count of the elements /// The size in bytes as UInt32 [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs b/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs index e0b728095e..9cbbaf0946 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs @@ -73,7 +73,7 @@ namespace ImageSharp /// /// The to convert [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator void* (ArrayPointer arrayPointer) + public static explicit operator void*(ArrayPointer arrayPointer) { return (void*)arrayPointer.PointerAtOffset; } @@ -83,7 +83,7 @@ namespace ImageSharp /// /// The to convert [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator byte* (ArrayPointer arrayPointer) + public static explicit operator byte*(ArrayPointer arrayPointer) { return (byte*)arrayPointer.PointerAtOffset; } diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs similarity index 93% rename from src/ImageSharp/Common/Memory/PinnedBuffer.cs rename to src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index 201d93b56a..d95d675571 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -1,3 +1,8 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + namespace ImageSharp { using System; @@ -21,7 +26,7 @@ namespace ImageSharp /// A value indicating wether this instance should return the array to the pool. /// private bool isPoolingOwner; - + /// /// Initializes a new instance of the class. /// @@ -56,11 +61,15 @@ namespace ImageSharp { throw new ArgumentException("Can't initialize a PinnedBuffer with array.Length < count", nameof(array)); } + this.Count = count; this.Array = array; this.Pin(); } + /// + /// Finalizes an instance of the class. + /// ~PinnedBuffer() { this.UnPin(); @@ -71,14 +80,13 @@ namespace ImageSharp /// public bool IsDisposedOrLostArrayOwnership { get; private set; } - /// /// Gets the count of "relevant" elements. Usually be smaller than 'Array.Length' when is pooled. /// public int Count { get; private set; } /// - /// The (pinned) array of elements. + /// Gets the backing pinned array. /// public T[] Array { get; private set; } @@ -96,6 +104,7 @@ namespace ImageSharp { return; } + this.IsDisposedOrLostArrayOwnership = true; this.UnPin(); @@ -147,6 +156,7 @@ namespace ImageSharp { return; } + this.handle.Free(); this.Pointer = IntPtr.Zero; } diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs index f6f6a10425..74f0c1e8e0 100644 --- a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs +++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 9bd760805a..c2110eca4f 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -163,9 +163,9 @@ namespace ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - // TODO: This check was useful. We can introduce a bool PixelAccessor.IsBoundToImage to re-introduce it. - // Guard.IsTrue(pixelSource.PooledMemory, nameof(pixelSource.PooledMemory), "pixelSource must be using pooled memory"); + // TODO: Was this check really useful? If yes, we can define a bool PixelAccessor.IsBoundToImage to re-introduce it: + // Guard.IsTrue(pixelSource.PooledMemory, nameof(pixelSource.PooledMemory), "pixelSource must be using pooled memory"); int newWidth = pixelSource.Width; int newHeight = pixelSource.Height; diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index 3a3f0f5c7e..9201270d9d 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -22,7 +22,7 @@ namespace ImageSharp /// The position of the first pixel in the image. /// private byte* pixelsBase; - + /// /// A value indicating whether this instance of the given entity has been disposed. /// @@ -86,11 +86,6 @@ namespace ImageSharp Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - //if (!(pixels.Length >= width * height)) - //{ - // throw new ArgumentException($"Pixel array must have the length of at least {width * height}."); - //} - this.SetPixelBufferUnsafe(width, height, pixels); this.ParallelOptions = Configuration.Default.ParallelOptions; @@ -103,7 +98,7 @@ namespace ImageSharp { this.Dispose(); } - + /// /// Gets the pixel buffer array. /// @@ -230,7 +225,7 @@ namespace ImageSharp { return; } - + // Note disposing is done. this.isDisposed = true; @@ -513,36 +508,6 @@ namespace ImageSharp this.RowStride = this.Width * this.PixelSize; } - ///// - ///// Pins the pixels data. - ///// - //private void PinPixels() - //{ - // // unpin any old pixels just incase - // this.UnPinPixels(); - - // this.pixelsHandle = GCHandle.Alloc(this.pixelBuffer, GCHandleType.Pinned); - // this.dataPointer = this.pixelsHandle.AddrOfPinnedObject(); - // this.pixelsBase = (byte*)this.dataPointer.ToPointer(); - //} - - ///// - ///// Unpins pixels data. - ///// - //private void UnPinPixels() - //{ - // if (this.pixelsBase != null) - // { - // if (this.pixelsHandle.IsAllocated) - // { - // this.pixelsHandle.Free(); - // } - - // this.dataPointer = IntPtr.Zero; - // this.pixelsBase = null; - // } - //} - /// /// Copy an area of pixels to the image. /// diff --git a/src/ImageSharp/Image/PixelArea{TColor}.cs b/src/ImageSharp/Image/PixelArea{TColor}.cs index 25840167eb..c54de12d6c 100644 --- a/src/ImageSharp/Image/PixelArea{TColor}.cs +++ b/src/ImageSharp/Image/PixelArea{TColor}.cs @@ -69,7 +69,6 @@ namespace ImageSharp this.Length = bytes.Length; // TODO: Is this the right value for Length? this.byteBuffer = new PinnedBuffer(bytes); - this.PixelBase = (byte*)this.byteBuffer.Pointer; } @@ -123,7 +122,7 @@ namespace ImageSharp this.byteBuffer = new PinnedBuffer(this.Length); this.PixelBase = (byte*)this.byteBuffer.Pointer; } - + /// /// Gets the data in bytes. /// @@ -163,7 +162,7 @@ namespace ImageSharp /// Gets the width. /// public int Width { get; } - + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -249,6 +248,6 @@ namespace ImageSharp nameof(bytes), $"Invalid byte array length. Length {bytes.Length}; Should be {requiredLength}."); } - } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 3682aa78a3..4e1083033e 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -9,11 +9,13 @@ { public class Color : BulkPixelOperationsTests { + // MemberData does not work without redeclaring the public field in the derived test class: public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; } public class Argb : BulkPixelOperationsTests { + // MemberData does not work without redeclaring the public field in the derived test class: public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; } } @@ -21,7 +23,8 @@ public abstract class BulkPixelOperationsTests where TColor : struct, IPixel { - protected static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; + // The field is private so it can be safely redeclared in inherited non-abstract test classes. + private static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; [Theory] [MemberData(nameof(ArraySizesData))] From 8a08319ce0d8b146410a85eff45d7c64aecbef3e Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Mar 2017 18:32:06 +0100 Subject: [PATCH 39/85] build and testrunning fix --- src/ImageSharp/Common/Memory/PixelDataPool{T}.cs | 3 ++- .../Colors/BulkPixelOperationsTests.cs | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs index 74f0c1e8e0..a97d17fdbb 100644 --- a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs +++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs @@ -46,7 +46,8 @@ namespace ImageSharp /// The maxArrayLength value internal static int CalculateMaxArrayLength() { - if (typeof(IPixel).IsAssignableFrom(typeof(T))) + // ReSharper disable once SuspiciousTypeConversion.Global + if (default(T) is IPixel) { const int MaximumExpectedImageSize = 16384; return MaximumExpectedImageSize * MaximumExpectedImageSize; diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 4e1083033e..0e69a54f54 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -9,22 +9,21 @@ { public class Color : BulkPixelOperationsTests { - // MemberData does not work without redeclaring the public field in the derived test class: - public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } public class Argb : BulkPixelOperationsTests { - // MemberData does not work without redeclaring the public field in the derived test class: - public static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } } public abstract class BulkPixelOperationsTests where TColor : struct, IPixel { - // The field is private so it can be safely redeclared in inherited non-abstract test classes. - private static TheoryData ArraySizesData = new TheoryData { 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; [Theory] [MemberData(nameof(ArraySizesData))] From 4e54632d631417fd49b395401b8d96f95640f694 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Mar 2017 19:25:31 +0100 Subject: [PATCH 40/85] BulkPixelOperationsTests.GetGlobalInstance() to make CodeCov happy --- .../Colors/BulkPixelOperationsTests.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 0e69a54f54..c179b01a10 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -5,7 +5,7 @@ using Xunit; - public abstract class BulkPixelOperationsTests + public class BulkPixelOperationsTests { public class Color : BulkPixelOperationsTests { @@ -18,6 +18,14 @@ // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } + + [Theory] + [WithBlankImages(1, 1, PixelTypes.All)] + public void GetGlobalInstance(TestImageProvider dummy) + where TColor:struct, IPixel + { + Assert.NotNull(BulkPixelOperations.Instance); + } } public abstract class BulkPixelOperationsTests From 4b11becfff2d487d122824ccb89a9a1acf44bccd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Mar 2017 21:18:31 +0100 Subject: [PATCH 41/85] IPixel.BulkOperations ---> IPixel.CreateBulkOperations() --- src/ImageSharp/Colors/Color.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Alpha8.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Argb.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Bgr565.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Bgra4444.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Bgra5551.cs | 6 +++--- .../Colors/PackedPixel/BulkPixelOperations{TColor}.cs | 2 +- src/ImageSharp/Colors/PackedPixel/Byte4.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/HalfSingle.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/HalfVector2.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/HalfVector4.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/IPixel.cs | 6 ++++-- src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Rg32.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Rgba64.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Short2.cs | 6 +++--- src/ImageSharp/Colors/PackedPixel/Short4.cs | 6 +++--- 21 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Colors/Color.cs b/src/ImageSharp/Colors/Color.cs index 8a869935c1..1ad6f9a643 100644 --- a/src/ImageSharp/Colors/Color.cs +++ b/src/ImageSharp/Colors/Color.cs @@ -112,9 +112,6 @@ namespace ImageSharp this.packedValue = packed; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Gets or sets the red component. /// @@ -248,6 +245,9 @@ namespace ImageSharp return ColorBuilder.FromHex(hex); } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromBytes(byte x, byte y, byte z, byte w) diff --git a/src/ImageSharp/Colors/PackedPixel/Alpha8.cs b/src/ImageSharp/Colors/PackedPixel/Alpha8.cs index 1181eb9e47..9a340544cf 100644 --- a/src/ImageSharp/Colors/PackedPixel/Alpha8.cs +++ b/src/ImageSharp/Colors/PackedPixel/Alpha8.cs @@ -26,9 +26,6 @@ namespace ImageSharp /// public byte PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -61,6 +58,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/Argb.cs b/src/ImageSharp/Colors/PackedPixel/Argb.cs index 1b97d2337a..70fd7de8a7 100644 --- a/src/ImageSharp/Colors/PackedPixel/Argb.cs +++ b/src/ImageSharp/Colors/PackedPixel/Argb.cs @@ -109,9 +109,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Gets or sets the red component. /// @@ -223,6 +220,9 @@ namespace ImageSharp this.PackedValue = Pack(ref vector); } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() diff --git a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs index 41b2bdc2e0..77d9434785 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgr565.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgr565.cs @@ -39,9 +39,6 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -70,6 +67,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs b/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs index 99659a36bc..1346a54efc 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgra4444.cs @@ -38,9 +38,6 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -69,6 +66,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() diff --git a/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs b/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs index 86864fd485..7989804cfb 100644 --- a/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs +++ b/src/ImageSharp/Colors/PackedPixel/Bgra5551.cs @@ -40,9 +40,6 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -71,6 +68,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs index 31f872e42a..986994af7b 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs @@ -24,7 +24,7 @@ namespace ImageSharp /// /// Gets the global instance for the pixel type /// - public static BulkPixelOperations Instance { get; } = default(TColor).BulkOperations; + public static BulkPixelOperations Instance { get; } = default(TColor).CreateBulkOperations(); /// /// Bulk version of diff --git a/src/ImageSharp/Colors/PackedPixel/Byte4.cs b/src/ImageSharp/Colors/PackedPixel/Byte4.cs index 5712027d96..11ec5eaf4b 100644 --- a/src/ImageSharp/Colors/PackedPixel/Byte4.cs +++ b/src/ImageSharp/Colors/PackedPixel/Byte4.cs @@ -41,9 +41,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -72,6 +69,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs b/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs index 0bc82c3a61..4c785a8636 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfSingle.cs @@ -36,9 +36,6 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -75,6 +72,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// /// Expands the packed representation into a . /// diff --git a/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs b/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs index 68cb427356..d06ab6ba07 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfVector2.cs @@ -46,9 +46,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -85,6 +82,9 @@ namespace ImageSharp return !left.Equals(right); } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// /// Expands the packed representation into a . /// diff --git a/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs b/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs index c24553d3f3..a5fa796e1d 100644 --- a/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs +++ b/src/ImageSharp/Colors/PackedPixel/HalfVector4.cs @@ -49,9 +49,6 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -88,6 +85,9 @@ namespace ImageSharp return !left.Equals(right); } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/IPixel.cs b/src/ImageSharp/Colors/PackedPixel/IPixel.cs index c17fe86ccf..67e013a422 100644 --- a/src/ImageSharp/Colors/PackedPixel/IPixel.cs +++ b/src/ImageSharp/Colors/PackedPixel/IPixel.cs @@ -16,9 +16,11 @@ namespace ImageSharp where TSelf : struct, IPixel { /// - /// Gets the instance for this pixel type. + /// Creates a instance for this pixel type. + /// This method is not intended to be consumed directly. Use instead. /// - BulkPixelOperations BulkOperations { get; } + /// The instance. + BulkPixelOperations CreateBulkOperations(); } /// diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs index d425806c27..56be64a86c 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs @@ -51,9 +51,6 @@ namespace ImageSharp /// public ushort PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -90,6 +87,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs index 4511060e48..a1f9b8d847 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs @@ -53,9 +53,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -92,6 +89,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs index 4bc7f94277..b34c1e88b7 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs @@ -51,9 +51,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -90,6 +87,9 @@ namespace ImageSharp return !left.Equals(right); } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs index c848b72369..f33ac25a64 100644 --- a/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs +++ b/src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs @@ -53,9 +53,6 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -92,6 +89,9 @@ namespace ImageSharp return !left.Equals(right); } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/Rg32.cs b/src/ImageSharp/Colors/PackedPixel/Rg32.cs index 9eb2247c9b..f8486f7f29 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rg32.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rg32.cs @@ -36,9 +36,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -75,6 +72,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs index 4f99feb6e5..56f3040703 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs @@ -39,9 +39,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -78,6 +75,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() diff --git a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs index a23e57ec3d..816401d4e0 100644 --- a/src/ImageSharp/Colors/PackedPixel/Rgba64.cs +++ b/src/ImageSharp/Colors/PackedPixel/Rgba64.cs @@ -38,9 +38,6 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -77,6 +74,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Vector4 ToVector4() diff --git a/src/ImageSharp/Colors/PackedPixel/Short2.cs b/src/ImageSharp/Colors/PackedPixel/Short2.cs index f26e825789..802df7c1d4 100644 --- a/src/ImageSharp/Colors/PackedPixel/Short2.cs +++ b/src/ImageSharp/Colors/PackedPixel/Short2.cs @@ -51,9 +51,6 @@ namespace ImageSharp /// public uint PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -90,6 +87,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) diff --git a/src/ImageSharp/Colors/PackedPixel/Short4.cs b/src/ImageSharp/Colors/PackedPixel/Short4.cs index 6dc7545e1b..2517ef7a84 100644 --- a/src/ImageSharp/Colors/PackedPixel/Short4.cs +++ b/src/ImageSharp/Colors/PackedPixel/Short4.cs @@ -53,9 +53,6 @@ namespace ImageSharp /// public ulong PackedValue { get; set; } - /// - public BulkPixelOperations BulkOperations => new BulkPixelOperations(); - /// /// Compares two objects for equality. /// @@ -92,6 +89,9 @@ namespace ImageSharp return left.PackedValue != right.PackedValue; } + /// + public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PackFromVector4(Vector4 vector) From a8ab5d4b89591bf865b9aac3136006c6083ca8e2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 6 Mar 2017 01:15:07 +0100 Subject: [PATCH 42/85] Renamed BulkPixelOperation methods, removed ArrayExtensions and the unused dangerous PixelAccessor ctr. --- .../BulkPixelOperations{TColor}.cs | 10 +++---- .../Common/Extensions/ArrayExtensions.cs | 29 ------------------- .../Common/Memory/PinnedBuffer{T}.cs | 2 +- src/ImageSharp/Image/ImageBase{TColor}.cs | 3 -- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 11 ------- .../ImageSharp.Sandbox46.csproj | 3 -- tests/ImageSharp.Sandbox46/Program.cs | 2 +- .../Colors/BulkPixelOperationsTests.cs | 10 +++---- .../PixelDataPoolTests.cs} | 0 9 files changed, 12 insertions(+), 58 deletions(-) delete mode 100644 src/ImageSharp/Common/Extensions/ArrayExtensions.cs rename tests/ImageSharp.Tests/{Image/PixelPoolTests.cs => Common/PixelDataPoolTests.cs} (100%) diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs index 986994af7b..a84c3edf3e 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs @@ -58,7 +58,7 @@ namespace ImageSharp /// The to the source colors. /// The to the destination vectors. /// The number of pixels to convert. - internal virtual void PackToVector4( + internal virtual void ToVector4( ArrayPointer sourceColors, ArrayPointer destVectors, int count) @@ -105,7 +105,7 @@ namespace ImageSharp /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - internal virtual void PackToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + internal virtual void ToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; @@ -148,7 +148,7 @@ namespace ImageSharp /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - internal virtual void PackToXyzwBytes( + internal virtual void ToXyzwBytes( ArrayPointer sourceColors, ArrayPointer destBytes, int count) @@ -194,7 +194,7 @@ namespace ImageSharp /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - internal virtual void PackToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + internal virtual void ToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) { byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; @@ -237,7 +237,7 @@ namespace ImageSharp /// The to the source colors. /// The to the destination bytes. /// The number of pixels to convert. - internal virtual void PackToZyxwBytes( + internal virtual void ToZyxwBytes( ArrayPointer sourceColors, ArrayPointer destBytes, int count) diff --git a/src/ImageSharp/Common/Extensions/ArrayExtensions.cs b/src/ImageSharp/Common/Extensions/ArrayExtensions.cs deleted file mode 100644 index cce442c522..0000000000 --- a/src/ImageSharp/Common/Extensions/ArrayExtensions.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System; - - /// - /// Extension methods for arrays. - /// - public static class ArrayExtensions - { - /// - /// Locks the pixel buffer providing access to the pixels. - /// - /// The pixel format. - /// The pixel buffer. - /// Gets the width of the image represented by the pixel buffer. - /// The height of the image represented by the pixel buffer. - /// The - public static PixelAccessor Lock(this TColor[] pixels, int width, int height) - where TColor : struct, IPixel - { - return new PixelAccessor(width, height, pixels); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index d95d675571..04217a0123 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -23,7 +23,7 @@ namespace ImageSharp private GCHandle handle; /// - /// A value indicating wether this instance should return the array to the pool. + /// A value indicating whether this instance should return the array to the pool. /// private bool isPoolingOwner; diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index c2110eca4f..2badc008a2 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -163,9 +163,6 @@ namespace ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - // TODO: Was this check really useful? If yes, we can define a bool PixelAccessor.IsBoundToImage to re-introduce it: - - // Guard.IsTrue(pixelSource.PooledMemory, nameof(pixelSource.PooledMemory), "pixelSource must be using pooled memory"); int newWidth = pixelSource.Width; int newHeight = pixelSource.Height; diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index 9201270d9d..e104b8ae77 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -53,17 +53,6 @@ namespace ImageSharp this.ParallelOptions = image.Configuration.ParallelOptions; } - /// - /// Initializes a new instance of the class. - /// - /// The width of the image represented by the pixel buffer. - /// The height of the image represented by the pixel buffer. - /// The pixel buffer. - public PixelAccessor(int width, int height, TColor[] pixels) - : this(width, height, new PinnedBuffer(width * height, pixels)) - { - } - /// /// Initializes a new instance of the class. /// diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 094eedb180..1d78994860 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -251,9 +251,6 @@ Tests\Formats\Jpg\YCbCrImageTests.cs - - Tests\Image\PixelPoolTests.cs - Tests\MetaData\ImagePropertyTests.cs diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 3afd180941..4d6d159255 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -37,7 +37,7 @@ namespace ImageSharp.Sandbox46 /// public static void Main(string[] args) { - //RunDecodeJpegProfilingTests(); + // RunDecodeJpegProfilingTests(); TestPixelAccessorCopyFromXyzw(); Console.ReadLine(); } diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index c179b01a10..1c22411d09 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -67,7 +67,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackToVector4(s, d, count) + (ops, s, d) => ops.ToVector4(s, d, count) ); } @@ -109,7 +109,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackToXyzBytes(s, d, count) + (ops, s, d) => ops.ToXyzBytes(s, d, count) ); } @@ -150,7 +150,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackToXyzwBytes(s, d, count) + (ops, s, d) => ops.ToXyzwBytes(s, d, count) ); } @@ -191,7 +191,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackToZyxBytes(s, d, count) + (ops, s, d) => ops.ToZyxBytes(s, d, count) ); } @@ -232,7 +232,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackToZyxwBytes(s, d, count) + (ops, s, d) => ops.ToZyxwBytes(s, d, count) ); } diff --git a/tests/ImageSharp.Tests/Image/PixelPoolTests.cs b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Image/PixelPoolTests.cs rename to tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs From 099697cf0a31e4ddc81666a579ef7c32634edf62 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 6 Mar 2017 21:47:45 +0100 Subject: [PATCH 43/85] renamed ArrayPointer to BufferPointer --- .../BulkPixelOperations{TColor}.cs | 76 +++++++++---------- .../{ArrayPointer.cs => BufferPointer.cs} | 24 +++--- ...ArrayPointer{T}.cs => BufferPointer{T}.cs} | 40 +++++----- .../Color/Bulk/PixelAccessorVirtualCopy.cs | 24 +++--- .../Colors/BulkPixelOperationsTests.cs | 6 +- ...yPointerTests.cs => BufferPointerTests.cs} | 26 +++---- .../Common/PinnedBufferTests.cs | 4 +- 7 files changed, 100 insertions(+), 100 deletions(-) rename src/ImageSharp/Common/Memory/{ArrayPointer.cs => BufferPointer.cs} (79%) rename src/ImageSharp/Common/Memory/{ArrayPointer{T}.cs => BufferPointer{T}.cs} (66%) rename tests/ImageSharp.Tests/Common/{ArrayPointerTests.cs => BufferPointerTests.cs} (81%) diff --git a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs index a84c3edf3e..259b1c9b47 100644 --- a/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs +++ b/src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs @@ -29,12 +29,12 @@ namespace ImageSharp /// /// Bulk version of /// - /// The to the source vectors. - /// The to the destination colors. + /// The to the source vectors. + /// The to the destination colors. /// The number of pixels to convert. internal virtual void PackFromVector4( - ArrayPointer sourceVectors, - ArrayPointer destColors, + BufferPointer sourceVectors, + BufferPointer destColors, int count) { Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; @@ -55,12 +55,12 @@ namespace ImageSharp /// /// Bulk version of . /// - /// The to the source colors. - /// The to the destination vectors. + /// The to the source colors. + /// The to the destination vectors. /// The number of pixels to convert. internal virtual void ToVector4( - ArrayPointer sourceColors, - ArrayPointer destVectors, + BufferPointer sourceColors, + BufferPointer destVectors, int count) { byte* sp = (byte*)sourceColors; @@ -78,12 +78,12 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// The to the source bytes. - /// The to the destination colors. + /// The to the source bytes. + /// The to the destination colors. /// The number of pixels to convert. internal virtual void PackFromXyzBytes( - ArrayPointer sourceBytes, - ArrayPointer destColors, + BufferPointer sourceBytes, + BufferPointer destColors, int count) { byte* sp = (byte*)sourceBytes; @@ -102,10 +102,10 @@ namespace ImageSharp /// /// Bulk version of . /// - /// The to the source colors. - /// The to the destination bytes. + /// The to the source colors. + /// The to the destination bytes. /// The number of pixels to convert. - internal virtual void ToXyzBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + internal virtual void ToXyzBytes(BufferPointer sourceColors, BufferPointer destBytes, int count) { byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; @@ -121,12 +121,12 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// The to the source bytes. - /// The to the destination colors. + /// The to the source bytes. + /// The to the destination colors. /// The number of pixels to convert. internal virtual void PackFromXyzwBytes( - ArrayPointer sourceBytes, - ArrayPointer destColors, + BufferPointer sourceBytes, + BufferPointer destColors, int count) { byte* sp = (byte*)sourceBytes; @@ -145,12 +145,12 @@ namespace ImageSharp /// /// Bulk version of . /// - /// The to the source colors. - /// The to the destination bytes. + /// The to the source colors. + /// The to the destination bytes. /// The number of pixels to convert. internal virtual void ToXyzwBytes( - ArrayPointer sourceColors, - ArrayPointer destBytes, + BufferPointer sourceColors, + BufferPointer destBytes, int count) { byte* sp = (byte*)sourceColors; @@ -167,12 +167,12 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// The to the source bytes. - /// The to the destination colors. + /// The to the source bytes. + /// The to the destination colors. /// The number of pixels to convert. internal virtual void PackFromZyxBytes( - ArrayPointer sourceBytes, - ArrayPointer destColors, + BufferPointer sourceBytes, + BufferPointer destColors, int count) { byte* sp = (byte*)sourceBytes; @@ -191,10 +191,10 @@ namespace ImageSharp /// /// Bulk version of . /// - /// The to the source colors. - /// The to the destination bytes. + /// The to the source colors. + /// The to the destination bytes. /// The number of pixels to convert. - internal virtual void ToZyxBytes(ArrayPointer sourceColors, ArrayPointer destBytes, int count) + internal virtual void ToZyxBytes(BufferPointer sourceColors, BufferPointer destBytes, int count) { byte* sp = (byte*)sourceColors; byte[] dest = destBytes.Array; @@ -210,12 +210,12 @@ namespace ImageSharp /// /// Bulk version of that converts data in . /// - /// The to the source bytes. - /// The to the destination colors. + /// The to the source bytes. + /// The to the destination colors. /// The number of pixels to convert. internal virtual void PackFromZyxwBytes( - ArrayPointer sourceBytes, - ArrayPointer destColors, + BufferPointer sourceBytes, + BufferPointer destColors, int count) { byte* sp = (byte*)sourceBytes; @@ -234,12 +234,12 @@ namespace ImageSharp /// /// Bulk version of . /// - /// The to the source colors. - /// The to the destination bytes. + /// The to the source colors. + /// The to the destination bytes. /// The number of pixels to convert. internal virtual void ToZyxwBytes( - ArrayPointer sourceColors, - ArrayPointer destBytes, + BufferPointer sourceColors, + BufferPointer destBytes, int count) { byte* sp = (byte*)sourceColors; diff --git a/src/ImageSharp/Common/Memory/ArrayPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs similarity index 79% rename from src/ImageSharp/Common/Memory/ArrayPointer.cs rename to src/ImageSharp/Common/Memory/BufferPointer.cs index 342eaa6c87..c80e22e21d 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -8,32 +8,32 @@ namespace ImageSharp using System.Runtime.CompilerServices; /// - /// Utility methods to + /// Utility methods for /// - internal static class ArrayPointer + internal static class BufferPointer { /// - /// Gets an to the beginning of the raw data in 'buffer'. + /// Gets a to the beginning of the raw data in 'buffer'. /// /// The element type /// The input - /// The + /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe ArrayPointer GetArrayPointer(this PinnedBuffer buffer) + public static unsafe BufferPointer Slice(this PinnedBuffer buffer) where T : struct { - return new ArrayPointer(buffer.Array, (void*)buffer.Pointer); + return new BufferPointer(buffer.Array, (void*)buffer.Pointer); } /// /// Copy 'count' number of elements of the same type from 'source' to 'dest' /// /// The element type. - /// The input - /// The destination . + /// The input + /// The destination . /// The number of elements to copy [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int count) + public static unsafe void Copy(BufferPointer source, BufferPointer destination, int count) where T : struct { Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(count)); @@ -47,7 +47,7 @@ namespace ImageSharp /// The destination buffer. /// The number of elements to copy from 'source' [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int countInSource) + public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInSource) where T : struct { Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInSource)); @@ -61,7 +61,7 @@ namespace ImageSharp /// The destination buffer"/> /// The number of elements to copy. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Copy(ArrayPointer source, ArrayPointer destination, int countInDest) + public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInDest) where T : struct { Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInDest)); diff --git a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs similarity index 66% rename from src/ImageSharp/Common/Memory/ArrayPointer{T}.cs rename to src/ImageSharp/Common/Memory/BufferPointer{T}.cs index 9cbbaf0946..fff4e513e1 100644 --- a/src/ImageSharp/Common/Memory/ArrayPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -1,4 +1,4 @@ -// +// // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // @@ -15,21 +15,21 @@ namespace ImageSharp /// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays /// - It's possible to retrieve a reference to the array () so we can pass it to API-s like /// - There is no bounds checking for performance reasons. Therefore we don't need to store length. (However this could be added as DEBUG-only feature.) - /// This makes an unsafe type! - /// - Currently the arrays provided to ArrayPointer need to be pinned. This behaviour could be changed using C#7 features. + /// This makes an unsafe type! + /// - Currently the arrays provided to BufferPointer need to be pinned. This behaviour could be changed using C#7 features. /// /// The type of elements of the array - internal unsafe struct ArrayPointer + internal unsafe struct BufferPointer where T : struct { /// - /// Initializes a new instance of the struct from a pinned array and an offset. + /// Initializes a new instance of the struct from a pinned array and an offset. /// /// The pinned array /// Pointer to the beginning of array /// The offset inside the array [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArrayPointer(T[] array, void* pointerToArray, int offset) + public BufferPointer(T[] array, void* pointerToArray, int offset) { DebugGuard.NotNull(array, nameof(array)); @@ -39,12 +39,12 @@ namespace ImageSharp } /// - /// Initializes a new instance of the struct from a pinned array. + /// Initializes a new instance of the struct from a pinned array. /// /// The pinned array /// Pointer to the start of 'array' [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArrayPointer(T[] array, void* pointerToArray) + public BufferPointer(T[] array, void* pointerToArray) { DebugGuard.NotNull(array, nameof(array)); @@ -69,34 +69,34 @@ namespace ImageSharp public IntPtr PointerAtOffset { get; private set; } /// - /// Convertes instance to a raw 'void*' pointer + /// Convertes instance to a raw 'void*' pointer /// - /// The to convert + /// The to convert [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator void*(ArrayPointer arrayPointer) + public static explicit operator void*(BufferPointer bufferPointer) { - return (void*)arrayPointer.PointerAtOffset; + return (void*)bufferPointer.PointerAtOffset; } /// - /// Convertes instance to a raw 'byte*' pointer + /// Convertes instance to a raw 'byte*' pointer /// - /// The to convert + /// The to convert [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator byte*(ArrayPointer arrayPointer) + public static explicit operator byte*(BufferPointer bufferPointer) { - return (byte*)arrayPointer.PointerAtOffset; + return (byte*)bufferPointer.PointerAtOffset; } /// - /// Forms a slice out of the given ArrayPointer, beginning at 'offset'. + /// Forms a slice out of the given BufferPointer, beginning at 'offset'. /// /// The offset in number of elements - /// The offseted (sliced) ArrayPointer + /// The offseted (sliced) BufferPointer [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ArrayPointer Slice(int offset) + public BufferPointer Slice(int offset) { - ArrayPointer result = default(ArrayPointer); + BufferPointer result = default(BufferPointer); result.Array = this.Array; result.Offset = this.Offset + offset; result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * offset); diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs index 9222d6bac2..694a26f3dd 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs @@ -19,13 +19,13 @@ namespace ImageSharp.Benchmarks.Color.Bulk { abstract class CopyExecutor { - internal abstract void VirtualCopy(ArrayPointer destination, ArrayPointer source, int count); + internal abstract void VirtualCopy(BufferPointer destination, BufferPointer source, int count); } class UnsafeCopyExecutor : CopyExecutor { [MethodImpl(MethodImplOptions.NoInlining)] - internal override unsafe void VirtualCopy(ArrayPointer destination, ArrayPointer source, int count) + internal override unsafe void VirtualCopy(BufferPointer destination, BufferPointer source, int count) { Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)count*4); } @@ -76,7 +76,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk } [Benchmark] - public void CopyArrayPointerUnsafeInlined() + public void CopyBufferPointerUnsafeInlined() { uint byteCount = (uint)this.area.Width * 4; @@ -85,22 +85,22 @@ namespace ImageSharp.Benchmarks.Color.Bulk for (int y = 0; y < this.Height; y++) { - ArrayPointer source = this.GetAreaRow(y); - ArrayPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); + BufferPointer source = this.GetAreaRow(y); + BufferPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); } } [Benchmark] - public void CopyArrayPointerUnsafeVirtual() + public void CopyBufferPointerUnsafeVirtual() { int targetX = this.Width / 4; int targetY = 0; for (int y = 0; y < this.Height; y++) { - ArrayPointer source = this.GetAreaRow(y); - ArrayPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); + BufferPointer source = this.GetAreaRow(y); + BufferPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); this.executor.VirtualCopy(destination, source, this.area.Width); } } @@ -111,9 +111,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ArrayPointer GetPixelAccessorRow(int x, int y) + private BufferPointer GetPixelAccessorRow(int x, int y) { - return new ArrayPointer( + return new BufferPointer( this.pixelAccessor.PixelBuffer, (void*)this.pixelAccessor.DataPointer, (y * this.pixelAccessor.Width) + x @@ -121,9 +121,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ArrayPointer GetAreaRow(int y) + private BufferPointer GetAreaRow(int y) { - return new ArrayPointer(this.area.Bytes, this.area.PixelBase, y * this.area.RowStride); + return new BufferPointer(this.area.Bytes, this.area.PixelBase, y * this.area.RowStride); } } } diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 1c22411d09..80d5952a1e 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -245,8 +245,8 @@ public PinnedBuffer ActualDestBuffer { get; } public PinnedBuffer ExpectedDestBuffer { get; } - public ArrayPointer Source => this.SourceBuffer.GetArrayPointer(); - public ArrayPointer ActualDest => this.ActualDestBuffer.GetArrayPointer(); + public BufferPointer Source => this.SourceBuffer.Slice(); + public BufferPointer ActualDest => this.ActualDestBuffer.Slice(); public TestBuffers(TSource[] source, TDest[] expectedDest) { @@ -277,7 +277,7 @@ private static void TestOperation( TSource[] source, TDest[] expected, - Action, ArrayPointer, ArrayPointer> action) + Action, BufferPointer, BufferPointer> action) where TSource : struct where TDest : struct { diff --git a/tests/ImageSharp.Tests/Common/ArrayPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs similarity index 81% rename from tests/ImageSharp.Tests/Common/ArrayPointerTests.cs rename to tests/ImageSharp.Tests/Common/BufferPointerTests.cs index 916a109475..4b5847d53f 100644 --- a/tests/ImageSharp.Tests/Common/ArrayPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs @@ -7,7 +7,7 @@ namespace ImageSharp.Tests.Common using Xunit; - public unsafe class ArrayPointerTests + public unsafe class BufferPointerTests { public struct Foo { @@ -33,7 +33,7 @@ namespace ImageSharp.Tests.Common fixed (Foo* p = array) { // Act: - ArrayPointer ap = new ArrayPointer(array, p); + BufferPointer ap = new BufferPointer(array, p); // Assert: Assert.Equal(array, ap.Array); @@ -49,7 +49,7 @@ namespace ImageSharp.Tests.Common fixed (Foo* p = array) { // Act: - ArrayPointer ap = new ArrayPointer(array, p, offset); + BufferPointer ap = new BufferPointer(array, p, offset); // Assert: Assert.Equal(array, ap.Array); @@ -67,7 +67,7 @@ namespace ImageSharp.Tests.Common int totalOffset = offset0 + offset1; fixed (Foo* p = array) { - ArrayPointer ap = new ArrayPointer(array, p, offset0); + BufferPointer ap = new BufferPointer(array, p, offset0); // Act: ap = ap.Slice(offset1); @@ -92,10 +92,10 @@ namespace ImageSharp.Tests.Common fixed (Foo* pSource = source) fixed (Foo* pDest = dest) { - ArrayPointer apSource = new ArrayPointer(source, pSource); - ArrayPointer apDest = new ArrayPointer(dest, pDest); + BufferPointer apSource = new BufferPointer(source, pSource); + BufferPointer apDest = new BufferPointer(dest, pDest); - ArrayPointer.Copy(apSource, apDest, count); + BufferPointer.Copy(apSource, apDest, count); } Assert.Equal(source[0], dest[0]); @@ -115,10 +115,10 @@ namespace ImageSharp.Tests.Common fixed (Foo* pSource = source) fixed (byte* pDest = dest) { - ArrayPointer apSource = new ArrayPointer(source, pSource); - ArrayPointer apDest = new ArrayPointer(dest, pDest); + BufferPointer apSource = new BufferPointer(source, pSource); + BufferPointer apDest = new BufferPointer(dest, pDest); - ArrayPointer.Copy(apSource, apDest, count); + BufferPointer.Copy(apSource, apDest, count); } Assert.True(ElementsAreEqual(source, dest, 0)); @@ -138,10 +138,10 @@ namespace ImageSharp.Tests.Common fixed(byte* pSource = source) fixed (Foo* pDest = dest) { - ArrayPointer apSource = new ArrayPointer(source, pSource); - ArrayPointer apDest = new ArrayPointer(dest, pDest); + BufferPointer apSource = new BufferPointer(source, pSource); + BufferPointer apDest = new BufferPointer(dest, pDest); - ArrayPointer.Copy(apSource, apDest, count); + BufferPointer.Copy(apSource, apDest, count); } Assert.True(ElementsAreEqual(dest, source, 0)); diff --git a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs index c5eb2a5103..65077ae7f3 100644 --- a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs +++ b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs @@ -57,13 +57,13 @@ } [Fact] - public void GetArrayPointer() + public void Slice() { Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } }; using (PinnedBuffer buffer = new PinnedBuffer(a)) { - var arrayPtr = buffer.GetArrayPointer(); + var arrayPtr = buffer.Slice(); Assert.Equal(a, arrayPtr.Array); Assert.Equal(0, arrayPtr.Offset); From 23bd85c4464add6e6e79dd4a196c753a86609c53 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 6 Mar 2017 21:53:36 +0100 Subject: [PATCH 44/85] DebugGuard --- codecov.yml | 4 + src/ImageSharp/Colors/Color.BulkOperations.cs | 25 ++++ src/ImageSharp/Common/Helpers/DebugGuard.cs | 132 ++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 codecov.yml create mode 100644 src/ImageSharp/Colors/Color.BulkOperations.cs diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000000..ae6dd5f6bf --- /dev/null +++ b/codecov.yml @@ -0,0 +1,4 @@ +ignore: + "src/ImageSharp/Common/Helpers/DebugGuard.cs" + + \ No newline at end of file diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs new file mode 100644 index 0000000000..75d9eb5807 --- /dev/null +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -0,0 +1,25 @@ +namespace ImageSharp +{ + using System.Numerics; + + public partial struct Color + { + internal class BulkOperations : BulkPixelOperations + { + private static readonly int VectorSize = Vector.Count; + + internal static void PackToVector4Aligned( + ArrayPointer source, + ArrayPointer destination, + int count) + { + DebugGuard.IsTrue( + count % VectorSize == 0, + nameof(count), + "Argument 'count' should divisible by Vector.Count!"); + + + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index 0ca6f09120..1375636f4b 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -29,5 +29,137 @@ namespace ImageSharp throw new ArgumentNullException(parameterName); } } + + + /// + /// Verifies that the specified value is less than a maximum value + /// and throws an exception if it is not. + /// + /// The target value, which should be validated. + /// The maximum value. + /// The name of the parameter that is to be checked. + /// The type of the value. + /// + /// is greater than the maximum value. + /// + [Conditional("DEBUG")] + public static void MustBeLessThan(TValue value, TValue max, string parameterName) + where TValue : IComparable + { + if (value.CompareTo(max) >= 0) + { + throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than {max}."); + } + } + + /// + /// Verifies that the specified value is less than or equal to a maximum value + /// and throws an exception if it is not. + /// + /// The target value, which should be validated. + /// The maximum value. + /// The name of the parameter that is to be checked. + /// The type of the value. + /// + /// is greater than the maximum value. + /// + [Conditional("DEBUG")] + public static void MustBeLessThanOrEqualTo(TValue value, TValue max, string parameterName) + where TValue : IComparable + { + if (value.CompareTo(max) > 0) + { + throw new ArgumentOutOfRangeException(parameterName, $"Value must be less than or equal to {max}."); + } + } + + /// + /// Verifies that the specified value is greater than a minimum value + /// and throws an exception if it is not. + /// + /// The target value, which should be validated. + /// The minimum value. + /// The name of the parameter that is to be checked. + /// The type of the value. + /// + /// is less than the minimum value. + /// + [Conditional("DEBUG")] + public static void MustBeGreaterThan(TValue value, TValue min, string parameterName) + where TValue : IComparable + { + if (value.CompareTo(min) <= 0) + { + throw new ArgumentOutOfRangeException( + parameterName, + $"Value must be greater than {min}."); + } + } + + /// + /// Verifies that the specified value is greater than or equal to a minimum value + /// and throws an exception if it is not. + /// + /// The target value, which should be validated. + /// The minimum value. + /// The name of the parameter that is to be checked. + /// The type of the value. + /// + /// is less than the minimum value. + /// + [Conditional("DEBUG")] + public static void MustBeGreaterThanOrEqualTo(TValue value, TValue min, string parameterName) + where TValue : IComparable + { + if (value.CompareTo(min) < 0) + { + throw new ArgumentOutOfRangeException(parameterName, $"Value must be greater than or equal to {min}."); + } + } + + + /// + /// Verifies, that the method parameter with specified target value is true + /// and throws an exception if it is found to be so. + /// + /// + /// The target value, which cannot be false. + /// + /// + /// The name of the parameter that is to be checked. + /// + /// + /// The error message, if any to add to the exception. + /// + /// + /// is false + /// + [Conditional("DEBUG")] + public static void IsTrue(bool target, string parameterName, string message) + { + if (!target) + { + throw new ArgumentException(message, parameterName); + } + } + + /// + /// Verifies, that the method parameter with specified target value is false + /// and throws an exception if it is found to be so. + /// + /// The target value, which cannot be true. + /// The name of the parameter that is to be checked. + /// The error message, if any to add to the exception. + /// + /// is true + /// + [Conditional("DEBUG")] + public static void IsFalse(bool target, string parameterName, string message) + { + if (target) + { + throw new ArgumentException(message, parameterName); + } + } } } \ No newline at end of file From decb84078fc4cb8c4988ffd40e5bb2cb97aa3e5b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 7 Mar 2017 00:45:13 +0100 Subject: [PATCH 45/85] implemented Color.BulkOperations.ToVector4() --- src/ImageSharp/Colors/Color.BulkOperations.cs | 117 ++++++++++++++- src/ImageSharp/Colors/Color.cs | 2 +- .../ImageSharp.Sandbox46.csproj | 3 + .../Colors/BulkPixelOperationsTests.cs | 133 ++++++++++++------ .../Formats/Jpg/JpegUtilityTestFixture.cs | 25 +--- .../TestUtilities/ApproximateFloatComparer.cs | 38 +++++ 6 files changed, 246 insertions(+), 72 deletions(-) create mode 100644 tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 75d9eb5807..9d698b8ac1 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -1,24 +1,129 @@ namespace ImageSharp { + using System; using System.Numerics; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; public partial struct Color { + /// + /// implementation optimized for . + /// internal class BulkOperations : BulkPixelOperations { - private static readonly int VectorSize = Vector.Count; + /// + /// Value type to store -s unpacked into multiple -s. + /// + private struct RGBAUint + { + private uint r; + private uint g; + private uint b; + private uint a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Load(uint p) + { + this.r = p; + this.g = p >> Color.GreenShift; + this.b = p >> Color.BlueShift; + this.a = p >> Color.AlphaShift; + } + } - internal static void PackToVector4Aligned( - ArrayPointer source, - ArrayPointer destination, + /// + /// SIMD optimized bulk implementation of + /// that works only with `count` divisible by . + /// + /// The to the source colors. + /// The to the dstination vectors. + /// The number of pixels to convert. + /// + /// Implementation adapted from: + /// + /// http://stackoverflow.com/a/5362789 + /// + /// + internal static unsafe void ToVector4SimdAligned( + BufferPointer sourceColors, + BufferPointer destVectors, int count) { + int vecSize = Vector.Count; + DebugGuard.IsTrue( - count % VectorSize == 0, + count % vecSize == 0, nameof(count), - "Argument 'count' should divisible by Vector.Count!"); + "Argument 'count' should divisible by Vector.Count!" + ); + + Vector bVec = new Vector(256.0f / 255.0f); + Vector magicInt = new Vector(1191182336); + Vector magicFloat = new Vector(32768.0f); + Vector mask = new Vector(255); + + int rawInputSize = count * 4; + + uint* src = (uint*)sourceColors.PointerAtOffset; + uint* srcEnd = src + count; + + using (PinnedBuffer tempBuf = new PinnedBuffer(rawInputSize + Vector.Count)) + { + uint* tPtr = (uint*)tempBuf.Pointer; + uint[] temp = tempBuf.Array; + float[] fTemp = Unsafe.As(temp); + RGBAUint* dst = (RGBAUint*)tPtr; + + for (; src < srcEnd; src++, dst++) + { + dst->Load(*src); + } + + for (int i = 0; i < rawInputSize; i += vecSize) + { + Vector vi = new Vector(temp, i); + + vi &= mask; + vi |= magicInt; + + Vector vf = Vector.AsVectorSingle(vi); + vf = (vf - magicFloat) * bVec; + vf.CopyTo(fTemp, i); + } + + // TODO: Replace this with an optimized ArrayPointer.Copy() implementation: + uint byteCount = (uint)rawInputSize * sizeof(float); + + if (byteCount > 1024u) + { + Marshal.Copy(fTemp, 0, destVectors.PointerAtOffset, rawInputSize); + } + else + { + Unsafe.CopyBlock((void*)destVectors, tPtr, byteCount); + } + } + } + + /// + internal override void ToVector4(BufferPointer sourceColors, BufferPointer destVectors, int count) + { + int remainder = count % Vector.Count; + + int alignedCount = count - remainder; + if (alignedCount > 0) + { + ToVector4SimdAligned(sourceColors, destVectors, alignedCount); + } + if (remainder > 0) + { + sourceColors = sourceColors.Slice(alignedCount); + destVectors = destVectors.Slice(alignedCount); + base.ToVector4(sourceColors, destVectors, remainder); + } } } } diff --git a/src/ImageSharp/Colors/Color.cs b/src/ImageSharp/Colors/Color.cs index 1ad6f9a643..5977309373 100644 --- a/src/ImageSharp/Colors/Color.cs +++ b/src/ImageSharp/Colors/Color.cs @@ -246,7 +246,7 @@ namespace ImageSharp } /// - public BulkPixelOperations CreateBulkOperations() => new BulkPixelOperations(); + public BulkPixelOperations CreateBulkOperations() => new Color.BulkOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 1d78994860..a8b7ceb333 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -272,6 +272,9 @@ Tests\TestImages.cs + + Tests\TestUtilities\ApproximateFloatComparer.cs + Tests\TestUtilities\Attributes\ImageDataAttributeBase.cs diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 80d5952a1e..41abd9d4a4 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -10,13 +10,32 @@ public class Color : BulkPixelOperationsTests { // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + + [Fact] + public void IsSpecialImplementation() + { + Assert.IsType(BulkPixelOperations.Instance); + } + + [Fact] + public void ToVector4SimdAligned() + { + ImageSharp.Color[] source = CreatePixelTestData(64); + Vector4[] expected = CreateExpectedVector4Data(source); + + TestOperation( + source, + expected, + (s, d) => ImageSharp.Color.BulkOperations.ToVector4SimdAligned(s, d, 64) + ); + } } public class Argb : BulkPixelOperationsTests { // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } [Theory] @@ -32,42 +51,56 @@ where TColor : struct, IPixel { public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; - - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackFromVector4(int count) + + private static BulkPixelOperations Operations => BulkPixelOperations.Instance; + + internal static TColor[] CreateExpectedPixelData(Vector4[] source) { - Vector4[] source = CreateVector4TestData(count); - TColor[] expected = new TColor[count]; + TColor[] expected = new TColor[source.Length]; - for (int i = 0; i < count; i++) + for (int i = 0; i < expected.Length; i++) { expected[i].PackFromVector4(source[i]); } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void PackFromVector4(int count) + { + Vector4[] source = CreateVector4TestData(count); + TColor[] expected = CreateExpectedPixelData(source); TestOperation( source, expected, - (ops, s, d) => ops.PackFromVector4(s, d, count) + (s, d) => Operations.PackFromVector4(s, d, count) ); } - [Theory] - [MemberData(nameof(ArraySizesData))] - public void PackToVector4(int count) + internal static Vector4[] CreateExpectedVector4Data(TColor[] source) { - TColor[] source = CreatePixelTestData(count); - Vector4[] expected = new Vector4[count]; + Vector4[] expected = new Vector4[source.Length]; - for (int i = 0; i < count; i++) + for (int i = 0; i < expected.Length; i++) { expected[i] = source[i].ToVector4(); } + return expected; + } + + [Theory] + [MemberData(nameof(ArraySizesData))] + public void ToVector4(int count) + { + TColor[] source = CreatePixelTestData(count); + Vector4[] expected = CreateExpectedVector4Data(source); TestOperation( source, expected, - (ops, s, d) => ops.ToVector4(s, d, count) + (s, d) => Operations.ToVector4(s, d, count) ); } @@ -89,13 +122,13 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackFromXyzBytes(s, d, count) + (s, d) => Operations.PackFromXyzBytes(s, d, count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToXyzBytes(int count) + public void ToXyzBytes(int count) { TColor[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; @@ -109,7 +142,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.ToXyzBytes(s, d, count) + (s, d) => Operations.ToXyzBytes(s, d, count) ); } @@ -130,13 +163,13 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackFromXyzwBytes(s, d, count) + (s, d) => Operations.PackFromXyzwBytes(s, d, count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToXyzwBytes(int count) + public void ToXyzwBytes(int count) { TColor[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; @@ -150,7 +183,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.ToXyzwBytes(s, d, count) + (s, d) => Operations.ToXyzwBytes(s, d, count) ); } @@ -171,13 +204,13 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackFromZyxBytes(s, d, count) + (s, d) => Operations.PackFromZyxBytes(s, d, count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToZyxBytes(int count) + public void ToZyxBytes(int count) { TColor[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; @@ -191,7 +224,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.ToZyxBytes(s, d, count) + (s, d) => Operations.ToZyxBytes(s, d, count) ); } @@ -212,13 +245,13 @@ TestOperation( source, expected, - (ops, s, d) => ops.PackFromZyxwBytes(s, d, count) + (s, d) => Operations.PackFromZyxwBytes(s, d, count) ); } [Theory] [MemberData(nameof(ArraySizesData))] - public void PackToZyxwBytes(int count) + public void ToZyxwBytes(int count) { TColor[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; @@ -232,7 +265,7 @@ TestOperation( source, expected, - (ops, s, d) => ops.ToZyxwBytes(s, d, count) + (s, d) => Operations.ToZyxwBytes(s, d, count) ); } @@ -262,33 +295,51 @@ this.ExpectedDestBuffer.Dispose(); } + private const float Tolerance = 0.0001f; + public void Verify() { int count = this.ExpectedDestBuffer.Count; - TDest[] expected = this.ExpectedDestBuffer.Array; - TDest[] actual = this.ActualDestBuffer.Array; - for (int i = 0; i < count; i++) + + if (typeof(TDest) == typeof(Vector4)) { - Assert.Equal(expected[i], actual[i]); + Vector4[] expected = this.ExpectedDestBuffer.Array as Vector4[]; + Vector4[] actual = this.ActualDestBuffer.Array as Vector4[]; + + for (int i = 0; i < count; i++) + { + // ReSharper disable PossibleNullReferenceException + Assert.Equal(expected[i], actual[i], new ApproximateFloatComparer(0.001f)); + // ReSharper restore PossibleNullReferenceException + } + } + else + { + TDest[] expected = this.ExpectedDestBuffer.Array; + TDest[] actual = this.ActualDestBuffer.Array; + for (int i = 0; i < count; i++) + { + Assert.Equal(expected[i], actual[i]); + } } } } - private static void TestOperation( + internal static void TestOperation( TSource[] source, TDest[] expected, - Action, BufferPointer, BufferPointer> action) + Action, BufferPointer> action) where TSource : struct where TDest : struct { using (var buffers = new TestBuffers(source, expected)) { - action(BulkPixelOperations.Instance, buffers.Source, buffers.ActualDest); + action(buffers.Source, buffers.ActualDest); buffers.Verify(); } } - private static Vector4[] CreateVector4TestData(int length) + internal static Vector4[] CreateVector4TestData(int length) { Vector4[] result = new Vector4[length]; Random rnd = new Random(42); // Deterministic random values @@ -300,7 +351,7 @@ return result; } - private static TColor[] CreatePixelTestData(int length) + internal static TColor[] CreatePixelTestData(int length) { TColor[] result = new TColor[length]; @@ -315,7 +366,7 @@ return result; } - private static byte[] CreateByteTestData(int length) + internal static byte[] CreateByteTestData(int length) { byte[] result = new byte[length]; Random rnd = new Random(42); // Deterministic random values @@ -326,8 +377,8 @@ } return result; } - - private static Vector4 GetVector(Random rnd) + + internal static Vector4 GetVector(Random rnd) { return new Vector4( (float)rnd.NextDouble(), diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegUtilityTestFixture.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegUtilityTestFixture.cs index 736225680e..252b01138b 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegUtilityTestFixture.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegUtilityTestFixture.cs @@ -4,14 +4,13 @@ // using System.Text; -using ImageSharp.Formats; + using Xunit.Abstractions; // ReSharper disable InconsistentNaming namespace ImageSharp.Tests { using System; - using System.Collections.Generic; using System.Diagnostics; using ImageSharp.Formats.Jpg; @@ -99,28 +98,6 @@ namespace ImageSharp.Tests this.Output.WriteLine(bld.ToString()); } - internal struct ApproximateFloatComparer : IEqualityComparer - { - private readonly float Eps; - - public ApproximateFloatComparer(float eps = 1f) - { - this.Eps = eps; - } - - public bool Equals(float x, float y) - { - float d = x - y; - - return d > -this.Eps && d < this.Eps; - } - - public int GetHashCode(float obj) - { - throw new InvalidOperationException(); - } - } - protected void Print(string msg) { Debug.WriteLine(msg); diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs new file mode 100644 index 0000000000..333b645dea --- /dev/null +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -0,0 +1,38 @@ +namespace ImageSharp.Tests +{ + using System; + using System.Collections.Generic; + using System.Numerics; + + internal struct ApproximateFloatComparer : IEqualityComparer, IEqualityComparer + { + private readonly float Eps; + + public ApproximateFloatComparer(float eps = 1f) + { + this.Eps = eps; + } + + public bool Equals(float x, float y) + { + float d = x - y; + + return d > -this.Eps && d < this.Eps; + } + + public int GetHashCode(float obj) + { + throw new InvalidOperationException(); + } + + public bool Equals(Vector4 a, Vector4 b) + { + return this.Equals(a.X, b.X) && this.Equals(a.Y, b.Y) && this.Equals(a.Z, b.Z) && this.Equals(a.W, b.W); + } + + public int GetHashCode(Vector4 obj) + { + throw new InvalidOperationException(); + } + } +} \ No newline at end of file From ebb581b3f6ffaa3c71a732414b4be1742fdfff34 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 7 Mar 2017 01:53:46 +0100 Subject: [PATCH 46/85] Color.BulkOperations full implementation --- src/ImageSharp/Colors/Color.BulkOperations.cs | 109 ++++++++++++++++++ src/ImageSharp/Common/Memory/BufferPointer.cs | 19 +-- .../Common/Memory/BufferPointer{T}.cs | 4 +- .../Common/Memory/PinnedBuffer{T}.cs | 22 ++++ .../Common/BufferPointerTests.cs | 59 +++++++++- 5 files changed, 192 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 9d698b8ac1..18f9d92a68 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -125,6 +125,115 @@ namespace ImageSharp base.ToVector4(sourceColors, destVectors, remainder); } } + + /// + internal override unsafe void PackFromXyzBytes(BufferPointer sourceBytes, BufferPointer destColors, int count) + { + byte* source = (byte*)sourceBytes; + byte* destination = (byte*)destColors; + + for (int x = 0; x < count; x++) + { + Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24)); + + source += 3; + destination += 4; + } + } + + /// + internal override unsafe void ToXyzBytes(BufferPointer sourceColors, BufferPointer destBytes, int count) + { + byte* source = (byte*)sourceColors; + byte* destination = (byte*)destBytes; + + for (int x = 0; x < count; x++) + { + *destination = *(source + 0); + *(destination + 1) = *(source + 1); + *(destination + 2) = *(source + 2); + + source += 4; + destination += 3; + } + } + + /// + internal override void PackFromXyzwBytes(BufferPointer sourceBytes, BufferPointer destColors, int count) + { + BufferPointer.Copy(sourceBytes, destColors, count); + } + + /// + internal override void ToXyzwBytes(BufferPointer sourceColors, BufferPointer destBytes, int count) + { + BufferPointer.Copy(sourceColors, destBytes, count); + } + + /// + internal override unsafe void PackFromZyxBytes(BufferPointer sourceBytes, BufferPointer destColors, int count) + { + byte* source = (byte*)sourceBytes; + byte* destination = (byte*)destColors; + + for (int x = 0; x < count; x++) + { + Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24)); + + source += 3; + destination += 4; + } + } + + /// + internal override unsafe void ToZyxBytes(BufferPointer sourceColors, BufferPointer destBytes, int count) + { + byte* source = (byte*)sourceColors; + byte* destination = (byte*)destBytes; + + for (int x = 0; x < count; x++) + { + *destination = *(source + 2); + *(destination + 1) = *(source + 1); + *(destination + 2) = *(source + 0); + + source += 4; + destination += 3; + } + } + + /// + internal override unsafe void PackFromZyxwBytes(BufferPointer sourceBytes, BufferPointer destColors, int count) + { + byte* source = (byte*)sourceBytes; + byte* destination = (byte*)destColors; + + for (int x = 0; x < count; x++) + { + Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24)); + + source += 4; + destination += 4; + } + } + + /// + internal override unsafe void ToZyxwBytes(BufferPointer sourceColors, BufferPointer destBytes, int count) + { + byte* source = (byte*)sourceColors; + byte* destination = (byte*)destBytes; + + for (int x = 0; x < count; x++) + { + *destination = *(source + 2); + *(destination + 1) = *(source + 1); + *(destination + 2) = *(source + 0); + *(destination + 3) = *(source + 3); + + source += 4; + destination += 4; + } + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs index c80e22e21d..f8798ba247 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -12,18 +12,7 @@ namespace ImageSharp /// internal static class BufferPointer { - /// - /// Gets a to the beginning of the raw data in 'buffer'. - /// - /// The element type - /// The input - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe BufferPointer Slice(this PinnedBuffer buffer) - where T : struct - { - return new BufferPointer(buffer.Array, (void*)buffer.Pointer); - } + /// /// Copy 'count' number of elements of the same type from 'source' to 'dest' @@ -36,7 +25,7 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int count) where T : struct { - Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(count)); + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf(count)); } /// @@ -50,7 +39,7 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInSource) where T : struct { - Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInSource)); + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf(countInSource)); } /// @@ -64,7 +53,7 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInDest) where T : struct { - Unsafe.CopyBlock((void*)source.PointerAtOffset, (void*)destination.PointerAtOffset, USizeOf(countInDest)); + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf(countInDest)); } /// diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs index fff4e513e1..e05650a709 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -79,7 +79,7 @@ namespace ImageSharp } /// - /// Convertes instance to a raw 'byte*' pointer + /// Converts instance to a raw 'byte*' pointer /// /// The to convert [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -87,7 +87,7 @@ namespace ImageSharp { return (byte*)bufferPointer.PointerAtOffset; } - + /// /// Forms a slice out of the given BufferPointer, beginning at 'offset'. /// diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index 04217a0123..8e5ded0489 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -7,6 +7,7 @@ namespace ImageSharp { using System; using System.Buffers; + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; /// @@ -94,6 +95,27 @@ namespace ImageSharp /// Gets a pointer to the pinned . /// public IntPtr Pointer { get; private set; } + + /// + /// Converts to an . + /// + /// The to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator BufferPointer(PinnedBuffer buffer) + { + return buffer.Slice(); + } + + /// + /// Gets a to the beginning of the raw data in 'buffer'. + /// + /// The element type + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe BufferPointer Slice() + { + return new BufferPointer(this.Array, (void*)this.Pointer); + } /// /// Disposes the instance by unpinning the array, and returning the pooled buffer when necessary. diff --git a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs index 4b5847d53f..a0b91b4c4a 100644 --- a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs @@ -15,12 +15,18 @@ namespace ImageSharp.Tests.Common public double B; + public Foo(int a, double b) + { + this.A = a; + this.B = b; + } + internal static Foo[] CreateArray(int size) { Foo[] result = new Foo[size]; for (int i = 0; i < size; i++) { - result[i] = new Foo() { A = i, B = i }; + result[i] = new Foo(i, i); } return result; } @@ -81,6 +87,12 @@ namespace ImageSharp.Tests.Common public class Copy { + private static void AssertNotDefault(T[] data, int idx) + where T : struct + { + Assert.NotEqual(default(T), data[idx]); + } + [Theory] [InlineData(4)] [InlineData(1500)] @@ -98,7 +110,11 @@ namespace ImageSharp.Tests.Common BufferPointer.Copy(apSource, apDest, count); } + AssertNotDefault(source, 1); + AssertNotDefault(dest, 1); + Assert.Equal(source[0], dest[0]); + Assert.Equal(source[1], dest[1]); Assert.Equal(source[count-1], dest[count-1]); Assert.NotEqual(source[count], dest[count]); } @@ -121,19 +137,31 @@ namespace ImageSharp.Tests.Common BufferPointer.Copy(apSource, apDest, count); } + AssertNotDefault(source, 1); + Assert.True(ElementsAreEqual(source, dest, 0)); Assert.True(ElementsAreEqual(source, dest, count - 1)); Assert.False(ElementsAreEqual(source, dest, count)); } + private static byte[] CreateTestBytes(int count) + { + byte[] result = new byte[count]; + for (int i = 0; i < result.Length; i++) + { + result[i] = (byte)(i % 255); + } + return result; + } + [Theory] [InlineData(4)] [InlineData(1500)] public void BytesToGeneric(int count) { - int destCount = count * sizeof(Foo); - byte[] source = new byte[destCount + sizeof(Foo) + 1]; - Foo[] dest = Foo.CreateArray(count + 2); + int srcCount = count * sizeof(Foo); + byte[] source = CreateTestBytes(srcCount); + Foo[] dest = new Foo[count + 2]; fixed(byte* pSource = source) fixed (Foo* pDest = dest) @@ -144,10 +172,33 @@ namespace ImageSharp.Tests.Common BufferPointer.Copy(apSource, apDest, count); } + AssertNotDefault(source, sizeof(Foo) + 1); + AssertNotDefault(dest, 1); + Assert.True(ElementsAreEqual(dest, source, 0)); + Assert.True(ElementsAreEqual(dest, source, 1)); Assert.True(ElementsAreEqual(dest, source, count - 1)); Assert.False(ElementsAreEqual(dest, source, count)); } + + [Fact] + public void ColorToBytes() + { + Color[] colors = { new Color(0, 1, 2, 3), new Color(4, 5, 6, 7), new Color(8, 9, 10, 11), }; + + using (PinnedBuffer colorBuf = new PinnedBuffer(colors)) + using (PinnedBuffer byteBuf = new PinnedBuffer(colors.Length*4)) + { + BufferPointer.Copy(colorBuf, byteBuf, colorBuf.Count); + + byte[] a = byteBuf.Array; + + for (int i = 0; i < byteBuf.Count; i++) + { + Assert.Equal((byte)i, a[i]); + } + } + } private static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index) { From 82a791878a5edecb9c6b2c7a59f030a3fc2b47ae Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 7 Mar 2017 03:20:07 +0100 Subject: [PATCH 47/85] optimized BufferPointer.Copy() implementations --- src/ImageSharp/Colors/Color.BulkOperations.cs | 14 +- src/ImageSharp/Common/Memory/BufferPointer.cs | 45 +++++- .../Common/Memory/BufferPointer{T}.cs | 17 ++- .../Common/Memory/PinnedBuffer{T}.cs | 12 ++ .../ImageSharp.Sandbox46.csproj | 3 + .../Colors/BulkPixelOperationsTests.cs | 2 +- .../Common/BufferPointerTests.cs | 136 +++++++++++++++--- 7 files changed, 191 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 18f9d92a68..8ec332a911 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -59,8 +59,8 @@ namespace ImageSharp ); Vector bVec = new Vector(256.0f / 255.0f); - Vector magicInt = new Vector(1191182336); Vector magicFloat = new Vector(32768.0f); + Vector magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f Vector mask = new Vector(255); int rawInputSize = count * 4; @@ -92,17 +92,7 @@ namespace ImageSharp vf.CopyTo(fTemp, i); } - // TODO: Replace this with an optimized ArrayPointer.Copy() implementation: - uint byteCount = (uint)rawInputSize * sizeof(float); - - if (byteCount > 1024u) - { - Marshal.Copy(fTemp, 0, destVectors.PointerAtOffset, rawInputSize); - } - else - { - Unsafe.CopyBlock((void*)destVectors, tPtr, byteCount); - } + BufferPointer.Copy(tempBuf, (BufferPointer) destVectors, rawInputSize); } } diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs index f8798ba247..cc544341ee 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -6,13 +6,17 @@ namespace ImageSharp { using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; /// /// Utility methods for /// internal static class BufferPointer { - + /// + /// It's worth to use Marshal.Copy() over this size. + /// + private const uint ByteCountThreshold = 1024u; /// /// Copy 'count' number of elements of the same type from 'source' to 'dest' @@ -25,7 +29,19 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int count) where T : struct { - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf(count)); + int elementSize = Unsafe.SizeOf(); + uint byteCount = (uint) (count * elementSize); + + if (byteCount > ByteCountThreshold && elementSize == sizeof(int)) + { + // TODO: Add the optimized path for non int-compatible types + int[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + } + else + { + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + } } /// @@ -39,7 +55,19 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInSource) where T : struct { - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf(countInSource)); + int elementSize = Unsafe.SizeOf(); + uint byteCount = (uint)(countInSource * elementSize); + + if (byteCount > ByteCountThreshold && elementSize == sizeof(int)) + { + // TODO: Add the optimized path for non int-compatible types + int[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, countInSource); + } + else + { + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + } } /// @@ -53,7 +81,16 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInDest) where T : struct { - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, USizeOf(countInDest)); + int byteCount = SizeOf(countInDest); + + if (byteCount > (int)ByteCountThreshold) + { + Marshal.Copy(source.Array, source.Offset, destination.PointerAtOffset, byteCount); + } + else + { + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)byteCount); + } } /// diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs index e05650a709..a9935c5ddc 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -87,7 +87,22 @@ namespace ImageSharp { return (byte*)bufferPointer.PointerAtOffset; } - + + /// + /// Converts instance to + /// setting it's and to correct values. + /// + /// The to convert + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator BufferPointer(BufferPointer source) + { + BufferPointer result = default(BufferPointer); + result.Array = Unsafe.As(source.Array); + result.Offset = source.Offset * Unsafe.SizeOf(); + result.PointerAtOffset = source.PointerAtOffset; + return result; + } + /// /// Forms a slice out of the given BufferPointer, beginning at 'offset'. /// diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index 8e5ded0489..ea76252c5f 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -117,6 +117,18 @@ namespace ImageSharp return new BufferPointer(this.Array, (void*)this.Pointer); } + /// + /// Gets a to the beginning of the raw data in 'buffer'. + /// + /// The element type + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public unsafe BufferPointer Slice(int offset) + { + return new BufferPointer(this.Array, (void*)this.Pointer, offset); + } + + /// /// Disposes the instance by unpinning the array, and returning the pooled buffer when necessary. /// diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index a8b7ceb333..4d3548c818 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -212,6 +212,9 @@ Tests\Colors\BulkPixelOperationsTests.cs + + Tests\Common\BufferPointerTests.cs + Tests\Common\PinnedBufferTests.cs diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 41abd9d4a4..fa1b536f3b 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -17,7 +17,7 @@ { Assert.IsType(BulkPixelOperations.Instance); } - + [Fact] public void ToVector4SimdAligned() { diff --git a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs index a0b91b4c4a..fc26bf0972 100644 --- a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs @@ -26,11 +26,26 @@ namespace ImageSharp.Tests.Common Foo[] result = new Foo[size]; for (int i = 0; i < size; i++) { - result[i] = new Foo(i, i); + result[i] = new Foo(i+1, i+1); } return result; } } + + [Fact] + public void AsBytes() + { + Foo[] fooz = { new Foo(1, 2), new Foo(3, 4), new Foo(5, 6) }; + + using (PinnedBuffer colorBuf = new PinnedBuffer(fooz)) + { + BufferPointer orig = colorBuf.Slice(1); + BufferPointer asBytes = (BufferPointer < byte > )orig; + + Assert.Equal(asBytes.Offset, sizeof(Foo)); + Assert.Equal(orig.PointerAtOffset, asBytes.PointerAtOffset); + } + } [Fact] public void ConstructWithoutOffset() @@ -93,6 +108,27 @@ namespace ImageSharp.Tests.Common Assert.NotEqual(default(T), data[idx]); } + + private static byte[] CreateTestBytes(int count) + { + byte[] result = new byte[count]; + for (int i = 0; i < result.Length; i++) + { + result[i] = (byte)((i % 200) + 1); + } + return result; + } + + private static int[] CreateTestInts(int count) + { + int[] result = new int[count]; + for (int i = 0; i < result.Length; i++) + { + result[i] = i + 1; + } + return result; + } + [Theory] [InlineData(4)] [InlineData(1500)] @@ -104,56 +140,102 @@ namespace ImageSharp.Tests.Common fixed (Foo* pSource = source) fixed (Foo* pDest = dest) { - BufferPointer apSource = new BufferPointer(source, pSource); - BufferPointer apDest = new BufferPointer(dest, pDest); + BufferPointer apSource = new BufferPointer(source, pSource, 1); + BufferPointer apDest = new BufferPointer(dest, pDest, 1); - BufferPointer.Copy(apSource, apDest, count); + BufferPointer.Copy(apSource, apDest, count-1); } AssertNotDefault(source, 1); AssertNotDefault(dest, 1); - Assert.Equal(source[0], dest[0]); + Assert.NotEqual(source[0], dest[0]); Assert.Equal(source[1], dest[1]); + Assert.Equal(source[2], dest[2]); Assert.Equal(source[count-1], dest[count-1]); Assert.NotEqual(source[count], dest[count]); } - + + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void IntToInt(int count) + { + int[] source = CreateTestInts(count+2); + int[] dest = new int[count + 5]; + + fixed (int* pSource = source) + fixed (int* pDest = dest) + { + BufferPointer apSource = new BufferPointer(source, pSource, 1); + BufferPointer apDest = new BufferPointer(dest, pDest, 1); + + BufferPointer.Copy(apSource, apDest, count -1); + } + + AssertNotDefault(source, 1); + AssertNotDefault(dest, 1); + + Assert.NotEqual(source[0], dest[0]); + Assert.Equal(source[1], dest[1]); + Assert.Equal(source[2], dest[2]); + Assert.Equal(source[count - 1], dest[count - 1]); + Assert.NotEqual(source[count], dest[count]); + } + [Theory] [InlineData(4)] [InlineData(1500)] public void GenericToBytes(int count) { int destCount = count * sizeof(Foo); - Foo[] source = Foo.CreateArray(count + 2); - byte[] dest = new byte[destCount + sizeof(Foo) + 1]; + Foo[] source = Foo.CreateArray(count+2); + byte[] dest = new byte[destCount + sizeof(Foo)*2]; fixed (Foo* pSource = source) fixed (byte* pDest = dest) { - BufferPointer apSource = new BufferPointer(source, pSource); - BufferPointer apDest = new BufferPointer(dest, pDest); + BufferPointer apSource = new BufferPointer(source, pSource, 1); + BufferPointer apDest = new BufferPointer(dest, pDest, sizeof(Foo)); - BufferPointer.Copy(apSource, apDest, count); + BufferPointer.Copy(apSource, apDest, count - 1); } AssertNotDefault(source, 1); - Assert.True(ElementsAreEqual(source, dest, 0)); + Assert.False(ElementsAreEqual(source, dest, 0)); + Assert.True(ElementsAreEqual(source, dest, 1)); + Assert.True(ElementsAreEqual(source, dest, 2)); Assert.True(ElementsAreEqual(source, dest, count - 1)); Assert.False(ElementsAreEqual(source, dest, count)); } - - private static byte[] CreateTestBytes(int count) + + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void IntToBytes(int count) { - byte[] result = new byte[count]; - for (int i = 0; i < result.Length; i++) + int destCount = count * sizeof(int); + int[] source = CreateTestInts(count+2); + byte[] dest = new byte[destCount + sizeof(int) + 1]; + + fixed (int* pSource = source) + fixed (byte* pDest = dest) { - result[i] = (byte)(i % 255); + BufferPointer apSource = new BufferPointer(source, pSource); + BufferPointer apDest = new BufferPointer(dest, pDest); + + BufferPointer.Copy(apSource, apDest, count); } - return result; + + AssertNotDefault(source, 1); + + Assert.True(ElementsAreEqual(source, dest, 0)); + Assert.True(ElementsAreEqual(source, dest, count - 1)); + Assert.False(ElementsAreEqual(source, dest, count)); } + [Theory] [InlineData(4)] [InlineData(1500)] @@ -199,8 +281,8 @@ namespace ImageSharp.Tests.Common } } } - - private static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index) + + internal static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index) { fixed (Foo* pArray = array) fixed (byte* pRaw = rawArray) @@ -213,6 +295,20 @@ namespace ImageSharp.Tests.Common return val1.Equals(val2); } } + + internal static bool ElementsAreEqual(int[] array, byte[] rawArray, int index) + { + fixed (int* pArray = array) + fixed (byte* pRaw = rawArray) + { + int* pCasted = (int*)pRaw; + + int val1 = pArray[index]; + int val2 = pCasted[index]; + + return val1.Equals(val2); + } + } } } } \ No newline at end of file From 20c97ddfcbbbd9ea7310d2f0aef2d6b1a7ca12ba Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 7 Mar 2017 03:46:42 +0100 Subject: [PATCH 48/85] even better BufferPointer.Copy() --- src/ImageSharp/Common/Memory/BufferPointer.cs | 95 +++++++++++++++---- 1 file changed, 75 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs index cc544341ee..10a5c2db2c 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -5,6 +5,7 @@ namespace ImageSharp { + using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -29,19 +30,17 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int count) where T : struct { - int elementSize = Unsafe.SizeOf(); - uint byteCount = (uint) (count * elementSize); + uint byteCount = USizeOf(count); - if (byteCount > ByteCountThreshold && elementSize == sizeof(int)) + if (byteCount > ByteCountThreshold) { - // TODO: Add the optimized path for non int-compatible types - int[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - } - else - { - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + if (TryMarshalCopy(source, destination, count)) + { + return; + } } + + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); } /// @@ -55,19 +54,17 @@ namespace ImageSharp public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInSource) where T : struct { - int elementSize = Unsafe.SizeOf(); - uint byteCount = (uint)(countInSource * elementSize); + uint byteCount = USizeOf(countInSource); - if (byteCount > ByteCountThreshold && elementSize == sizeof(int)) - { - // TODO: Add the optimized path for non int-compatible types - int[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, countInSource); - } - else + if (byteCount > ByteCountThreshold) { - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + if (TryMarshalCopy(source, destination, countInSource)) + { + return; + } } + + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); } /// @@ -113,5 +110,63 @@ namespace ImageSharp public static uint USizeOf(int count) where T : struct => (uint)SizeOf(count); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryMarshalCopy(BufferPointer source, BufferPointer destination, int count) + where TSource : struct + where TDest : struct + { + // Pattern Based On: + // https://github.com/dotnet/corefx/blob/master/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs#L12 + // + // Note: The following patterns are used throughout the code here and are described here + // + // PATTERN: + // if (typeof(T) == typeof(Int32)) { ... } + // else if (typeof(T) == typeof(Single)) { ... } + // EXPLANATION: + // At runtime, each instantiation of BufferPointer will be type-specific, and each of these typeof blocks will be eliminated, + // as typeof(T) is a (JIT) compile-time constant for each instantiation. This design was chosen to eliminate any overhead from + // delegates and other patterns. + + if (typeof(TSource) == typeof(long)) + { + long[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + return true; + } + else if (typeof(TSource) == typeof(int)) + { + int[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + return true; + } + else if (typeof(TSource) == typeof(uint)) + { + int[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + return true; + } + else if (typeof(TSource) == typeof(short)) + { + short[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + return true; + } + else if (typeof(TSource) == typeof(ushort)) + { + short[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + return true; + } + else if (typeof(TSource) == typeof(byte)) + { + byte[] srcArray = Unsafe.As(source.Array); + Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); + return true; + } + + return false; + } } } \ No newline at end of file From 126471b841e4eff8b07b54eaa004bbc071a4cd90 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 7 Mar 2017 03:51:25 +0100 Subject: [PATCH 49/85] naming --- src/ImageSharp/Colors/Color.BulkOperations.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 8ec332a911..2488c643fe 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -15,7 +15,7 @@ namespace ImageSharp /// /// Value type to store -s unpacked into multiple -s. /// - private struct RGBAUint + private struct UnpackedRGBA { private uint r; private uint g; @@ -63,24 +63,24 @@ namespace ImageSharp Vector magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f Vector mask = new Vector(255); - int rawInputSize = count * 4; + int unpackedRawCount = count * 4; uint* src = (uint*)sourceColors.PointerAtOffset; uint* srcEnd = src + count; - using (PinnedBuffer tempBuf = new PinnedBuffer(rawInputSize + Vector.Count)) + using (PinnedBuffer tempBuf = new PinnedBuffer(unpackedRawCount + Vector.Count)) { uint* tPtr = (uint*)tempBuf.Pointer; uint[] temp = tempBuf.Array; float[] fTemp = Unsafe.As(temp); - RGBAUint* dst = (RGBAUint*)tPtr; + UnpackedRGBA* dst = (UnpackedRGBA*)tPtr; for (; src < srcEnd; src++, dst++) { dst->Load(*src); } - for (int i = 0; i < rawInputSize; i += vecSize) + for (int i = 0; i < unpackedRawCount; i += vecSize) { Vector vi = new Vector(temp, i); @@ -92,7 +92,7 @@ namespace ImageSharp vf.CopyTo(fTemp, i); } - BufferPointer.Copy(tempBuf, (BufferPointer) destVectors, rawInputSize); + BufferPointer.Copy(tempBuf, (BufferPointer) destVectors, unpackedRawCount); } } From 19251fe4feca427c8d2a01909aebe4270af7af65 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 01:13:14 +0100 Subject: [PATCH 50/85] StyleStalin --- src/ImageSharp/Colors/Color.BulkOperations.cs | 59 +++++++++++-------- src/ImageSharp/Common/Helpers/DebugGuard.cs | 2 - src/ImageSharp/Common/Memory/BufferPointer.cs | 9 ++- .../Common/Memory/BufferPointer{T}.cs | 2 +- .../Common/Memory/PinnedBuffer{T}.cs | 10 ++-- 5 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 2488c643fe..3a1d667528 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -1,3 +1,8 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + namespace ImageSharp { using System; @@ -5,6 +10,9 @@ namespace ImageSharp using System.Runtime.CompilerServices; using System.Runtime.InteropServices; + /// + /// Conains the definition of + /// public partial struct Color { /// @@ -13,27 +21,7 @@ namespace ImageSharp internal class BulkOperations : BulkPixelOperations { /// - /// Value type to store -s unpacked into multiple -s. - /// - private struct UnpackedRGBA - { - private uint r; - private uint g; - private uint b; - private uint a; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Load(uint p) - { - this.r = p; - this.g = p >> Color.GreenShift; - this.b = p >> Color.BlueShift; - this.a = p >> Color.AlphaShift; - } - } - - /// - /// SIMD optimized bulk implementation of + /// SIMD optimized bulk implementation of /// that works only with `count` divisible by . /// /// The to the source colors. @@ -55,8 +43,7 @@ namespace ImageSharp DebugGuard.IsTrue( count % vecSize == 0, nameof(count), - "Argument 'count' should divisible by Vector.Count!" - ); + "Argument 'count' should divisible by Vector.Count!"); Vector bVec = new Vector(256.0f / 255.0f); Vector magicFloat = new Vector(32768.0f); @@ -64,7 +51,7 @@ namespace ImageSharp Vector mask = new Vector(255); int unpackedRawCount = count * 4; - + uint* src = (uint*)sourceColors.PointerAtOffset; uint* srcEnd = src + count; @@ -92,7 +79,7 @@ namespace ImageSharp vf.CopyTo(fTemp, i); } - BufferPointer.Copy(tempBuf, (BufferPointer) destVectors, unpackedRawCount); + BufferPointer.Copy(tempBuf, (BufferPointer)destVectors, unpackedRawCount); } } @@ -120,7 +107,7 @@ namespace ImageSharp internal override unsafe void PackFromXyzBytes(BufferPointer sourceBytes, BufferPointer destColors, int count) { byte* source = (byte*)sourceBytes; - byte* destination = (byte*)destColors; + byte* destination = (byte*)destColors; for (int x = 0; x < count; x++) { @@ -224,6 +211,26 @@ namespace ImageSharp destination += 4; } } + + /// + /// Value type to store -s unpacked into multiple -s. + /// + private struct UnpackedRGBA + { + private uint r; + private uint g; + private uint b; + private uint a; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Load(uint p) + { + this.r = p; + this.g = p >> Color.GreenShift; + this.b = p >> Color.BlueShift; + this.a = p >> Color.AlphaShift; + } + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index 1375636f4b..c1fa461913 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -30,7 +30,6 @@ namespace ImageSharp } } - /// /// Verifies that the specified value is less than a maximum value /// and throws an exception if it is not. @@ -117,7 +116,6 @@ namespace ImageSharp } } - /// /// Verifies, that the method parameter with specified target value is true /// and throws an exception if it is found to be so. diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs index 10a5c2db2c..e600f41882 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -63,7 +63,7 @@ namespace ImageSharp return; } } - + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); } @@ -110,13 +110,13 @@ namespace ImageSharp public static uint USizeOf(int count) where T : struct => (uint)SizeOf(count); - + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryMarshalCopy(BufferPointer source, BufferPointer destination, int count) - where TSource : struct + where TSource : struct where TDest : struct { - // Pattern Based On: + // Pattern Based On: // https://github.com/dotnet/corefx/blob/master/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs#L12 // // Note: The following patterns are used throughout the code here and are described here @@ -128,7 +128,6 @@ namespace ImageSharp // At runtime, each instantiation of BufferPointer will be type-specific, and each of these typeof blocks will be eliminated, // as typeof(T) is a (JIT) compile-time constant for each instantiation. This design was chosen to eliminate any overhead from // delegates and other patterns. - if (typeof(TSource) == typeof(long)) { long[] srcArray = Unsafe.As(source.Array); diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs index a9935c5ddc..fe79e064e8 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -89,7 +89,7 @@ namespace ImageSharp } /// - /// Converts instance to + /// Converts instance to /// setting it's and to correct values. /// /// The to convert diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index ea76252c5f..e902388882 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -95,7 +95,7 @@ namespace ImageSharp /// Gets a pointer to the pinned . /// public IntPtr Pointer { get; private set; } - + /// /// Converts to an . /// @@ -107,9 +107,8 @@ namespace ImageSharp } /// - /// Gets a to the beginning of the raw data in 'buffer'. + /// Gets a to the beginning of the raw data of the buffer. /// - /// The element type /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe BufferPointer Slice() @@ -118,9 +117,9 @@ namespace ImageSharp } /// - /// Gets a to the beginning of the raw data in 'buffer'. + /// Gets a to an offseted position inside the buffer. /// - /// The element type + /// The offset /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe BufferPointer Slice(int offset) @@ -128,7 +127,6 @@ namespace ImageSharp return new BufferPointer(this.Array, (void*)this.Pointer, offset); } - /// /// Disposes the instance by unpinning the array, and returning the pooled buffer when necessary. /// From 05a23b93a6be2cb4db41f17e8ee51c46921301e7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 01:50:31 +0100 Subject: [PATCH 51/85] Using BulkPixelOperations in PixelAccessor --- src/ImageSharp/Image.cs | 12 -- src/ImageSharp/Image/ImageBase{TColor}.cs | 2 +- src/ImageSharp/Image/PixelAccessor{TColor}.cs | 155 +++++++----------- src/ImageSharp/Image/PixelArea{TColor}.cs | 10 ++ src/ImageSharp/ImageFrame.cs | 52 ------ src/ImageSharp/PixelAccessor.cs | 153 ----------------- .../Color/Bulk/PixelAccessorVirtualCopy.cs | 2 +- .../Image/PixelAccessorTests.cs | 44 +---- 8 files changed, 71 insertions(+), 359 deletions(-) delete mode 100644 src/ImageSharp/ImageFrame.cs delete mode 100644 src/ImageSharp/PixelAccessor.cs diff --git a/src/ImageSharp/Image.cs b/src/ImageSharp/Image.cs index af31eff792..8bfd8ee1a3 100644 --- a/src/ImageSharp/Image.cs +++ b/src/ImageSharp/Image.cs @@ -223,17 +223,5 @@ namespace ImageSharp : base(other) { } - - /// - public override PixelAccessor Lock() - { - return new PixelAccessor(this); - } - - /// - internal override ImageFrame ToFrame() - { - return new ImageFrame(this); - } } } diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 2badc008a2..830318b32b 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -150,7 +150,7 @@ namespace ImageSharp } /// - public virtual PixelAccessor Lock() + public PixelAccessor Lock() { return new PixelAccessor(this); } diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index e104b8ae77..a106765652 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -15,7 +15,7 @@ namespace ImageSharp /// Provides per-pixel access to generic pixels. /// /// The pixel format. - public unsafe class PixelAccessor : IDisposable + public sealed unsafe class PixelAccessor : IDisposable where TColor : struct, IPixel { /// @@ -91,7 +91,7 @@ namespace ImageSharp /// /// Gets the pixel buffer array. /// - public TColor[] PixelBuffer => this.pixelBuffer.Array; + public TColor[] PixelArray => this.pixelBuffer.Array; /// /// Gets the pointer to the pixel buffer. @@ -123,6 +123,8 @@ namespace ImageSharp /// public ParallelOptions ParallelOptions { get; } + private static BulkPixelOperations Operations => BulkPixelOperations.Instance; + /// /// Gets or sets the pixel at the specified position. /// @@ -236,6 +238,17 @@ namespace ImageSharp Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height)); } + /// + /// Gets a to the row 'y' beginning from the pixel at 'x'. + /// + /// The x coordinate + /// The y coordinate + /// The + internal BufferPointer GetRowPointer(int x, int y) + { + return this.pixelBuffer.Slice((y * this.Width) + x); + } + /// /// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!! /// @@ -270,24 +283,15 @@ namespace ImageSharp /// The target row index. /// The width. /// The height. - protected virtual void CopyFromZyx(PixelArea area, int targetX, int targetY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyFromZyx(PixelArea area, int targetX, int targetY, int width, int height) { - TColor packed = default(TColor); - int size = Unsafe.SizeOf(); - for (int y = 0; y < height; y++) { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - packed.PackFromBytes(*(source + 2), *(source + 1), *source, 255); - Unsafe.Write(destination, packed); + BufferPointer source = area.GetRowPointer(y); + BufferPointer destination = this.GetRowPointer(targetX, targetY + y); - source += 3; - destination += size; - } + Operations.PackFromZyxBytes(source, destination, width); } } @@ -299,24 +303,15 @@ namespace ImageSharp /// The target row index. /// The width. /// The height. - protected virtual void CopyFromZyxw(PixelArea area, int targetX, int targetY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyFromZyxw(PixelArea area, int targetX, int targetY, int width, int height) { - TColor packed = default(TColor); - int size = Unsafe.SizeOf(); - for (int y = 0; y < height; y++) { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - packed.PackFromBytes(*(source + 2), *(source + 1), *source, *(source + 3)); - Unsafe.Write(destination, packed); + BufferPointer source = area.GetRowPointer(y); + BufferPointer destination = this.GetRowPointer(targetX, targetY + y); - source += 4; - destination += size; - } + Operations.PackFromZyxwBytes(source, destination, width); } } @@ -328,24 +323,15 @@ namespace ImageSharp /// The target row index. /// The width. /// The height. - protected virtual void CopyFromXyz(PixelArea area, int targetX, int targetY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyFromXyz(PixelArea area, int targetX, int targetY, int width, int height) { - TColor packed = default(TColor); - int size = Unsafe.SizeOf(); - for (int y = 0; y < height; y++) { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - packed.PackFromBytes(*source, *(source + 1), *(source + 2), 255); - Unsafe.Write(destination, packed); + BufferPointer source = area.GetRowPointer(y); + BufferPointer destination = this.GetRowPointer(targetX, targetY + y); - source += 3; - destination += size; - } + Operations.PackFromXyzBytes(source, destination, width); } } @@ -357,24 +343,14 @@ namespace ImageSharp /// The target row index. /// The width. /// The height. - protected virtual void CopyFromXyzw(PixelArea area, int targetX, int targetY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyFromXyzw(PixelArea area, int targetX, int targetY, int width, int height) { - TColor packed = default(TColor); - int size = Unsafe.SizeOf(); - for (int y = 0; y < height; y++) { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - packed.PackFromBytes(*source, *(source + 1), *(source + 2), *(source + 3)); - Unsafe.Write(destination, packed); - - source += 4; - destination += size; - } + BufferPointer source = area.GetRowPointer(y); + BufferPointer destination = this.GetRowPointer(targetX, targetY + y); + Operations.PackFromXyzwBytes(source, destination, width); } } @@ -386,16 +362,14 @@ namespace ImageSharp /// The source row index. /// The width. /// The height. - protected virtual void CopyToZyx(PixelArea area, int sourceX, int sourceY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyToZyx(PixelArea area, int sourceX, int sourceY, int width, int height) { for (int y = 0; y < height; y++) { - int offset = y * area.RowStride; - for (int x = 0; x < width; x++) - { - this[sourceX + x, sourceY + y].ToZyxBytes(area.Bytes, offset); - offset += 3; - } + BufferPointer source = this.GetRowPointer(sourceX, sourceY + y); + BufferPointer destination = area.GetRowPointer(y); + Operations.ToZyxBytes(source, destination, width); } } @@ -407,16 +381,14 @@ namespace ImageSharp /// The source row index. /// The width. /// The height. - protected virtual void CopyToZyxw(PixelArea area, int sourceX, int sourceY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyToZyxw(PixelArea area, int sourceX, int sourceY, int width, int height) { for (int y = 0; y < height; y++) { - int offset = y * area.RowStride; - for (int x = 0; x < width; x++) - { - this[sourceX + x, sourceY + y].ToZyxwBytes(area.Bytes, offset); - offset += 4; - } + BufferPointer source = this.GetRowPointer(sourceX, sourceY + y); + BufferPointer destination = area.GetRowPointer(y); + Operations.ToZyxwBytes(source, destination, width); } } @@ -428,16 +400,14 @@ namespace ImageSharp /// The source row index. /// The width. /// The height. - protected virtual void CopyToXyz(PixelArea area, int sourceX, int sourceY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyToXyz(PixelArea area, int sourceX, int sourceY, int width, int height) { for (int y = 0; y < height; y++) { - int offset = y * area.RowStride; - for (int x = 0; x < width; x++) - { - this[sourceX + x, sourceY + y].ToXyzBytes(area.Bytes, offset); - offset += 3; - } + BufferPointer source = this.GetRowPointer(sourceX, sourceY + y); + BufferPointer destination = area.GetRowPointer(y); + Operations.ToXyzBytes(source, destination, width); } } @@ -449,32 +419,17 @@ namespace ImageSharp /// The source row index. /// The width. /// The height. - protected virtual void CopyToXyzw(PixelArea area, int sourceX, int sourceY, int width, int height) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CopyToXyzw(PixelArea area, int sourceX, int sourceY, int width, int height) { for (int y = 0; y < height; y++) { - int offset = y * area.RowStride; - for (int x = 0; x < width; x++) - { - this[sourceX + x, sourceY + y].ToXyzwBytes(area.Bytes, offset); - offset += 4; - } + BufferPointer source = this.GetRowPointer(sourceX, sourceY + y); + BufferPointer destination = area.GetRowPointer(y); + Operations.ToXyzwBytes(source, destination, width); } } - /// - /// Gets the pointer at the specified row. - /// - /// The column index. - /// The row index. - /// - /// The . - /// - protected byte* GetRowPointer(int x, int y) - { - return this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf()); - } - private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels) { this.SetPixelBufferUnsafe(width, height, new PinnedBuffer(width * height, pixels)); diff --git a/src/ImageSharp/Image/PixelArea{TColor}.cs b/src/ImageSharp/Image/PixelArea{TColor}.cs index c54de12d6c..be6debba2f 100644 --- a/src/ImageSharp/Image/PixelArea{TColor}.cs +++ b/src/ImageSharp/Image/PixelArea{TColor}.cs @@ -203,6 +203,16 @@ namespace ImageSharp Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowStride * this.Height)); } + /// + /// Gets a to the row y. + /// + /// The y coordinate + /// The + internal BufferPointer GetRowPointer(int y) + { + return this.byteBuffer.Slice(y * this.RowStride); + } + /// /// Gets component count for the given order. /// diff --git a/src/ImageSharp/ImageFrame.cs b/src/ImageSharp/ImageFrame.cs deleted file mode 100644 index be654111df..0000000000 --- a/src/ImageSharp/ImageFrame.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System.Diagnostics; - - /// - /// An optimized frame for the class. - /// - [DebuggerDisplay("ImageFrame: {Width}x{Height}")] - public sealed class ImageFrame : ImageFrame - { - /// - /// Initializes a new instance of the class. - /// - /// The width of the image in pixels. - /// The height of the image in pixels. - /// - /// The configuration providing initialization code which allows extending the library. - /// - public ImageFrame(int width, int height, Configuration configuration = null) - : base(width, height, configuration) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The image to create the frame from. - /// - public ImageFrame(ImageBase image) - : base(image) - { - } - - /// - public override PixelAccessor Lock() - { - return new PixelAccessor(this); - } - - /// - internal override ImageFrame Clone() - { - return new ImageFrame(this); - } - } -} diff --git a/src/ImageSharp/PixelAccessor.cs b/src/ImageSharp/PixelAccessor.cs deleted file mode 100644 index 7827e7b47b..0000000000 --- a/src/ImageSharp/PixelAccessor.cs +++ /dev/null @@ -1,153 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -namespace ImageSharp -{ - using System.Runtime.CompilerServices; - - /// - /// An optimized pixel accessor for the class. - /// - public sealed unsafe class PixelAccessor : PixelAccessor - { - /// - /// Initializes a new instance of the class. - /// - /// The image to provide pixel access for. - public PixelAccessor(ImageBase image) - : base(image) - { - } - - /// - protected override void CopyFromXyzw(PixelArea area, int targetX, int targetY, int width, int height) - { - uint byteCount = (uint)width * 4; - - for (int y = 0; y < height; y++) - { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - Unsafe.CopyBlock(destination, source, byteCount); - } - } - - /// - protected override void CopyFromXyz(PixelArea area, int targetX, int targetY, int width, int height) - { - for (int y = 0; y < height; y++) - { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24)); - - source += 3; - destination += 4; - } - } - } - - /// - protected override void CopyFromZyx(PixelArea area, int targetX, int targetY, int width, int height) - { - for (int y = 0; y < height; y++) - { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24)); - - source += 3; - destination += 4; - } - } - } - - /// - protected override void CopyFromZyxw(PixelArea area, int targetX, int targetY, int width, int height) - { - for (int y = 0; y < height; y++) - { - byte* source = area.PixelBase + (y * area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - for (int x = 0; x < width; x++) - { - Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24)); - - source += 4; - destination += 4; - } - } - } - - /// - protected override void CopyToZyx(PixelArea area, int sourceX, int sourceY, int width, int height) - { - for (int y = 0; y < height; y++) - { - byte* source = this.GetRowPointer(sourceX, sourceY + y); - byte* destination = area.PixelBase + (y * area.RowStride); - - for (int x = 0; x < width; x++) - { - *destination = *(source + 2); - *(destination + 1) = *(source + 1); - *(destination + 2) = *(source + 0); - - source += 4; - destination += 3; - } - } - } - - /// - protected override void CopyToXyz(PixelArea area, int sourceX, int sourceY, int width, int height) - { - for (int y = 0; y < height; y++) - { - byte* source = this.GetRowPointer(sourceX, sourceY + y); - byte* destination = area.PixelBase + (y * area.RowStride); - - for (int x = 0; x < width; x++) - { - *destination = *(source + 0); - *(destination + 1) = *(source + 1); - *(destination + 2) = *(source + 2); - - source += 4; - destination += 3; - } - } - } - - /// - protected override void CopyToZyxw(PixelArea area, int sourceX, int sourceY, int width, int height) - { - for (int y = 0; y < height; y++) - { - byte* source = this.GetRowPointer(sourceX, sourceY + y); - byte* destination = area.PixelBase + (y * area.RowStride); - - for (int x = 0; x < width; x++) - { - *destination = *(source + 2); - *(destination + 1) = *(source + 1); - *(destination + 2) = *(source + 0); - *(destination + 3) = *(source + 3); - - source += 4; - destination += 4; - } - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs index 694a26f3dd..3df688972f 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs @@ -114,7 +114,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk private BufferPointer GetPixelAccessorRow(int x, int y) { return new BufferPointer( - this.pixelAccessor.PixelBuffer, + this.pixelAccessor.PixelArray, (void*)this.pixelAccessor.DataPointer, (y * this.pixelAccessor.Width) + x ); diff --git a/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs b/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs index f3cd20f45c..cd9cd04b72 100644 --- a/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs +++ b/tests/ImageSharp.Tests/Image/PixelAccessorTests.cs @@ -130,16 +130,7 @@ namespace ImageSharp.Tests CopyFromZYX(image); } } - - [Fact] - public void CopyFromZYXOptimized() - { - using (Image image = new Image(1, 1)) - { - CopyFromZYX(image); - } - } - + [Fact] public void CopyFromZYXW() { @@ -148,16 +139,7 @@ namespace ImageSharp.Tests CopyFromZYXW(image); } } - - [Fact] - public void CopyFromZYXWOptimized() - { - using (Image image = new Image(1, 1)) - { - CopyFromZYXW(image); - } - } - + [Fact] public void CopyToZYX() { @@ -166,16 +148,7 @@ namespace ImageSharp.Tests CopyToZYX(image); } } - - [Fact] - public void CopyToZYXOptimized() - { - using (Image image = new Image(1, 1)) - { - CopyToZYX(image); - } - } - + [Fact] public void CopyToZYXW() { @@ -184,16 +157,7 @@ namespace ImageSharp.Tests CopyToZYXW(image); } } - - [Fact] - public void CopyToZYXWOptimized() - { - using (Image image = new Image(1, 1)) - { - CopyToZYXW(image); - } - } - + private static void CopyFromZYX(Image image) where TColor : struct, IPixel { From 79537eb16ec42795429bc8bb8ad6a3a7cfcb62e5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 03:26:27 +0100 Subject: [PATCH 52/85] benchmarks --- .../Common/Memory/BufferPointer{T}.cs | 5 + src/ImageSharp/project.json | 1 + .../Color/Bulk/PackFromXyzw.cs | 63 +++++++++ .../Color/Bulk/PixelAccessorVirtualCopy.cs | 129 ------------------ .../ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs | 61 +++++++++ .../Color/Bulk/ToXyzw.cs | 70 ++++++++++ .../ImageSharp.Benchmarks/Image/EncodePng.cs | 23 +++- .../ImageSharp.Sandbox46.csproj | 7 +- .../Colors/BulkPixelOperationsTests.cs | 4 +- 9 files changed, 226 insertions(+), 137 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs delete mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs index fe79e064e8..cfdd8e6ded 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -63,6 +63,11 @@ namespace ImageSharp /// public int Offset { get; private set; } + /// + /// Gets the offset inside in bytes. + /// + public int ByteOffset => this.Offset * Unsafe.SizeOf(); + /// /// Gets the pointer to the offseted array position /// diff --git a/src/ImageSharp/project.json b/src/ImageSharp/project.json index 639773377e..6519a3f6b8 100644 --- a/src/ImageSharp/project.json +++ b/src/ImageSharp/project.json @@ -98,6 +98,7 @@ }, "net461": { "dependencies": { + "System.Numerics.Vectors": "4.1.1", "System.Threading.Tasks.Parallel": "4.0.0" }, "frameworkAssemblies": { diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs new file mode 100644 index 0000000000..1c541d28b3 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs @@ -0,0 +1,63 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.Color.Bulk +{ + using BenchmarkDotNet.Attributes; + + using Color = ImageSharp.Color; + + public abstract class PackFromXyzw + where TColor : struct, IPixel + { + private PinnedBuffer destination; + + private PinnedBuffer source; + + [Params(16, 128, 1024)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.destination = new PinnedBuffer(this.Count); + this.source = new PinnedBuffer(this.Count * 4); + } + + [Cleanup] + public void Cleanup() + { + this.destination.Dispose(); + this.source.Dispose(); + } + + [Benchmark(Baseline = true)] + public void PerElement() + { + byte[] s = this.source.Array; + TColor[] d = this.destination.Array; + + for (int i = 0; i < this.Count; i++) + { + int i4 = i * 4; + TColor c = default(TColor); + c.PackFromBytes(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3]); + d[i] = c; + } + } + + [Benchmark] + public void CommonBulk() + { + new BulkPixelOperations().PackFromXyzwBytes(this.source, this.destination, this.Count); + } + + [Benchmark] + public void OptimizedBulk() + { + BulkPixelOperations.Instance.PackFromXyzwBytes(this.source, this.destination, this.Count); + } + } + + public class PackFromXyzw_Color : PackFromXyzw + { + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs deleted file mode 100644 index 3df688972f..0000000000 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/PixelAccessorVirtualCopy.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace ImageSharp.Benchmarks.Color.Bulk -{ - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - - using BenchmarkDotNet.Attributes; - - using Color = ImageSharp.Color; - - /// - /// Benchmark to measure the effect of using virtual bulk-copy calls inside PixelAccessor methods - /// - public unsafe class PixelAccessorVirtualCopy - { - abstract class CopyExecutor - { - internal abstract void VirtualCopy(BufferPointer destination, BufferPointer source, int count); - } - - class UnsafeCopyExecutor : CopyExecutor - { - [MethodImpl(MethodImplOptions.NoInlining)] - internal override unsafe void VirtualCopy(BufferPointer destination, BufferPointer source, int count) - { - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)count*4); - } - } - - private PixelAccessor pixelAccessor; - - private PixelArea area; - - private CopyExecutor executor; - - [Params(64, 256, 512)] - public int Width { get; set; } - - public int Height { get; set; } = 256; - - - [Setup] - public void Setup() - { - this.pixelAccessor = new PixelAccessor(this.Width, this.Height); - this.area = new PixelArea(this.Width / 2, this.Height, ComponentOrder.Xyzw); - this.executor = new UnsafeCopyExecutor(); - } - - [Cleanup] - public void Cleanup() - { - this.pixelAccessor.Dispose(); - this.area.Dispose(); - } - - [Benchmark(Baseline = true)] - public void CopyRawUnsafeInlined() - { - uint byteCount = (uint)this.area.Width * 4; - - int targetX = this.Width / 4; - int targetY = 0; - - for (int y = 0; y < this.Height; y++) - { - byte* source = this.area.PixelBase + (y * this.area.RowStride); - byte* destination = this.GetRowPointer(targetX, targetY + y); - - Unsafe.CopyBlock(destination, source, byteCount); - } - } - - [Benchmark] - public void CopyBufferPointerUnsafeInlined() - { - uint byteCount = (uint)this.area.Width * 4; - - int targetX = this.Width / 4; - int targetY = 0; - - for (int y = 0; y < this.Height; y++) - { - BufferPointer source = this.GetAreaRow(y); - BufferPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); - } - } - - [Benchmark] - public void CopyBufferPointerUnsafeVirtual() - { - int targetX = this.Width / 4; - int targetY = 0; - - for (int y = 0; y < this.Height; y++) - { - BufferPointer source = this.GetAreaRow(y); - BufferPointer destination = this.GetPixelAccessorRow(targetX, targetY + y); - this.executor.VirtualCopy(destination, source, this.area.Width); - } - } - - private byte* GetRowPointer(int x, int y) - { - return (byte*)this.pixelAccessor.DataPointer + (((y * this.pixelAccessor.Width) + x) * Unsafe.SizeOf()); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private BufferPointer GetPixelAccessorRow(int x, int y) - { - return new BufferPointer( - this.pixelAccessor.PixelArray, - (void*)this.pixelAccessor.DataPointer, - (y * this.pixelAccessor.Width) + x - ); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private BufferPointer GetAreaRow(int y) - { - return new BufferPointer(this.area.Bytes, this.area.PixelBase, y * this.area.RowStride); - } - } -} diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs new file mode 100644 index 0000000000..bc59dba4eb --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs @@ -0,0 +1,61 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.Color.Bulk +{ + using BenchmarkDotNet.Attributes; + + using Color = ImageSharp.Color; + + public abstract class ToXyz + where TColor : struct, IPixel + { + private PinnedBuffer source; + + private PinnedBuffer destination; + + [Params(16, 128, 1024)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.source = new PinnedBuffer(this.Count); + this.destination = new PinnedBuffer(this.Count * 3); + } + + [Cleanup] + public void Cleanup() + { + this.source.Dispose(); + this.destination.Dispose(); + } + + [Benchmark(Baseline = true)] + public void PerElement() + { + TColor[] s = this.source.Array; + byte[] d = this.destination.Array; + + for (int i = 0; i < this.Count; i++) + { + TColor c = s[i]; + c.ToXyzBytes(d, i * 4); + } + } + + [Benchmark] + public void CommonBulk() + { + new BulkPixelOperations().ToXyzBytes(this.source, this.destination, this.Count); + } + + [Benchmark] + public void OptimizedBulk() + { + BulkPixelOperations.Instance.ToXyzBytes(this.source, this.destination, this.Count); + } + } + + public class ToXyz_Color : ToXyz + { + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs new file mode 100644 index 0000000000..a4ec6f6dc3 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +// ReSharper disable InconsistentNaming + +namespace ImageSharp.Benchmarks.Color.Bulk +{ + using BenchmarkDotNet.Attributes; + + using Color = ImageSharp.Color; + + public abstract class ToXyzw + where TColor : struct, IPixel + { + private PinnedBuffer source; + + private PinnedBuffer destination; + + [Params(16, 128, 1024)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.source = new PinnedBuffer(this.Count); + this.destination = new PinnedBuffer(this.Count * 4); + } + + [Cleanup] + public void Cleanup() + { + this.source.Dispose(); + this.destination.Dispose(); + } + + [Benchmark(Baseline = true)] + public void PerElement() + { + TColor[] s = this.source.Array; + byte[] d = this.destination.Array; + + for (int i = 0; i < this.Count; i++) + { + TColor c = s[i]; + c.ToXyzwBytes(d, i * 4); + } + } + + [Benchmark] + public void CommonBulk() + { + new BulkPixelOperations().ToXyzwBytes(this.source, this.destination, this.Count); + } + + [Benchmark] + public void OptimizedBulk() + { + BulkPixelOperations.Instance.ToXyzwBytes(this.source, this.destination, this.Count); + } + } + + public class ToXyzw_Color : ToXyzw + { + } + + public class ToXyzw_Argb : ToXyzw + { + } +} diff --git a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs index dd1882c80d..a182ccd882 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs @@ -10,6 +10,10 @@ namespace ImageSharp.Benchmarks.Image using System.IO; using BenchmarkDotNet.Attributes; + + using ImageSharp.Formats; + using ImageSharp.Quantizers; + using CoreImage = ImageSharp.Image; public class EncodePng : BenchmarkBase @@ -19,12 +23,21 @@ namespace ImageSharp.Benchmarks.Image private Image bmpDrawing; private CoreImage bmpCore; + [Params(false, true)] + public bool LargeImage { get; set; } + + [Params(false, true)] + public bool UseOctreeQuantizer { get; set; } + [Setup] public void ReadImages() { if (this.bmpStream == null) { - this.bmpStream = File.OpenRead("../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp"); + string path = this.LargeImage + ? "../ImageSharp.Tests/TestImages/Formats/Jpg/baseline/jpeg420exif.jpg" + : "../ImageSharp.Tests/TestImages/Formats/Bmp/Car.bmp"; + this.bmpStream = File.OpenRead(path); this.bmpCore = new CoreImage(this.bmpStream); this.bmpStream.Position = 0; this.bmpDrawing = Image.FromStream(this.bmpStream); @@ -53,7 +66,13 @@ namespace ImageSharp.Benchmarks.Image { using (MemoryStream memoryStream = new MemoryStream()) { - this.bmpCore.SaveAsPng(memoryStream); + Quantizer quantizer = this.UseOctreeQuantizer + ? (Quantizer) + new OctreeQuantizer() + : new PaletteQuantizer(); + + PngEncoderOptions options = new PngEncoderOptions() { Quantizer = quantizer }; + this.bmpCore.SaveAsPng(memoryStream, options); } } } diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 4d3548c818..02318d0b43 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -206,9 +206,6 @@ - - Benchmarks\PixelAccessorVirtualCopy.cs - Tests\Colors\BulkPixelOperationsTests.cs @@ -346,7 +343,9 @@ - + + + diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index fa1b536f3b..88bc4a9be6 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -10,7 +10,7 @@ public class Color : BulkPixelOperationsTests { // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; [Fact] public void IsSpecialImplementation() @@ -35,7 +35,7 @@ public class Argb : BulkPixelOperationsTests { // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: - public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } [Theory] From 5f90483019fb40279be17d8182f8a83e3bd9de9c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 04:38:30 +0100 Subject: [PATCH 53/85] PixelDataPool is no longer static having PixelDataPool.Clean + PixelDataPool.Dirty instead --- src/ImageSharp/Colors/Color.BulkOperations.cs | 4 +- .../Common/Memory/PinnedBuffer{T}.cs | 29 ++++++--- .../Common/Memory/PixelDataPool{T}.cs | 50 ++++++++++++--- src/ImageSharp/Image/ImageBase{TColor}.cs | 4 +- .../Color/Bulk/ToVector4.cs | 61 +++++++++++++++++++ .../ImageSharp.Benchmarks/Image/EncodePng.cs | 4 +- tests/ImageSharp.Sandbox46/Program.cs | 21 +++---- .../Colors/BulkPixelOperationsTests.cs | 19 +++++- .../Common/PixelDataPoolTests.cs | 40 +++++++----- 9 files changed, 179 insertions(+), 53 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 3a1d667528..aadca236af 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -55,7 +55,9 @@ namespace ImageSharp uint* src = (uint*)sourceColors.PointerAtOffset; uint* srcEnd = src + count; - using (PinnedBuffer tempBuf = new PinnedBuffer(unpackedRawCount + Vector.Count)) + using (PinnedBuffer tempBuf = new PinnedBuffer( + unpackedRawCount + Vector.Count, + PixelDataPool.Dirty)) { uint* tPtr = (uint*)tempBuf.Pointer; uint[] temp = tempBuf.Array; diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index e902388882..8c81a3206d 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -24,22 +24,32 @@ namespace ImageSharp private GCHandle handle; /// - /// A value indicating whether this instance should return the array to the pool. + /// The if the is pooled. /// - private bool isPoolingOwner; + private PixelDataPool pool; /// /// Initializes a new instance of the class. /// /// The desired count of elements. (Minimum size for ) - public PinnedBuffer(int count) + /// The to be used to rent the data. + public PinnedBuffer(int count, PixelDataPool pool) { this.Count = count; - this.Array = PixelDataPool.Rent(count); - this.isPoolingOwner = true; + this.pool = pool; + this.Array = this.pool.Rent(count); this.Pin(); } + /// + /// Initializes a new instance of the class. + /// + /// The desired count of elements. (Minimum size for ) + public PinnedBuffer(int count) + : this(count, PixelDataPool.Clean) + { + } + /// /// Initializes a new instance of the class. /// @@ -48,6 +58,7 @@ namespace ImageSharp { this.Count = array.Length; this.Array = array; + this.pool = null; this.Pin(); } @@ -65,6 +76,7 @@ namespace ImageSharp this.Count = count; this.Array = array; + this.pool = null; this.Pin(); } @@ -140,11 +152,8 @@ namespace ImageSharp this.IsDisposedOrLostArrayOwnership = true; this.UnPin(); - if (this.isPoolingOwner) - { - PixelDataPool.Return(this.Array); - } - + this.pool?.Return(this.Array); + this.pool = null; this.Array = null; this.Count = 0; diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs index a97d17fdbb..a01a941bcd 100644 --- a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs +++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs @@ -9,39 +9,69 @@ namespace ImageSharp using System.Buffers; /// - /// Provides a resource pool that enables reusing instances of value type arrays . - /// will always return arrays initialized with 'default(T)' + /// Provides a resource pool that enables reusing instances of value type arrays for image data . /// /// The value type. - public static class PixelDataPool + public class PixelDataPool where T : struct { /// - /// The used to pool data. + /// The which will be always cleared. /// - private static readonly ArrayPool ArrayPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); + private static readonly ArrayPool CleanPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); + + /// + /// The which is not kept clean. + /// + private static readonly ArrayPool DirtyPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); + + /// + /// The backing + /// + private ArrayPool arrayPool; + + /// + /// A value indicating whether clearArray is requested on . + /// + private bool clearArray; + + private PixelDataPool(ArrayPool arrayPool, bool clearArray) + { + this.clearArray = clearArray; + this.arrayPool = arrayPool; + } + + /// + /// Gets the which will always return arrays initialized to default(T) + /// + public static PixelDataPool Clean { get; } = new PixelDataPool(CleanPool, true); + + /// + /// Gets the which does not keep the arrays clean on Rent/Return. + /// + public static PixelDataPool Dirty { get; } = new PixelDataPool(DirtyPool, false); /// /// Rents the pixel array from the pool. /// /// The minimum length of the array to return. /// The - public static T[] Rent(int minimumLength) + public T[] Rent(int minimumLength) { - return ArrayPool.Rent(minimumLength); + return CleanPool.Rent(minimumLength); } /// /// Returns the rented pixel array back to the pool. /// /// The array to return to the buffer pool. - public static void Return(T[] array) + public void Return(T[] array) { - ArrayPool.Return(array, true); + CleanPool.Return(array, this.clearArray); } /// - /// Heuristically calculates a reasonable maxArrayLength value for the backing . + /// Heuristically calculates a reasonable maxArrayLength value for the backing . /// /// The maxArrayLength value internal static int CalculateMaxArrayLength() diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 830318b32b..7d7fc843f0 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -221,7 +221,7 @@ namespace ImageSharp /// private void RentPixels() { - this.pixelBuffer = PixelDataPool.Rent(this.Width * this.Height); + this.pixelBuffer = PixelDataPool.Clean.Rent(this.Width * this.Height); } /// @@ -229,7 +229,7 @@ namespace ImageSharp /// private void ReturnPixels() { - PixelDataPool.Return(this.pixelBuffer); + PixelDataPool.Clean.Return(this.pixelBuffer); this.pixelBuffer = null; } } diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs new file mode 100644 index 0000000000..1300913868 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -0,0 +1,61 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.Color.Bulk +{ + using System.Numerics; + + using BenchmarkDotNet.Attributes; + + public abstract class ToVector4 + where TColor : struct, IPixel + { + private PinnedBuffer source; + + private PinnedBuffer destination; + + [Params(16, 128, 1024)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.source = new PinnedBuffer(this.Count); + this.destination = new PinnedBuffer(this.Count); + } + + [Cleanup] + public void Cleanup() + { + this.source.Dispose(); + this.destination.Dispose(); + } + + [Benchmark(Baseline = true)] + public void PerElement() + { + TColor[] s = this.source.Array; + Vector4[] d = this.destination.Array; + + for (int i = 0; i < this.Count; i++) + { + TColor c = s[i]; + d[i] = c.ToVector4(); + } + } + + [Benchmark] + public void CommonBulk() + { + new BulkPixelOperations().ToVector4(this.source, this.destination, this.Count); + } + + [Benchmark] + public void OptimizedBulk() + { + BulkPixelOperations.Instance.ToVector4(this.source, this.destination, this.Count); + } + } + + public class ToVector4_Color : ToVector4 + { + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs index a182ccd882..0bb0e922c5 100644 --- a/tests/ImageSharp.Benchmarks/Image/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Image/EncodePng.cs @@ -23,10 +23,10 @@ namespace ImageSharp.Benchmarks.Image private Image bmpDrawing; private CoreImage bmpCore; - [Params(false, true)] + [Params(false)] public bool LargeImage { get; set; } - [Params(false, true)] + [Params(false)] public bool UseOctreeQuantizer { get; set; } [Setup] diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index 4d6d159255..c361fd6a1f 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -7,9 +7,9 @@ namespace ImageSharp.Sandbox46 { using System; using System.Runtime.DesignerServices; - - using ImageSharp.Benchmarks.Color.Bulk; + using ImageSharp.Tests; + using ImageSharp.Tests.Colors; using Xunit.Abstractions; @@ -38,21 +38,18 @@ namespace ImageSharp.Sandbox46 public static void Main(string[] args) { // RunDecodeJpegProfilingTests(); - TestPixelAccessorCopyFromXyzw(); + + RunToVector4ProfilingTest(); + Console.ReadLine(); } - private static void TestPixelAccessorCopyFromXyzw() + private static void RunToVector4ProfilingTest() { - PixelAccessorVirtualCopy benchmark = new PixelAccessorVirtualCopy(); - benchmark.Width = 64; - benchmark.Setup(); - - benchmark.CopyRawUnsafeInlined(); - - benchmark.Cleanup(); + BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(); + tests.Benchmark_ToVector4(); } - + private static void RunDecodeJpegProfilingTests() { Console.WriteLine("RunDecodeJpegProfilingTests..."); diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 88bc4a9be6..786c77246c 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -1,4 +1,5 @@ -namespace ImageSharp.Tests.Colors +// ReSharper disable InconsistentNaming +namespace ImageSharp.Tests.Colors { using System; using System.Numerics; @@ -30,6 +31,22 @@ (s, d) => ImageSharp.Color.BulkOperations.ToVector4SimdAligned(s, d, 64) ); } + + [Fact] + public void Benchmark_ToVector4() + { + int times = 150000; + int count = 1024; + + using (PinnedBuffer source = new PinnedBuffer(count)) + using (PinnedBuffer dest = new PinnedBuffer(count)) + { + for (int i = 0; i < times; i++) + { + BulkPixelOperations.Instance.ToVector4(source, dest, count); + } + } + } } public class Argb : BulkPixelOperationsTests diff --git a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs index 001785d60c..db560ba6bb 100644 --- a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs +++ b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs @@ -3,6 +3,7 @@ // Licensed under the Apache License, Version 2.0. // +// ReSharper disable InconsistentNaming namespace ImageSharp.Tests { using System.Linq; @@ -14,50 +15,59 @@ namespace ImageSharp.Tests /// public class PixelDataPoolTests { - [Fact] - public void PixelDataPoolRentsMinimumSize() + private static PixelDataPool GetPool(bool clean) { - Color[] pixels = PixelDataPool.Rent(1024); + return clean ? PixelDataPool.Clean : PixelDataPool.Dirty; + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void PixelDataPoolRentsMinimumSize(bool clean) + { + Color[] pixels = GetPool(clean).Rent(1024); Assert.True(pixels.Length >= 1024); } [Fact] - public void PixelDataPoolRentsEmptyArray() + public void PixelDataPool_Clean_RentsCleanArray() { for (int i = 16; i < 1024; i += 16) { - Color[] pixels = PixelDataPool.Rent(i); + Color[] pixels = PixelDataPool.Clean.Rent(i); Assert.True(pixels.All(p => p == default(Color))); - PixelDataPool.Return(pixels); + PixelDataPool.Clean.Return(pixels); } for (int i = 16; i < 1024; i += 16) { - Color[] pixels = PixelDataPool.Rent(i); + Color[] pixels = PixelDataPool.Clean.Rent(i); Assert.True(pixels.All(p => p == default(Color))); - PixelDataPool.Return(pixels); + PixelDataPool.Clean.Return(pixels); } } - [Fact] - public void PixelDataPoolDoesNotThrowWhenReturningNonPooled() + [Theory] + [InlineData(false)] + [InlineData(true)] + public void PixelDataPoolDoesNotThrowWhenReturningNonPooled(bool clean) { Color[] pixels = new Color[1024]; - PixelDataPool.Return(pixels); + GetPool(clean).Return(pixels); Assert.True(pixels.Length >= 1024); } [Fact] - public void PixelDataPoolCleansRentedArray() + public void PixelDataPool_Clean_CleansRentedArray() { - Color[] pixels = PixelDataPool.Rent(256); + Color[] pixels = PixelDataPool.Clean.Rent(256); for (int i = 0; i < pixels.Length; i++) { @@ -66,7 +76,7 @@ namespace ImageSharp.Tests Assert.True(pixels.All(p => p == Color.Azure)); - PixelDataPool.Return(pixels); + PixelDataPool.Clean.Return(pixels); Assert.True(pixels.All(p => p == default(Color))); } @@ -85,7 +95,7 @@ namespace ImageSharp.Tests [Fact] public void RentNonIPixelData() { - byte[] data = PixelDataPool.Rent(16384); + byte[] data = PixelDataPool.Clean.Rent(16384); Assert.True(data.Length >= 16384); } From e04920416016a710fee81bf9fafe34423f4ceeaa Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 8 Mar 2017 22:07:23 +1100 Subject: [PATCH 54/85] Fix #127 Stop processing once we hit the end marker. --- src/ImageSharp.Formats.Png/PngDecoderCore.cs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp.Formats.Png/PngDecoderCore.cs index a7765342e9..fd03ed39b8 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderCore.cs @@ -109,6 +109,11 @@ namespace ImageSharp.Formats /// private byte[] paletteAlpha; + /// + /// A value indicating whether the end chunk has been reached. + /// + private bool isEndChunkReached; + /// /// Initializes static members of the class. /// @@ -158,18 +163,11 @@ namespace ImageSharp.Formats this.currentStream = stream; this.currentStream.Skip(8); - bool isEndChunkReached = false; - using (MemoryStream dataStream = new MemoryStream()) { PngChunk currentChunk; - while ((currentChunk = this.ReadChunk()) != null) + while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null) { - if (isEndChunkReached) - { - throw new ImageFormatException("Image does not end with end chunk."); - } - try { switch (currentChunk.Type) @@ -199,7 +197,7 @@ namespace ImageSharp.Formats this.ReadTextChunk(currentImage, currentChunk.Data, currentChunk.Length); break; case PngChunkTypes.End: - isEndChunkReached = true; + this.isEndChunkReached = true; break; } } From fdf4911eb46382c3cb2ececd4c2fcdeaf401f34f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 12:24:22 +0100 Subject: [PATCH 55/85] if (count < 256) { no SIMD } --- src/ImageSharp/Colors/Color.BulkOperations.cs | 7 ++++ .../Color/Bulk/ToVector4.cs | 2 +- .../Colors/BulkPixelOperationsTests.cs | 33 +++++++++++++++---- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index aadca236af..cdbfdfcd70 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -88,6 +88,13 @@ namespace ImageSharp /// internal override void ToVector4(BufferPointer sourceColors, BufferPointer destVectors, int count) { + if (count < 256) + { + // Doesn't worth to bother with SIMD: + base.ToVector4(sourceColors, destVectors, count); + return; + } + int remainder = count % Vector.Count; int alignedCount = count - remainder; diff --git a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs index 1300913868..b48eaa35af 100644 --- a/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs @@ -12,7 +12,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk private PinnedBuffer destination; - [Params(16, 128, 1024)] + [Params(64, 300, 1024)] public int Count { get; set; } [Setup] diff --git a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs index 786c77246c..6621292ec2 100644 --- a/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs @@ -1,15 +1,22 @@ // ReSharper disable InconsistentNaming +// ReSharper disable AccessToDisposedClosure namespace ImageSharp.Tests.Colors { using System; using System.Numerics; using Xunit; + using Xunit.Abstractions; public class BulkPixelOperationsTests { public class Color : BulkPixelOperationsTests { + public Color(ITestOutputHelper output) + : base(output) + { + } + // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; @@ -32,19 +39,21 @@ namespace ImageSharp.Tests.Colors ); } - [Fact] + // [Fact] // Profiling benchmark - enable manually! public void Benchmark_ToVector4() { - int times = 150000; + int times = 200000; int count = 1024; using (PinnedBuffer source = new PinnedBuffer(count)) using (PinnedBuffer dest = new PinnedBuffer(count)) { - for (int i = 0; i < times; i++) - { - BulkPixelOperations.Instance.ToVector4(source, dest, count); - } + this.Measure( + times, + () => + { + BulkPixelOperations.Instance.ToVector4(source, dest, count); + }); } } } @@ -52,6 +61,11 @@ namespace ImageSharp.Tests.Colors public class Argb : BulkPixelOperationsTests { // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: + public Argb(ITestOutputHelper output) + : base(output) + { + } + public static new TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; } @@ -64,9 +78,14 @@ namespace ImageSharp.Tests.Colors } } - public abstract class BulkPixelOperationsTests + public abstract class BulkPixelOperationsTests : MeasureFixture where TColor : struct, IPixel { + protected BulkPixelOperationsTests(ITestOutputHelper output) + : base(output) + { + } + public static TheoryData ArraySizesData => new TheoryData { 7, 16, 1111 }; private static BulkPixelOperations Operations => BulkPixelOperations.Instance; From c851143e0874226a1a56e4c59517328646c33d99 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 14:11:23 +0100 Subject: [PATCH 56/85] better BufferPointer.Copy() --- src/ImageSharp/Colors/Color.BulkOperations.cs | 1 + src/ImageSharp/Common/Memory/BufferPointer.cs | 106 ++++++------------ .../Common/BufferPointerTests.cs | 102 ++++++++++++++++- 3 files changed, 133 insertions(+), 76 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index cdbfdfcd70..617114dff9 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -66,6 +66,7 @@ namespace ImageSharp for (; src < srcEnd; src++, dst++) { + // TODO: We can benefit a lot of future Vector API-s here (https://github.com/dotnet/corefx/issues/15957) dst->Load(*src); } diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs index e600f41882..b470b4db59 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -5,6 +5,7 @@ namespace ImageSharp { + using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -17,7 +18,7 @@ namespace ImageSharp /// /// It's worth to use Marshal.Copy() over this size. /// - private const uint ByteCountThreshold = 1024u; + private const int ByteCountThreshold = 1024; /// /// Copy 'count' number of elements of the same type from 'source' to 'dest' @@ -27,20 +28,10 @@ namespace ImageSharp /// The destination . /// The number of elements to copy [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Copy(BufferPointer source, BufferPointer destination, int count) + public static void Copy(BufferPointer source, BufferPointer destination, int count) where T : struct { - uint byteCount = USizeOf(count); - - if (byteCount > ByteCountThreshold) - { - if (TryMarshalCopy(source, destination, count)) - { - return; - } - } - - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + CopyImpl(source, destination, count); } /// @@ -51,20 +42,10 @@ namespace ImageSharp /// The destination buffer. /// The number of elements to copy from 'source' [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static unsafe void Copy(BufferPointer source, BufferPointer destination, int countInSource) + public static void Copy(BufferPointer source, BufferPointer destination, int countInSource) where T : struct { - uint byteCount = USizeOf(countInSource); - - if (byteCount > ByteCountThreshold) - { - if (TryMarshalCopy(source, destination, countInSource)) - { - return; - } - } - - Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, byteCount); + CopyImpl(source, destination, countInSource); } /// @@ -112,60 +93,37 @@ namespace ImageSharp => (uint)SizeOf(count); [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool TryMarshalCopy(BufferPointer source, BufferPointer destination, int count) - where TSource : struct + private static unsafe void CopyImpl(BufferPointer source, BufferPointer destination, int count) + where T : struct where TDest : struct { - // Pattern Based On: - // https://github.com/dotnet/corefx/blob/master/src/System.Numerics.Vectors/src/System/Numerics/Vector.cs#L12 - // - // Note: The following patterns are used throughout the code here and are described here - // - // PATTERN: - // if (typeof(T) == typeof(Int32)) { ... } - // else if (typeof(T) == typeof(Single)) { ... } - // EXPLANATION: - // At runtime, each instantiation of BufferPointer will be type-specific, and each of these typeof blocks will be eliminated, - // as typeof(T) is a (JIT) compile-time constant for each instantiation. This design was chosen to eliminate any overhead from - // delegates and other patterns. - if (typeof(TSource) == typeof(long)) - { - long[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - return true; - } - else if (typeof(TSource) == typeof(int)) - { - int[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - return true; - } - else if (typeof(TSource) == typeof(uint)) - { - int[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - return true; - } - else if (typeof(TSource) == typeof(short)) - { - short[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - return true; - } - else if (typeof(TSource) == typeof(ushort)) - { - short[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - return true; - } - else if (typeof(TSource) == typeof(byte)) + int byteCount = SizeOf(count); + + if (byteCount > ByteCountThreshold) { - byte[] srcArray = Unsafe.As(source.Array); - Marshal.Copy(srcArray, source.Offset, destination.PointerAtOffset, count); - return true; + if (Unsafe.SizeOf() == sizeof(long)) + { + Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count); + return; + } + else if (Unsafe.SizeOf() == sizeof(int)) + { + Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count); + return; + } + else if (Unsafe.SizeOf() == sizeof(short)) + { + Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count); + return; + } + else if (Unsafe.SizeOf() == sizeof(byte)) + { + Marshal.Copy(Unsafe.As(source.Array), source.Offset, destination.PointerAtOffset, count); + return; + } } - return false; + Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)byteCount); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs index fc26bf0972..58fe2a1992 100644 --- a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs @@ -32,6 +32,37 @@ namespace ImageSharp.Tests.Common } } + /// + /// sizeof(AlignedFoo) == sizeof(long) + /// + public struct AlignedFoo + { + public int A; + + public int B; + + static AlignedFoo() + { + Assert.Equal(sizeof(AlignedFoo), sizeof(long)); + } + + public AlignedFoo(int a, int b) + { + this.A = a; + this.B = b; + } + + internal static AlignedFoo[] CreateArray(int size) + { + AlignedFoo[] result = new AlignedFoo[size]; + for (int i = 0; i < size; i++) + { + result[i] = new AlignedFoo(i + 1, i + 1); + } + return result; + } + } + [Fact] public void AsBytes() { @@ -108,7 +139,6 @@ namespace ImageSharp.Tests.Common Assert.NotEqual(default(T), data[idx]); } - private static byte[] CreateTestBytes(int count) { byte[] result = new byte[count]; @@ -156,6 +186,33 @@ namespace ImageSharp.Tests.Common Assert.NotEqual(source[count], dest[count]); } + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void GenericToOwnType_Aligned(int count) + { + AlignedFoo[] source = AlignedFoo.CreateArray(count + 2); + AlignedFoo[] dest = new AlignedFoo[count + 5]; + + fixed (AlignedFoo* pSource = source) + fixed (AlignedFoo* pDest = dest) + { + BufferPointer apSource = new BufferPointer(source, pSource, 1); + BufferPointer apDest = new BufferPointer(dest, pDest, 1); + + BufferPointer.Copy(apSource, apDest, count - 1); + } + + AssertNotDefault(source, 1); + AssertNotDefault(dest, 1); + + Assert.NotEqual(source[0], dest[0]); + Assert.Equal(source[1], dest[1]); + Assert.Equal(source[2], dest[2]); + Assert.Equal(source[count - 1], dest[count - 1]); + Assert.NotEqual(source[count], dest[count]); + } + [Theory] [InlineData(4)] [InlineData(1500)] @@ -209,7 +266,34 @@ namespace ImageSharp.Tests.Common Assert.True(ElementsAreEqual(source, dest, count - 1)); Assert.False(ElementsAreEqual(source, dest, count)); } - + + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void GenericToBytes_Aligned(int count) + { + int destCount = count * sizeof(Foo); + AlignedFoo[] source = AlignedFoo.CreateArray(count + 2); + byte[] dest = new byte[destCount + sizeof(AlignedFoo) * 2]; + + fixed (AlignedFoo* pSource = source) + fixed (byte* pDest = dest) + { + BufferPointer apSource = new BufferPointer(source, pSource, 1); + BufferPointer apDest = new BufferPointer(dest, pDest, sizeof(AlignedFoo)); + + BufferPointer.Copy(apSource, apDest, count - 1); + } + + AssertNotDefault(source, 1); + + Assert.False(ElementsAreEqual(source, dest, 0)); + Assert.True(ElementsAreEqual(source, dest, 1)); + Assert.True(ElementsAreEqual(source, dest, 2)); + Assert.True(ElementsAreEqual(source, dest, count - 1)); + Assert.False(ElementsAreEqual(source, dest, count)); + } + [Theory] [InlineData(4)] [InlineData(1500)] @@ -296,6 +380,20 @@ namespace ImageSharp.Tests.Common } } + internal static bool ElementsAreEqual(AlignedFoo[] array, byte[] rawArray, int index) + { + fixed (AlignedFoo* pArray = array) + fixed (byte* pRaw = rawArray) + { + AlignedFoo* pCasted = (AlignedFoo*)pRaw; + + AlignedFoo val1 = pArray[index]; + AlignedFoo val2 = pCasted[index]; + + return val1.Equals(val2); + } + } + internal static bool ElementsAreEqual(int[] array, byte[] rawArray, int index) { fixed (int* pArray = array) From f796bd60c7acc05477220f92f8d24af288960b15 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 18:42:04 +0100 Subject: [PATCH 57/85] inlining --- src/ImageSharp/Colors/Color.BulkOperations.cs | 2 +- src/ImageSharp/Common/Memory/BufferPointer.cs | 2 +- src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 617114dff9..154cd531dc 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -66,7 +66,7 @@ namespace ImageSharp for (; src < srcEnd; src++, dst++) { - // TODO: We can benefit a lot of future Vector API-s here (https://github.com/dotnet/corefx/issues/15957) + // TODO: This is the bottleneck now. We can improve it with future Vector API-s (https://github.com/dotnet/corefx/issues/15957) dst->Load(*src); } diff --git a/src/ImageSharp/Common/Memory/BufferPointer.cs b/src/ImageSharp/Common/Memory/BufferPointer.cs index b470b4db59..523889611f 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer.cs @@ -16,7 +16,7 @@ namespace ImageSharp internal static class BufferPointer { /// - /// It's worth to use Marshal.Copy() over this size. + /// It's worth to use Marshal.Copy() or Buffer.BlockCopy() over this size. /// private const int ByteCountThreshold = 1024; diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index 8c81a3206d..6e0d1fcc62 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -142,6 +142,7 @@ namespace ImageSharp /// /// Disposes the instance by unpinning the array, and returning the pooled buffer when necessary. /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { if (this.IsDisposedOrLostArrayOwnership) @@ -165,6 +166,7 @@ namespace ImageSharp /// If is rented, it's the callers responsibility to return it to it's pool. (Most likely ) /// /// The unpinned + [MethodImpl(MethodImplOptions.AggressiveInlining)] public T[] UnPinAndTakeArrayOwnership() { if (this.IsDisposedOrLostArrayOwnership) @@ -182,6 +184,7 @@ namespace ImageSharp /// /// Pins . /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Pin() { this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned); @@ -191,6 +194,7 @@ namespace ImageSharp /// /// Unpins . /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void UnPin() { if (this.Pointer == IntPtr.Zero || !this.handle.IsAllocated) From e3af41180dbf87fc0ba97ad3e2e57c59d7749ee5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 19:15:09 +0100 Subject: [PATCH 58/85] BufferPointer.Clear() --- .../Common/Memory/BufferPointer{T}.cs | 10 +++++ .../General/ClearBuffer.cs | 43 +++++++++++++++++++ .../Common/BufferPointerTests.cs | 20 ++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/ImageSharp.Benchmarks/General/ClearBuffer.cs diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs index cfdd8e6ded..4e7a400785 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -122,5 +122,15 @@ namespace ImageSharp result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf() * offset); return result; } + + /// + /// Clears `count` elements beginning from the pointed position. + /// + /// The number of elements to clear + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear(int count) + { + + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/General/ClearBuffer.cs b/tests/ImageSharp.Benchmarks/General/ClearBuffer.cs new file mode 100644 index 0000000000..9aa836de59 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/ClearBuffer.cs @@ -0,0 +1,43 @@ +// ReSharper disable InconsistentNaming +namespace ImageSharp.Benchmarks.General +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + using BenchmarkDotNet.Attributes; + + using Color = ImageSharp.Color; + + public unsafe class ClearBuffer + { + private PinnedBuffer buffer; + + [Params(32, 128, 512)] + public int Count { get; set; } + + [Setup] + public void Setup() + { + this.buffer = new PinnedBuffer(this.Count); + } + + [Cleanup] + public void Cleanup() + { + this.buffer.Dispose(); + } + + [Benchmark(Baseline = true)] + public void Array_Clear() + { + Array.Clear(this.buffer.Array, 0, this.Count); + } + + [Benchmark] + public void Unsafe_InitBlock() + { + Unsafe.InitBlock((void*)this.buffer.Pointer, default(byte), (uint)this.Count*sizeof(uint)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs index 58fe2a1992..39d76d9377 100644 --- a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs @@ -131,6 +131,25 @@ namespace ImageSharp.Tests.Common } } + + [Theory] + [InlineData(4)] + [InlineData(1500)] + public void Clear(int count) + { + Foo[] array = Foo.CreateArray(count + 42); + + int offset = 2; + fixed (Foo* p = array) + { + BufferPointer ap = new BufferPointer(array, p, offset); + + // Act: + ap.Clear(count); + } + } + + public class Copy { private static void AssertNotDefault(T[] data, int idx) @@ -319,7 +338,6 @@ namespace ImageSharp.Tests.Common Assert.False(ElementsAreEqual(source, dest, count)); } - [Theory] [InlineData(4)] [InlineData(1500)] From ac9e06b21c8210f863ffe8682061a7a33813fa40 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 21:03:47 +0100 Subject: [PATCH 59/85] PixelDataPool is static again, it no longer clears it's arrays. --- src/ImageSharp/Colors/Color.BulkOperations.cs | 9 ++-- .../Common/Memory/BufferPointer{T}.cs | 9 +++- .../Common/Memory/PinnedBuffer{T}.cs | 43 +++++++++++-------- .../Common/Memory/PixelDataPool{T}.cs | 43 +++---------------- src/ImageSharp/Image/ImageBase{TColor}.cs | 10 ++++- tests/ImageSharp.Sandbox46/Program.cs | 2 +- .../Common/BufferPointerTests.cs | 5 +++ .../Common/PinnedBufferTests.cs | 15 +++++++ .../Common/PixelDataPoolTests.cs | 35 ++++++--------- 9 files changed, 86 insertions(+), 85 deletions(-) diff --git a/src/ImageSharp/Colors/Color.BulkOperations.cs b/src/ImageSharp/Colors/Color.BulkOperations.cs index 154cd531dc..5c040e04c5 100644 --- a/src/ImageSharp/Colors/Color.BulkOperations.cs +++ b/src/ImageSharp/Colors/Color.BulkOperations.cs @@ -32,6 +32,10 @@ namespace ImageSharp /// /// http://stackoverflow.com/a/5362789 /// + /// TODO: We can replace this implementation in the future using new Vector API-s: + /// + /// https://github.com/dotnet/corefx/issues/15957 + /// /// internal static unsafe void ToVector4SimdAligned( BufferPointer sourceColors, @@ -56,8 +60,7 @@ namespace ImageSharp uint* srcEnd = src + count; using (PinnedBuffer tempBuf = new PinnedBuffer( - unpackedRawCount + Vector.Count, - PixelDataPool.Dirty)) + unpackedRawCount + Vector.Count)) { uint* tPtr = (uint*)tempBuf.Pointer; uint[] temp = tempBuf.Array; @@ -66,7 +69,7 @@ namespace ImageSharp for (; src < srcEnd; src++, dst++) { - // TODO: This is the bottleneck now. We can improve it with future Vector API-s (https://github.com/dotnet/corefx/issues/15957) + // This call is the bottleneck now: dst->Load(*src); } diff --git a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs index 4e7a400785..441f6b8ce0 100644 --- a/src/ImageSharp/Common/Memory/BufferPointer{T}.cs +++ b/src/ImageSharp/Common/Memory/BufferPointer{T}.cs @@ -130,7 +130,14 @@ namespace ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Clear(int count) { - + if (count < 256) + { + Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferPointer.USizeOf(count)); + } + else + { + System.Array.Clear(this.Array, this.Offset, count); + } } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index 6e0d1fcc62..2d3d44dda8 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -24,32 +24,23 @@ namespace ImageSharp private GCHandle handle; /// - /// The if the is pooled. + /// A value indicating wheter should be returned to + /// when disposing this instance. /// - private PixelDataPool pool; + private bool isPoolingOwner; /// /// Initializes a new instance of the class. /// /// The desired count of elements. (Minimum size for ) - /// The to be used to rent the data. - public PinnedBuffer(int count, PixelDataPool pool) + public PinnedBuffer(int count) { this.Count = count; - this.pool = pool; - this.Array = this.pool.Rent(count); + this.Array = PixelDataPool.Rent(count); + this.isPoolingOwner = true; this.Pin(); } - /// - /// Initializes a new instance of the class. - /// - /// The desired count of elements. (Minimum size for ) - public PinnedBuffer(int count) - : this(count, PixelDataPool.Clean) - { - } - /// /// Initializes a new instance of the class. /// @@ -58,7 +49,7 @@ namespace ImageSharp { this.Count = array.Length; this.Array = array; - this.pool = null; + this.isPoolingOwner = false; this.Pin(); } @@ -76,7 +67,7 @@ namespace ImageSharp this.Count = count; this.Array = array; - this.pool = null; + this.isPoolingOwner = false; this.Pin(); } @@ -153,8 +144,12 @@ namespace ImageSharp this.IsDisposedOrLostArrayOwnership = true; this.UnPin(); - this.pool?.Return(this.Array); - this.pool = null; + if (this.isPoolingOwner) + { + PixelDataPool.Return(this.Array); + } + + this.isPoolingOwner = false; this.Array = null; this.Count = 0; @@ -178,9 +173,19 @@ namespace ImageSharp this.UnPin(); T[] array = this.Array; this.Array = null; + this.isPoolingOwner = false; return array; } + /// + /// Clears the buffer, filling elements between 0 and -1 with default(T) + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + this.Slice().Clear(this.Count); + } + /// /// Pins . /// diff --git a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs index a01a941bcd..dcd031f6e2 100644 --- a/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs +++ b/src/ImageSharp/Common/Memory/PixelDataPool{T}.cs @@ -15,63 +15,32 @@ namespace ImageSharp public class PixelDataPool where T : struct { - /// - /// The which will be always cleared. - /// - private static readonly ArrayPool CleanPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); - /// /// The which is not kept clean. /// - private static readonly ArrayPool DirtyPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); - - /// - /// The backing - /// - private ArrayPool arrayPool; - - /// - /// A value indicating whether clearArray is requested on . - /// - private bool clearArray; - - private PixelDataPool(ArrayPool arrayPool, bool clearArray) - { - this.clearArray = clearArray; - this.arrayPool = arrayPool; - } - - /// - /// Gets the which will always return arrays initialized to default(T) - /// - public static PixelDataPool Clean { get; } = new PixelDataPool(CleanPool, true); - - /// - /// Gets the which does not keep the arrays clean on Rent/Return. - /// - public static PixelDataPool Dirty { get; } = new PixelDataPool(DirtyPool, false); + private static readonly ArrayPool ArrayPool = ArrayPool.Create(CalculateMaxArrayLength(), 50); /// /// Rents the pixel array from the pool. /// /// The minimum length of the array to return. /// The - public T[] Rent(int minimumLength) + public static T[] Rent(int minimumLength) { - return CleanPool.Rent(minimumLength); + return ArrayPool.Rent(minimumLength); } /// /// Returns the rented pixel array back to the pool. /// /// The array to return to the buffer pool. - public void Return(T[] array) + public static void Return(T[] array) { - CleanPool.Return(array, this.clearArray); + ArrayPool.Return(array); } /// - /// Heuristically calculates a reasonable maxArrayLength value for the backing . + /// Heuristically calculates a reasonable maxArrayLength value for the backing . /// /// The maxArrayLength value internal static int CalculateMaxArrayLength() diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 7d7fc843f0..7afc27a6d9 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -60,6 +60,7 @@ namespace ImageSharp { this.Configuration = configuration ?? Configuration.Default; this.InitPixels(width, height); + this.ClearPixels(); } /// @@ -221,7 +222,7 @@ namespace ImageSharp /// private void RentPixels() { - this.pixelBuffer = PixelDataPool.Clean.Rent(this.Width * this.Height); + this.pixelBuffer = PixelDataPool.Rent(this.Width * this.Height); } /// @@ -229,8 +230,13 @@ namespace ImageSharp /// private void ReturnPixels() { - PixelDataPool.Clean.Return(this.pixelBuffer); + PixelDataPool.Return(this.pixelBuffer); this.pixelBuffer = null; } + + private void ClearPixels() + { + Array.Clear(this.pixelBuffer, 0, this.Width * this.Height); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/Program.cs b/tests/ImageSharp.Sandbox46/Program.cs index c361fd6a1f..467663a539 100644 --- a/tests/ImageSharp.Sandbox46/Program.cs +++ b/tests/ImageSharp.Sandbox46/Program.cs @@ -46,7 +46,7 @@ namespace ImageSharp.Sandbox46 private static void RunToVector4ProfilingTest() { - BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(); + BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(new ConsoleOutput()); tests.Benchmark_ToVector4(); } diff --git a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs index 39d76d9377..c82b63f115 100644 --- a/tests/ImageSharp.Tests/Common/BufferPointerTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferPointerTests.cs @@ -146,6 +146,11 @@ namespace ImageSharp.Tests.Common // Act: ap.Clear(count); + + Assert.NotEqual(default(Foo), array[offset-1]); + Assert.Equal(default(Foo), array[offset]); + Assert.Equal(default(Foo), array[offset + count-1]); + Assert.NotEqual(default(Foo), array[offset + count]); } } diff --git a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs index 65077ae7f3..3688763b9a 100644 --- a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs +++ b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs @@ -47,6 +47,21 @@ } } + [Theory] + [InlineData(42)] + [InlineData(1111)] + public void Clear(int count) + { + Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } }; + using (PinnedBuffer buffer = new PinnedBuffer(a)) + { + buffer.Clear(); + + Assert.Equal(default(Foo), a[0]); + Assert.Equal(default(Foo), a[1]); + } + } + [Fact] public void Dispose() { diff --git a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs index db560ba6bb..ea747af7dc 100644 --- a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs +++ b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs @@ -15,17 +15,10 @@ namespace ImageSharp.Tests /// public class PixelDataPoolTests { - private static PixelDataPool GetPool(bool clean) - { - return clean ? PixelDataPool.Clean : PixelDataPool.Dirty; - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void PixelDataPoolRentsMinimumSize(bool clean) + [Fact] + public void PixelDataPoolRentsMinimumSize() { - Color[] pixels = GetPool(clean).Rent(1024); + Color[] pixels = PixelDataPool.Rent(1024); Assert.True(pixels.Length >= 1024); } @@ -35,31 +28,29 @@ namespace ImageSharp.Tests { for (int i = 16; i < 1024; i += 16) { - Color[] pixels = PixelDataPool.Clean.Rent(i); + Color[] pixels = PixelDataPool.Rent(i); Assert.True(pixels.All(p => p == default(Color))); - PixelDataPool.Clean.Return(pixels); + PixelDataPool.Return(pixels); } for (int i = 16; i < 1024; i += 16) { - Color[] pixels = PixelDataPool.Clean.Rent(i); + Color[] pixels = PixelDataPool.Rent(i); Assert.True(pixels.All(p => p == default(Color))); - PixelDataPool.Clean.Return(pixels); + PixelDataPool.Return(pixels); } } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void PixelDataPoolDoesNotThrowWhenReturningNonPooled(bool clean) + [Fact] + public void PixelDataPoolDoesNotThrowWhenReturningNonPooled() { Color[] pixels = new Color[1024]; - GetPool(clean).Return(pixels); + PixelDataPool.Return(pixels); Assert.True(pixels.Length >= 1024); } @@ -67,7 +58,7 @@ namespace ImageSharp.Tests [Fact] public void PixelDataPool_Clean_CleansRentedArray() { - Color[] pixels = PixelDataPool.Clean.Rent(256); + Color[] pixels = PixelDataPool.Rent(256); for (int i = 0; i < pixels.Length; i++) { @@ -76,7 +67,7 @@ namespace ImageSharp.Tests Assert.True(pixels.All(p => p == Color.Azure)); - PixelDataPool.Clean.Return(pixels); + PixelDataPool.Return(pixels); Assert.True(pixels.All(p => p == default(Color))); } @@ -95,7 +86,7 @@ namespace ImageSharp.Tests [Fact] public void RentNonIPixelData() { - byte[] data = PixelDataPool.Clean.Rent(16384); + byte[] data = PixelDataPool.Rent(16384); Assert.True(data.Length >= 16384); } From 3efdbc0300d2babd3ae89f27c2a9ec7fa7388ac2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 21:15:44 +0100 Subject: [PATCH 60/85] docs for ClearPixels() --- src/ImageSharp/Image/ImageBase{TColor}.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 7afc27a6d9..878ba09b39 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -234,6 +234,9 @@ namespace ImageSharp this.pixelBuffer = null; } + /// + /// Clears the pixel array. + /// private void ClearPixels() { Array.Clear(this.pixelBuffer, 0, this.Width * this.Height); From 704bc17207f82efe5fa4805a6a7f3a22be07036a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 Mar 2017 23:37:37 +0100 Subject: [PATCH 61/85] remove outdated tests --- .../Common/PixelDataPoolTests.cs | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs index ea747af7dc..403dffba9c 100644 --- a/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs +++ b/tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs @@ -23,28 +23,6 @@ namespace ImageSharp.Tests Assert.True(pixels.Length >= 1024); } - [Fact] - public void PixelDataPool_Clean_RentsCleanArray() - { - for (int i = 16; i < 1024; i += 16) - { - Color[] pixels = PixelDataPool.Rent(i); - - Assert.True(pixels.All(p => p == default(Color))); - - PixelDataPool.Return(pixels); - } - - for (int i = 16; i < 1024; i += 16) - { - Color[] pixels = PixelDataPool.Rent(i); - - Assert.True(pixels.All(p => p == default(Color))); - - PixelDataPool.Return(pixels); - } - } - [Fact] public void PixelDataPoolDoesNotThrowWhenReturningNonPooled() { @@ -55,23 +33,6 @@ namespace ImageSharp.Tests Assert.True(pixels.Length >= 1024); } - [Fact] - public void PixelDataPool_Clean_CleansRentedArray() - { - Color[] pixels = PixelDataPool.Rent(256); - - for (int i = 0; i < pixels.Length; i++) - { - pixels[i] = Color.Azure; - } - - Assert.True(pixels.All(p => p == Color.Azure)); - - PixelDataPool.Return(pixels); - - Assert.True(pixels.All(p => p == default(Color))); - } - [Theory] [InlineData(false)] [InlineData(true)] From 98dd13b935d980177cdf22cb98a065aec6057153 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 9 Mar 2017 21:37:41 +1100 Subject: [PATCH 62/85] Resize should respect source rectangle Fix #118 --- .../Transforms/CompandingResizeProcessor.cs | 12 ++++++----- .../Processors/Transforms/ResizeProcessor.cs | 12 ++++++----- .../Processors/Filters/ResizeTests.cs | 21 +++++++++++++++++++ 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs b/src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs index 53da214831..2190254f0d 100644 --- a/src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs +++ b/src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs @@ -56,6 +56,8 @@ namespace ImageSharp.Processing.Processors int width = this.Width; int height = this.Height; + int sourceX = sourceRectangle.X; + int sourceY = sourceRectangle.Y; int startY = this.ResizeRectangle.Y; int endY = this.ResizeRectangle.Bottom; int startX = this.ResizeRectangle.X; @@ -83,12 +85,12 @@ namespace ImageSharp.Processing.Processors y => { // Y coordinates of source points - int originY = (int)((y - startY) * heightFactor); + int originY = (int)(((y - startY) * heightFactor) + sourceY); for (int x = minX; x < maxX; x++) { // X coordinates of source points - targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY]; + targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY]; } }); } @@ -110,7 +112,7 @@ namespace ImageSharp.Processing.Processors { Parallel.For( 0, - sourceRectangle.Height, + sourceRectangle.Bottom, this.ParallelOptions, y => { @@ -125,7 +127,7 @@ namespace ImageSharp.Processing.Processors for (int i = 0; i < horizontalValues.Length; i++) { Weight xw = horizontalValues[i]; - destination += sourcePixels[xw.Index, y].ToVector4().Expand() * xw.Value; + destination += sourcePixels[xw.Index + sourceX, y].ToVector4().Expand() * xw.Value; } TColor d = default(TColor); @@ -152,7 +154,7 @@ namespace ImageSharp.Processing.Processors for (int i = 0; i < verticalValues.Length; i++) { Weight yw = verticalValues[i]; - destination += firstPassPixels[x, yw.Index].ToVector4().Expand() * yw.Value; + destination += firstPassPixels[x, yw.Index + sourceY].ToVector4().Expand() * yw.Value; } TColor d = default(TColor); diff --git a/src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs index f4ec39f785..9ec804aa4f 100644 --- a/src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs @@ -55,6 +55,8 @@ namespace ImageSharp.Processing.Processors int width = this.Width; int height = this.Height; + int sourceX = sourceRectangle.X; + int sourceY = sourceRectangle.Y; int startY = this.ResizeRectangle.Y; int endY = this.ResizeRectangle.Bottom; int startX = this.ResizeRectangle.X; @@ -82,12 +84,12 @@ namespace ImageSharp.Processing.Processors y => { // Y coordinates of source points - int originY = (int)((y - startY) * heightFactor); + int originY = (int)(((y - startY) * heightFactor) + sourceY); for (int x = minX; x < maxX; x++) { // X coordinates of source points - targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY]; + targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY]; } }); } @@ -109,7 +111,7 @@ namespace ImageSharp.Processing.Processors { Parallel.For( 0, - sourceRectangle.Height, + sourceRectangle.Bottom, this.ParallelOptions, y => { @@ -124,7 +126,7 @@ namespace ImageSharp.Processing.Processors for (int i = 0; i < horizontalValues.Length; i++) { Weight xw = horizontalValues[i]; - destination += sourcePixels[xw.Index, y].ToVector4() * xw.Value; + destination += sourcePixels[xw.Index + sourceX, y].ToVector4() * xw.Value; } TColor d = default(TColor); @@ -151,7 +153,7 @@ namespace ImageSharp.Processing.Processors for (int i = 0; i < verticalValues.Length; i++) { Weight yw = verticalValues[i]; - destination += firstPassPixels[x, yw.Index].ToVector4() * yw.Value; + destination += firstPassPixels[x, yw.Index + sourceY].ToVector4() * yw.Value; } TColor d = default(TColor); diff --git a/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs b/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs index 5acbe0f3eb..06ab245c90 100644 --- a/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processors/Filters/ResizeTests.cs @@ -50,6 +50,27 @@ namespace ImageSharp.Tests } } + [Theory] + [MemberData(nameof(ReSamplers))] + public void ImageShouldResizeFromSourceRectangle(string name, IResampler sampler) + { + name = $"{name}-SourceRect"; + + string path = this.CreateOutputDirectory("Resize"); + + foreach (TestFile file in Files) + { + string filename = file.GetFileName(name); + using (Image image = file.CreateImage()) + using (FileStream output = File.OpenWrite($"{path}/{filename}")) + { + var sourceRectangle = new Rectangle(image.Width / 8, image.Height / 8, image.Width / 4, image.Height / 4); + var destRectangle = new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2); + image.Resize(image.Width, image.Height, sampler, sourceRectangle, destRectangle, false).Save(output); + } + } + } + [Theory] [MemberData(nameof(ReSamplers))] public void ImageShouldResizeWidthAndKeepAspect(string name, IResampler sampler) From 509eaf12d5ea029f4a0bdd8e362c32c03e103df0 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 9 Mar 2017 19:05:38 +0000 Subject: [PATCH 63/85] consolidate packages --- ImageSharp.sln | 111 ------------------ build/Properties/launchSettings.json | 3 +- build/build.csproj | 14 +-- .../ImageSharp.Drawing.Paths.csproj | 84 ------------- .../Properties/AssemblyInfo.cs | 6 - .../ImageSharp.Drawing.Text.csproj | 84 ------------- .../Properties/AssemblyInfo.cs | 6 - .../ImageSharp.Drawing.csproj | 20 +--- .../Paths}/DrawBeziers.cs | 0 .../Paths}/DrawLines.cs | 0 .../Paths}/DrawPath.cs | 0 .../Paths}/DrawPolygon.cs | 0 .../Paths}/DrawRectangle.cs | 0 .../Paths}/FillPaths.cs | 0 .../Paths}/FillPolygon.cs | 0 .../Paths}/FillRectangle.cs | 0 .../Paths}/RectangleExtensions.cs | 0 .../Paths}/ShapePath.cs | 0 .../Paths}/ShapeRegion.cs | 0 .../Text}/DrawText.cs | 0 .../Text}/GlyphBuilder.cs | 0 .../Text}/TextGraphicsOptions.cs | 0 .../ImageSharp.Formats.Bmp.csproj | 61 ---------- .../Properties/AssemblyInfo.cs | 6 - .../ImageSharp.Formats.Gif.csproj | 61 ---------- .../Properties/AssemblyInfo.cs | 6 - .../ImageSharp.Formats.Jpeg.csproj | 61 ---------- .../Properties/AssemblyInfo.cs | 6 - .../ImageSharp.Formats.Png.csproj | 61 ---------- .../Properties/AssemblyInfo.cs | 6 - .../ImageSharp.Processing.csproj | 61 ---------- .../Properties/AssemblyInfo.cs | 6 - src/ImageSharp/Configuration.cs | 8 +- .../Drawing}/Brushes/Brushes.cs | 0 .../Drawing}/Brushes/Brushes{TColor}.cs | 0 .../Drawing}/Brushes/IBrush.cs | 0 .../Drawing}/Brushes/ImageBrush.cs | 0 .../Drawing}/Brushes/ImageBrush{TColor}.cs | 0 .../Drawing}/Brushes/PatternBrush.cs | 0 .../Drawing}/Brushes/PatternBrush{TColor}.cs | 0 .../Brushes/Processors/BrushApplicator.cs | 0 .../Drawing}/Brushes/RecolorBrush.cs | 0 .../Drawing}/Brushes/RecolorBrush{TColor}.cs | 0 .../Drawing}/Brushes/SolidBrush.cs | 0 .../Drawing}/Brushes/SolidBrush{TColor}.cs | 0 .../Drawing}/DrawImage.cs | 0 .../Drawing}/DrawPath.cs | 0 .../Drawing}/Drawable.cs | 0 .../Drawing}/FillRegion.cs | 0 .../Drawing}/GraphicsOptions.cs | 0 .../Drawing}/Pens/IPen.cs | 0 .../Drawing}/Pens/Pen.cs | 0 .../Drawing}/Pens/Pens.cs | 0 .../Drawing}/Pens/Pens{TColor}.cs | 0 .../Drawing}/Pens/Pen{TColor}.cs | 0 .../Pens/Processors/ColoredPointInfo.cs | 0 .../Drawing}/Pens/Processors/PenApplicator.cs | 0 .../Drawing}/PointInfo.cs | 0 .../Drawing}/Processors/DrawImageProcessor.cs | 0 .../Drawing}/Processors/DrawPathProcessor.cs | 0 .../Drawing}/Processors/FillProcessor.cs | 0 .../Processors/FillRegionProcessor.cs | 0 .../Drawing}/Region.cs | 0 .../Formats/Bmp}/BmpBitsPerPixel.cs | 0 .../Formats/Bmp}/BmpCompression.cs | 0 .../Formats/Bmp}/BmpDecoder.cs | 0 .../Formats/Bmp}/BmpDecoderCore.cs | 0 .../Formats/Bmp}/BmpEncoder.cs | 0 .../Formats/Bmp}/BmpEncoderCore.cs | 0 .../Formats/Bmp}/BmpEncoderOptions.cs | 0 .../Formats/Bmp}/BmpFileHeader.cs | 0 .../Formats/Bmp}/BmpFormat.cs | 0 .../Formats/Bmp}/BmpInfoHeader.cs | 0 .../Formats/Bmp}/IBmpEncoderOptions.cs | 0 .../Formats/Bmp}/ImageExtensions.cs | 0 .../Formats/Bmp}/README.md | 0 .../Formats/Gif}/DisposalMethod.cs | 0 .../Formats/Gif}/GifConstants.cs | 0 .../Formats/Gif}/GifDecoder.cs | 0 .../Formats/Gif}/GifDecoderCore.cs | 0 .../Formats/Gif}/GifDecoderOptions.cs | 0 .../Formats/Gif}/GifEncoder.cs | 0 .../Formats/Gif}/GifEncoderCore.cs | 0 .../Formats/Gif}/GifEncoderOptions.cs | 0 .../Formats/Gif}/GifFormat.cs | 0 .../Formats/Gif}/IGifDecoderOptions.cs | 0 .../Formats/Gif}/IGifEncoderOptions.cs | 0 .../Formats/Gif}/ImageExtensions.cs | 0 .../Formats/Gif}/LzwDecoder.cs | 0 .../Formats/Gif}/LzwEncoder.cs | 0 .../Formats/Gif}/PackedField.cs | 0 .../Formats/Gif}/README.md | 0 .../Sections/GifGraphicsControlExtension.cs | 0 .../Gif}/Sections/GifImageDescriptor.cs | 0 .../Sections/GifLogicalScreenDescriptor.cs | 0 .../Jpeg}/Components/Block8x8F.Generated.cs | 0 .../Jpeg}/Components/Block8x8F.Generated.tt | 0 .../Formats/Jpeg}/Components/Block8x8F.cs | 0 .../Formats/Jpeg}/Components/BlockQuad.cs | 0 .../Formats/Jpeg}/Components/DCT.cs | 0 .../Formats/Jpeg}/Components/Decoder/Bits.cs | 0 .../Formats/Jpeg}/Components/Decoder/Bytes.cs | 0 .../Jpeg}/Components/Decoder/Component.cs | 0 .../Jpeg}/Components/Decoder/ComponentScan.cs | 0 .../Jpeg}/Components/Decoder/DecodedBlock.cs | 0 .../Components/Decoder/DecodedBlockArray.cs | 0 .../Components/Decoder/DecoderErrorCode.cs | 0 .../Components/Decoder/DecoderThrowHelper.cs | 0 .../Jpeg}/Components/Decoder/EOFException.cs | 0 .../Jpeg}/Components/Decoder/HuffmanTree.cs | 0 .../Components/Decoder/InputProcessor.cs | 0 .../Components/Decoder/JpegBlockProcessor.cs | 0 .../Jpeg}/Components/Decoder/JpegPixelArea.cs | 0 .../JpegScanDecoder.ComputationData.cs | 0 .../Decoder/JpegScanDecoder.DataPointers.cs | 0 .../Components/Decoder/JpegScanDecoder.cs | 0 .../Components/Decoder/JpegScanDecoder.md | 0 .../Decoder/MissingFF00Exception.cs | 0 .../Jpeg}/Components/Decoder/YCbCrImage.cs | 0 .../Jpeg}/Components/Encoder/HuffIndex.cs | 0 .../Jpeg}/Components/Encoder/HuffmanLut.cs | 0 .../Jpeg}/Components/Encoder/HuffmanSpec.cs | 0 .../Jpeg}/Components/Encoder/QuantIndex.cs | 0 .../Formats/Jpeg}/IJpegEncoderOptions.cs | 0 .../Formats/Jpeg}/ImageExtensions.cs | 0 .../Formats/Jpeg}/JpegConstants.cs | 0 .../Formats/Jpeg}/JpegDecoder.cs | 0 .../Formats/Jpeg}/JpegDecoderCore.cs | 0 .../Formats/Jpeg}/JpegEncoder.cs | 0 .../Formats/Jpeg}/JpegEncoderCore.cs | 0 .../Formats/Jpeg}/JpegEncoderOptions.cs | 0 .../Formats/Jpeg}/JpegFormat.cs | 0 .../Formats/Jpeg}/JpegSubsample.cs | 0 .../Formats/Jpeg}/README.md | 0 .../Formats/Jpeg}/UnzigData.cs | 0 .../Formats/Jpeg}/Utils/JpegUtils.cs | 0 .../Formats/Jpeg}/Utils/MutableSpan.cs | 0 .../Jpeg}/Utils/MutableSpanExtensions.cs | 0 .../Formats/Png}/Filters/AverageFilter.cs | 0 .../Formats/Png}/Filters/FilterType.cs | 0 .../Formats/Png}/Filters/NoneFilter.cs | 0 .../Formats/Png}/Filters/PaethFilter.cs | 0 .../Formats/Png}/Filters/SubFilter.cs | 0 .../Formats/Png}/Filters/UpFilter.cs | 0 .../Formats/Png}/IPngDecoderOptions.cs | 0 .../Formats/Png}/IPngEncoderOptions.cs | 0 .../Formats/Png}/ImageExtensions.cs | 0 .../Formats/Png}/PngChunk.cs | 0 .../Formats/Png}/PngChunkTypes.cs | 0 .../Formats/Png}/PngColorType.cs | 0 .../Formats/Png}/PngDecoder.cs | 0 .../Formats/Png}/PngDecoderCore.cs | 0 .../Formats/Png}/PngDecoderOptions.cs | 0 .../Formats/Png}/PngEncoder.cs | 0 .../Formats/Png}/PngEncoderCore.cs | 0 .../Formats/Png}/PngEncoderOptions.cs | 0 .../Formats/Png}/PngFormat.cs | 0 .../Formats/Png}/PngHeader.cs | 0 .../Formats/Png}/PngInterlaceMode.cs | 0 .../Formats/Png}/README.md | 0 .../Formats/Png}/Zlib/Adler32.cs | 0 .../Formats/Png}/Zlib/Crc32.cs | 0 .../Formats/Png}/Zlib/IChecksum.cs | 0 .../Formats/Png}/Zlib/README.md | 0 .../Formats/Png}/Zlib/ZlibDeflateStream.cs | 0 .../Formats/Png}/Zlib/ZlibInflateStream.cs | 0 src/ImageSharp/ImageSharp.csproj | 20 +--- .../Binarization/BinaryThreshold.cs | 0 .../Processing}/Binarization/Dither.cs | 0 .../Processing}/ColorMatrix/BlackWhite.cs | 0 .../Processing}/ColorMatrix/ColorBlindness.cs | 0 .../Processing}/ColorMatrix/Grayscale.cs | 0 .../Processing}/ColorMatrix/Hue.cs | 0 .../Processing}/ColorMatrix/Kodachrome.cs | 0 .../Processing}/ColorMatrix/Lomograph.cs | 0 .../ColorMatrix/Options/ColorBlindness.cs | 0 .../ColorMatrix/Options/GrayscaleMode.cs | 0 .../Processing}/ColorMatrix/Polaroid.cs | 0 .../Processing}/ColorMatrix/Saturation.cs | 0 .../Processing}/ColorMatrix/Sepia.cs | 0 .../Processing}/Convolution/BoxBlur.cs | 0 .../Processing}/Convolution/DetectEdges.cs | 0 .../Processing}/Convolution/GaussianBlur.cs | 0 .../Convolution/GaussianSharpen.cs | 0 .../Convolution/Options/EdgeDetection.cs | 0 .../Processing}/Effects/Alpha.cs | 0 .../Processing}/Effects/BackgroundColor.cs | 0 .../Processing}/Effects/Brightness.cs | 0 .../Processing}/Effects/Contrast.cs | 0 .../Processing}/Effects/Invert.cs | 0 .../Processing}/Effects/OilPainting.cs | 0 .../Processing}/Effects/Pixelate.cs | 0 .../Processing}/Overlays/Glow.cs | 0 .../Processing}/Overlays/Vignette.cs | 0 .../Binarization/BinaryThresholdProcessor.cs | 0 .../ErrorDiffusionDitherProcessor.cs | 0 .../Binarization/OrderedDitherProcessor.cs | 0 .../ColorMatrix/BlackWhiteProcessor.cs | 0 .../ColorBlindness/AchromatomalyProcessor.cs | 0 .../ColorBlindness/AchromatopsiaProcessor.cs | 0 .../ColorBlindness/DeuteranomalyProcessor.cs | 0 .../ColorBlindness/DeuteranopiaProcessor.cs | 0 .../ColorBlindness/ProtanomalyProcessor.cs | 0 .../ColorBlindness/ProtanopiaProcessor.cs | 0 .../ColorMatrix/ColorBlindness/README.md | 0 .../ColorBlindness/TritanomalyProcessor.cs | 0 .../ColorBlindness/TritanopiaProcessor.cs | 0 .../ColorMatrix/ColorMatrixFilter.cs | 0 .../ColorMatrix/GrayscaleBt601Processor.cs | 0 .../ColorMatrix/GrayscaleBt709Processor.cs | 0 .../Processors/ColorMatrix/HueProcessor.cs | 0 .../ColorMatrix/IColorMatrixFilter.cs | 0 .../ColorMatrix/KodachromeProcessor.cs | 0 .../ColorMatrix/LomographProcessor.cs | 0 .../ColorMatrix/PolaroidProcessor.cs | 0 .../ColorMatrix/SaturationProcessor.cs | 0 .../Processors/ColorMatrix/SepiaProcessor.cs | 0 .../Convolution/BoxBlurProcessor.cs | 0 .../Convolution/Convolution2DProcessor.cs | 0 .../Convolution/Convolution2PassProcessor.cs | 0 .../Convolution/ConvolutionProcessor.cs | 0 .../EdgeDetection/EdgeDetector2DProcessor.cs | 0 .../EdgeDetectorCompassProcessor.cs | 0 .../EdgeDetection/EdgeDetectorProcessor.cs | 0 .../EdgeDetection/IEdgeDetectorProcessor.cs | 0 .../EdgeDetection/KayyaliProcessor.cs | 0 .../EdgeDetection/KirschProcessor.cs | 0 .../EdgeDetection/Laplacian3X3Processor.cs | 0 .../EdgeDetection/Laplacian5X5Processor.cs | 0 .../LaplacianOfGaussianProcessor.cs | 0 .../EdgeDetection/PrewittProcessor.cs | 0 .../EdgeDetection/RobertsCrossProcessor.cs | 0 .../EdgeDetection/RobinsonProcessor.cs | 0 .../EdgeDetection/ScharrProcessor.cs | 0 .../EdgeDetection/SobelProcessor.cs | 0 .../Convolution/GaussianBlurProcessor.cs | 0 .../Convolution/GaussianSharpenProcessor.cs | 0 .../Processors/Effects/AlphaProcessor.cs | 0 .../Effects/BackgroundColorProcessor.cs | 0 .../Processors/Effects/BrightnessProcessor.cs | 0 .../Processors/Effects/ContrastProcessor.cs | 0 .../Processors/Effects/InvertProcessor.cs | 0 .../Effects/OilPaintingProcessor.cs | 0 .../Processors/Effects/PixelateProcessor.cs | 0 .../Processors/Overlays/GlowProcessor.cs | 0 .../Processors/Overlays/VignetteProcessor.cs | 0 .../Transforms/CompandingResizeProcessor.cs | 0 .../Processors/Transforms/CropProcessor.cs | 0 .../Transforms/EntropyCropProcessor.cs | 0 .../Processors/Transforms/FlipProcessor.cs | 0 .../Transforms/Matrix3x2Processor.cs | 0 .../Transforms/ResamplingWeightedProcessor.cs | 0 .../Processors/Transforms/ResizeProcessor.cs | 0 .../Processors/Transforms/RotateProcessor.cs | 0 .../Processors/Transforms/SkewProcessor.cs | 0 .../Processing}/Transforms/AutoOrient.cs | 0 .../Processing}/Transforms/Crop.cs | 0 .../Processing}/Transforms/EntropyCrop.cs | 0 .../Processing}/Transforms/Flip.cs | 0 .../Transforms/Options/AnchorPosition.cs | 0 .../Transforms/Options/FlipType.cs | 0 .../Transforms/Options/Orientation.cs | 0 .../Transforms/Options/ResizeHelper.cs | 0 .../Transforms/Options/ResizeMode.cs | 0 .../Transforms/Options/ResizeOptions.cs | 0 .../Transforms/Options/RotateType.cs | 0 .../Processing}/Transforms/Pad.cs | 0 .../Transforms/Resamplers/BicubicResampler.cs | 0 .../Transforms/Resamplers/BoxResampler.cs | 0 .../Resamplers/CatmullRomResampler.cs | 0 .../Transforms/Resamplers/HermiteResampler.cs | 0 .../Transforms/Resamplers/IResampler.cs | 0 .../Resamplers/Lanczos2Resampler.cs | 0 .../Resamplers/Lanczos3Resampler.cs | 0 .../Resamplers/Lanczos5Resampler.cs | 0 .../Resamplers/Lanczos8Resampler.cs | 0 .../Resamplers/MitchellNetravaliResampler.cs | 0 .../Resamplers/NearestNeighborResampler.cs | 0 .../Resamplers/RobidouxResampler.cs | 0 .../Resamplers/RobidouxSharpResampler.cs | 0 .../Transforms/Resamplers/SplineResampler.cs | 0 .../Resamplers/TriangleResampler.cs | 0 .../Transforms/Resamplers/WelchResampler.cs | 0 .../Processing}/Transforms/Resize.cs | 0 .../Processing}/Transforms/Rotate.cs | 0 .../Processing}/Transforms/RotateFlip.cs | 0 .../Processing}/Transforms/Skew.cs | 0 src/ImageSharp/Properties/AssemblyInfo.cs | 7 +- .../ImageSharp.Benchmarks.csproj | 5 - tests/ImageSharp.Benchmarks/project.json | 67 ----------- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 20 +--- tests/ImageSharp.Tests/project.json | 71 ----------- 292 files changed, 24 insertions(+), 837 deletions(-) delete mode 100644 src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.csproj delete mode 100644 src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs delete mode 100644 src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.csproj delete mode 100644 src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/DrawBeziers.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/DrawLines.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/DrawPath.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/DrawPolygon.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/DrawRectangle.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/FillPaths.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/FillPolygon.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/FillRectangle.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/RectangleExtensions.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/ShapePath.cs (100%) rename src/{ImageSharp.Drawing.Paths => ImageSharp.Drawing/Paths}/ShapeRegion.cs (100%) rename src/{ImageSharp.Drawing.Text => ImageSharp.Drawing/Text}/DrawText.cs (100%) rename src/{ImageSharp.Drawing.Text => ImageSharp.Drawing/Text}/GlyphBuilder.cs (100%) rename src/{ImageSharp.Drawing.Text => ImageSharp.Drawing/Text}/TextGraphicsOptions.cs (100%) delete mode 100644 src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj delete mode 100644 src/ImageSharp.Formats.Bmp/Properties/AssemblyInfo.cs delete mode 100644 src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj delete mode 100644 src/ImageSharp.Formats.Gif/Properties/AssemblyInfo.cs delete mode 100644 src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj delete mode 100644 src/ImageSharp.Formats.Jpeg/Properties/AssemblyInfo.cs delete mode 100644 src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj delete mode 100644 src/ImageSharp.Formats.Png/Properties/AssemblyInfo.cs delete mode 100644 src/ImageSharp.Processing/ImageSharp.Processing.csproj delete mode 100644 src/ImageSharp.Processing/Properties/AssemblyInfo.cs rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/Brushes.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/Brushes{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/IBrush.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/ImageBrush.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/ImageBrush{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/PatternBrush.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/PatternBrush{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/Processors/BrushApplicator.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/RecolorBrush.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/RecolorBrush{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/SolidBrush.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Brushes/SolidBrush{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/DrawImage.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/DrawPath.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Drawable.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/FillRegion.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/GraphicsOptions.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/IPen.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/Pen.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/Pens.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/Pens{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/Pen{TColor}.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/Processors/ColoredPointInfo.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Pens/Processors/PenApplicator.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/PointInfo.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Processors/DrawImageProcessor.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Processors/DrawPathProcessor.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Processors/FillProcessor.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Processors/FillRegionProcessor.cs (100%) rename src/{ImageSharp.Drawing => ImageSharp/Drawing}/Region.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpBitsPerPixel.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpCompression.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpDecoder.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpDecoderCore.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpEncoder.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpEncoderCore.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpFileHeader.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpFormat.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/BmpInfoHeader.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/IBmpEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/ImageExtensions.cs (100%) rename src/{ImageSharp.Formats.Bmp => ImageSharp/Formats/Bmp}/README.md (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/DisposalMethod.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifConstants.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifDecoder.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifDecoderCore.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifDecoderOptions.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifEncoder.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifEncoderCore.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/GifFormat.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/IGifDecoderOptions.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/IGifEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/ImageExtensions.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/LzwDecoder.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/LzwEncoder.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/PackedField.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/README.md (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/Sections/GifGraphicsControlExtension.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/Sections/GifImageDescriptor.cs (100%) rename src/{ImageSharp.Formats.Gif => ImageSharp/Formats/Gif}/Sections/GifLogicalScreenDescriptor.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Block8x8F.Generated.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Block8x8F.Generated.tt (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Block8x8F.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/BlockQuad.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/DCT.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/Bits.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/Bytes.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/Component.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/ComponentScan.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/DecodedBlock.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/DecodedBlockArray.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/DecoderErrorCode.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/DecoderThrowHelper.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/EOFException.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/HuffmanTree.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/InputProcessor.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/JpegBlockProcessor.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/JpegPixelArea.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/JpegScanDecoder.ComputationData.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/JpegScanDecoder.DataPointers.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/JpegScanDecoder.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/JpegScanDecoder.md (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/MissingFF00Exception.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Decoder/YCbCrImage.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Encoder/HuffIndex.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Encoder/HuffmanLut.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Encoder/HuffmanSpec.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Components/Encoder/QuantIndex.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/IJpegEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/ImageExtensions.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegConstants.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegDecoder.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegDecoderCore.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegEncoder.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegEncoderCore.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegFormat.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/JpegSubsample.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/README.md (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/UnzigData.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Utils/JpegUtils.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Utils/MutableSpan.cs (100%) rename src/{ImageSharp.Formats.Jpeg => ImageSharp/Formats/Jpeg}/Utils/MutableSpanExtensions.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Filters/AverageFilter.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Filters/FilterType.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Filters/NoneFilter.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Filters/PaethFilter.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Filters/SubFilter.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Filters/UpFilter.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/IPngDecoderOptions.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/IPngEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/ImageExtensions.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngChunk.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngChunkTypes.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngColorType.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngDecoder.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngDecoderCore.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngDecoderOptions.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngEncoder.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngEncoderCore.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngEncoderOptions.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngFormat.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngHeader.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/PngInterlaceMode.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/README.md (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Zlib/Adler32.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Zlib/Crc32.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Zlib/IChecksum.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Zlib/README.md (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Zlib/ZlibDeflateStream.cs (100%) rename src/{ImageSharp.Formats.Png => ImageSharp/Formats/Png}/Zlib/ZlibInflateStream.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Binarization/BinaryThreshold.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Binarization/Dither.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/BlackWhite.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/ColorBlindness.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Grayscale.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Hue.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Kodachrome.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Lomograph.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Options/ColorBlindness.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Options/GrayscaleMode.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Polaroid.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Saturation.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/ColorMatrix/Sepia.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Convolution/BoxBlur.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Convolution/DetectEdges.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Convolution/GaussianBlur.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Convolution/GaussianSharpen.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Convolution/Options/EdgeDetection.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/Alpha.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/BackgroundColor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/Brightness.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/Contrast.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/Invert.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/OilPainting.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Effects/Pixelate.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Overlays/Glow.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Overlays/Vignette.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Binarization/BinaryThresholdProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Binarization/ErrorDiffusionDitherProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Binarization/OrderedDitherProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/BlackWhiteProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/README.md (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/ColorMatrixFilter.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/GrayscaleBt601Processor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/GrayscaleBt709Processor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/HueProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/IColorMatrixFilter.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/KodachromeProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/LomographProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/PolaroidProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/SaturationProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/ColorMatrix/SepiaProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/BoxBlurProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/Convolution2DProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/Convolution2PassProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/ConvolutionProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/KirschProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/PrewittProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/ScharrProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/EdgeDetection/SobelProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/GaussianBlurProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Convolution/GaussianSharpenProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/AlphaProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/BackgroundColorProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/BrightnessProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/ContrastProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/InvertProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/OilPaintingProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Effects/PixelateProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Overlays/GlowProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Overlays/VignetteProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/CompandingResizeProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/CropProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/EntropyCropProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/FlipProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/Matrix3x2Processor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/ResamplingWeightedProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/ResizeProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/RotateProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Processors/Transforms/SkewProcessor.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/AutoOrient.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Crop.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/EntropyCrop.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Flip.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/AnchorPosition.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/FlipType.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/Orientation.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/ResizeHelper.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/ResizeMode.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/ResizeOptions.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Options/RotateType.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Pad.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/BicubicResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/BoxResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/CatmullRomResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/HermiteResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/IResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/Lanczos2Resampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/Lanczos3Resampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/Lanczos5Resampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/Lanczos8Resampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/MitchellNetravaliResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/NearestNeighborResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/RobidouxResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/RobidouxSharpResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/SplineResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/TriangleResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resamplers/WelchResampler.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Resize.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Rotate.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/RotateFlip.cs (100%) rename src/{ImageSharp.Processing => ImageSharp/Processing}/Transforms/Skew.cs (100%) delete mode 100644 tests/ImageSharp.Benchmarks/project.json delete mode 100644 tests/ImageSharp.Tests/project.json diff --git a/ImageSharp.sln b/ImageSharp.sln index dec5cbc363..485fca7fbb 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -39,36 +39,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Drawing", "src\I EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{575A5002-DD9F-4335-AA47-1DD87FA13645}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Bmp", "src\ImageSharp.Formats.Bmp\ImageSharp.Formats.Bmp.csproj", "{C77661B9-F793-422E-8E27-AC60ECC5F215}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Gif", "src\ImageSharp.Formats.Gif\ImageSharp.Formats.Gif.csproj", "{27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Jpeg", "src\ImageSharp.Formats.Jpeg\ImageSharp.Formats.Jpeg.csproj", "{7213767C-0003-41CA-AB18-0223CFA7CE4B}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Formats.Png", "src\ImageSharp.Formats.Png\ImageSharp.Formats.Png.csproj", "{556ABDCF-ED93-4327-BE98-F6815F78B9B8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Processing", "src\ImageSharp.Processing\ImageSharp.Processing.csproj", "{A623CFE9-9D2B-4528-AD1F-2E834B061134}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" ProjectSection(ProjectDependencies) = postProject {2E33181E-6E28-4662-A801-E2E7DC206029} = {2E33181E-6E28-4662-A801-E2E7DC206029} {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} = {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} - {7213767C-0003-41CA-AB18-0223CFA7CE4B} = {7213767C-0003-41CA-AB18-0223CFA7CE4B} - {E5BD4F96-28A8-410C-8B63-1C5731948549} = {E5BD4F96-28A8-410C-8B63-1C5731948549} - {C77661B9-F793-422E-8E27-AC60ECC5F215} = {C77661B9-F793-422E-8E27-AC60ECC5F215} - {556ABDCF-ED93-4327-BE98-F6815F78B9B8} = {556ABDCF-ED93-4327-BE98-F6815F78B9B8} - {A623CFE9-9D2B-4528-AD1F-2E834B061134} = {A623CFE9-9D2B-4528-AD1F-2E834B061134} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests", "tests\ImageSharp.Tests\ImageSharp.Tests.csproj", "{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Drawing.Paths", "src\ImageSharp.Drawing.Paths\ImageSharp.Drawing.Paths.csproj", "{E5BD4F96-28A8-410C-8B63-1C5731948549}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Drawing.Text", "src\ImageSharp.Drawing.Text\ImageSharp.Drawing.Text.csproj", "{329D7698-65BC-48AD-A16F-428682964493}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -115,66 +95,6 @@ Global {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x64.Build.0 = Release|Any CPU {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x86.ActiveCfg = Release|Any CPU {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x86.Build.0 = Release|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x64.ActiveCfg = Debug|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x64.Build.0 = Debug|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x86.ActiveCfg = Debug|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Debug|x86.Build.0 = Debug|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|Any CPU.Build.0 = Release|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x64.ActiveCfg = Release|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x64.Build.0 = Release|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x86.ActiveCfg = Release|Any CPU - {C77661B9-F793-422E-8E27-AC60ECC5F215}.Release|x86.Build.0 = Release|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x64.ActiveCfg = Debug|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x64.Build.0 = Debug|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x86.ActiveCfg = Debug|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Debug|x86.Build.0 = Debug|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|Any CPU.Build.0 = Release|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x64.ActiveCfg = Release|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x64.Build.0 = Release|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x86.ActiveCfg = Release|Any CPU - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F}.Release|x86.Build.0 = Release|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x64.ActiveCfg = Debug|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x64.Build.0 = Debug|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x86.ActiveCfg = Debug|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Debug|x86.Build.0 = Debug|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|Any CPU.Build.0 = Release|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x64.ActiveCfg = Release|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x64.Build.0 = Release|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x86.ActiveCfg = Release|Any CPU - {7213767C-0003-41CA-AB18-0223CFA7CE4B}.Release|x86.Build.0 = Release|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x64.ActiveCfg = Debug|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x64.Build.0 = Debug|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x86.ActiveCfg = Debug|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Debug|x86.Build.0 = Debug|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|Any CPU.Build.0 = Release|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x64.ActiveCfg = Release|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x64.Build.0 = Release|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x86.ActiveCfg = Release|Any CPU - {556ABDCF-ED93-4327-BE98-F6815F78B9B8}.Release|x86.Build.0 = Release|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x64.ActiveCfg = Debug|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x64.Build.0 = Debug|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x86.ActiveCfg = Debug|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Debug|x86.Build.0 = Debug|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|Any CPU.Build.0 = Release|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x64.ActiveCfg = Release|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x64.Build.0 = Release|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x86.ActiveCfg = Release|Any CPU - {A623CFE9-9D2B-4528-AD1F-2E834B061134}.Release|x86.Build.0 = Release|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -211,30 +131,6 @@ Global {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.Build.0 = Release|Any CPU {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.ActiveCfg = Release|Any CPU {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.Build.0 = Release|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|x64.ActiveCfg = Debug|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|x64.Build.0 = Debug|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|x86.ActiveCfg = Debug|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Debug|x86.Build.0 = Debug|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|Any CPU.Build.0 = Release|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|x64.ActiveCfg = Release|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|x64.Build.0 = Release|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|x86.ActiveCfg = Release|Any CPU - {E5BD4F96-28A8-410C-8B63-1C5731948549}.Release|x86.Build.0 = Release|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Debug|Any CPU.Build.0 = Debug|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Debug|x64.ActiveCfg = Debug|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Debug|x64.Build.0 = Debug|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Debug|x86.ActiveCfg = Debug|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Debug|x86.Build.0 = Debug|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Release|Any CPU.ActiveCfg = Release|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Release|Any CPU.Build.0 = Release|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Release|x64.ActiveCfg = Release|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Release|x64.Build.0 = Release|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Release|x86.ActiveCfg = Release|Any CPU - {329D7698-65BC-48AD-A16F-428682964493}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -244,15 +140,8 @@ Global {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {2E33181E-6E28-4662-A801-E2E7DC206029} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {575A5002-DD9F-4335-AA47-1DD87FA13645} = {E919DF0B-2607-4462-8FC0-5C98FE50F8C9} - {C77661B9-F793-422E-8E27-AC60ECC5F215} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {27AD4B5F-ECC4-4C63-9ECB-04EC772FDB6F} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {7213767C-0003-41CA-AB18-0223CFA7CE4B} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {556ABDCF-ED93-4327-BE98-F6815F78B9B8} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {A623CFE9-9D2B-4528-AD1F-2E834B061134} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} - {E5BD4F96-28A8-410C-8B63-1C5731948549} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} - {329D7698-65BC-48AD-A16F-428682964493} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} EndGlobalSection EndGlobal diff --git a/build/Properties/launchSettings.json b/build/Properties/launchSettings.json index b3ff6cb020..d175ae7547 100644 --- a/build/Properties/launchSettings.json +++ b/build/Properties/launchSettings.json @@ -1,7 +1,8 @@ { "profiles": { "build": { - "commandName": "Project" + "commandName": "Project", + "commandLineArgs": "reset" } } } \ No newline at end of file diff --git a/build/build.csproj b/build/build.csproj index 371c6f91b5..56b6f82bf4 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -1,7 +1,6 @@  - net46 - win7-x64 + netcoreapp1.0 portable true build @@ -10,12 +9,7 @@ ..\ImageSharp.ruleset - - - + + - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.csproj b/src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.csproj deleted file mode 100644 index 7afccc882d..0000000000 --- a/src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.csproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Drawing.Paths - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Drawing.Paths - ImageSharp.Drawing.Paths - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - diff --git a/src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs b/src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs deleted file mode 100644 index fba25a9dba..0000000000 --- a/src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` diff --git a/src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.csproj b/src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.csproj deleted file mode 100644 index f0e23c0c28..0000000000 --- a/src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.csproj +++ /dev/null @@ -1,84 +0,0 @@ - - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Drawing.Text - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Drawing.Text - ImageSharp.Drawing.Text - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - diff --git a/src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs b/src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs deleted file mode 100644 index fba25a9dba..0000000000 --- a/src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index ba4ccb7d1e..de759859b1 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -4,7 +4,7 @@ ImageSharp.Drawing 1.0.0-alpha2 James Jackson-South and contributors - netstandard1.1;net45;net461 + netstandard1.1 true true ImageSharp.Drawing @@ -30,21 +30,14 @@ - + + - - - - - - - - ..\..\ImageSharp.ruleset @@ -52,11 +45,4 @@ true - - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Drawing.Paths/DrawBeziers.cs b/src/ImageSharp.Drawing/Paths/DrawBeziers.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/DrawBeziers.cs rename to src/ImageSharp.Drawing/Paths/DrawBeziers.cs diff --git a/src/ImageSharp.Drawing.Paths/DrawLines.cs b/src/ImageSharp.Drawing/Paths/DrawLines.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/DrawLines.cs rename to src/ImageSharp.Drawing/Paths/DrawLines.cs diff --git a/src/ImageSharp.Drawing.Paths/DrawPath.cs b/src/ImageSharp.Drawing/Paths/DrawPath.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/DrawPath.cs rename to src/ImageSharp.Drawing/Paths/DrawPath.cs diff --git a/src/ImageSharp.Drawing.Paths/DrawPolygon.cs b/src/ImageSharp.Drawing/Paths/DrawPolygon.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/DrawPolygon.cs rename to src/ImageSharp.Drawing/Paths/DrawPolygon.cs diff --git a/src/ImageSharp.Drawing.Paths/DrawRectangle.cs b/src/ImageSharp.Drawing/Paths/DrawRectangle.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/DrawRectangle.cs rename to src/ImageSharp.Drawing/Paths/DrawRectangle.cs diff --git a/src/ImageSharp.Drawing.Paths/FillPaths.cs b/src/ImageSharp.Drawing/Paths/FillPaths.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/FillPaths.cs rename to src/ImageSharp.Drawing/Paths/FillPaths.cs diff --git a/src/ImageSharp.Drawing.Paths/FillPolygon.cs b/src/ImageSharp.Drawing/Paths/FillPolygon.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/FillPolygon.cs rename to src/ImageSharp.Drawing/Paths/FillPolygon.cs diff --git a/src/ImageSharp.Drawing.Paths/FillRectangle.cs b/src/ImageSharp.Drawing/Paths/FillRectangle.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/FillRectangle.cs rename to src/ImageSharp.Drawing/Paths/FillRectangle.cs diff --git a/src/ImageSharp.Drawing.Paths/RectangleExtensions.cs b/src/ImageSharp.Drawing/Paths/RectangleExtensions.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/RectangleExtensions.cs rename to src/ImageSharp.Drawing/Paths/RectangleExtensions.cs diff --git a/src/ImageSharp.Drawing.Paths/ShapePath.cs b/src/ImageSharp.Drawing/Paths/ShapePath.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/ShapePath.cs rename to src/ImageSharp.Drawing/Paths/ShapePath.cs diff --git a/src/ImageSharp.Drawing.Paths/ShapeRegion.cs b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs similarity index 100% rename from src/ImageSharp.Drawing.Paths/ShapeRegion.cs rename to src/ImageSharp.Drawing/Paths/ShapeRegion.cs diff --git a/src/ImageSharp.Drawing.Text/DrawText.cs b/src/ImageSharp.Drawing/Text/DrawText.cs similarity index 100% rename from src/ImageSharp.Drawing.Text/DrawText.cs rename to src/ImageSharp.Drawing/Text/DrawText.cs diff --git a/src/ImageSharp.Drawing.Text/GlyphBuilder.cs b/src/ImageSharp.Drawing/Text/GlyphBuilder.cs similarity index 100% rename from src/ImageSharp.Drawing.Text/GlyphBuilder.cs rename to src/ImageSharp.Drawing/Text/GlyphBuilder.cs diff --git a/src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs similarity index 100% rename from src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs rename to src/ImageSharp.Drawing/Text/TextGraphicsOptions.cs diff --git a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj b/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj deleted file mode 100644 index 77df6cac28..0000000000 --- a/src/ImageSharp.Formats.Bmp/ImageSharp.Formats.Bmp.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Formats.Bmp - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Formats.Bmp - ImageSharp.Formats.Bmp - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - ..\..\ImageSharp.ruleset - - - true - - - - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Bmp/Properties/AssemblyInfo.cs b/src/ImageSharp.Formats.Bmp/Properties/AssemblyInfo.cs deleted file mode 100644 index d6e98c6d6c..0000000000 --- a/src/ImageSharp.Formats.Bmp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` \ No newline at end of file diff --git a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj b/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj deleted file mode 100644 index 0b4fd4c2da..0000000000 --- a/src/ImageSharp.Formats.Gif/ImageSharp.Formats.Gif.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Formats.Gif - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Formats.Gif - ImageSharp.Formats.Gif - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - ..\..\ImageSharp.ruleset - - - true - - - - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Gif/Properties/AssemblyInfo.cs b/src/ImageSharp.Formats.Gif/Properties/AssemblyInfo.cs deleted file mode 100644 index d6e98c6d6c..0000000000 --- a/src/ImageSharp.Formats.Gif/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj b/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj deleted file mode 100644 index f09576932d..0000000000 --- a/src/ImageSharp.Formats.Jpeg/ImageSharp.Formats.Jpeg.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Formats.Jpeg - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Formats.Jpeg - ImageSharp.Formats.Jpeg - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - ..\..\ImageSharp.ruleset - - - true - - - - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Jpeg/Properties/AssemblyInfo.cs b/src/ImageSharp.Formats.Jpeg/Properties/AssemblyInfo.cs deleted file mode 100644 index d6e98c6d6c..0000000000 --- a/src/ImageSharp.Formats.Jpeg/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` \ No newline at end of file diff --git a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj b/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj deleted file mode 100644 index b58d5fbf3b..0000000000 --- a/src/ImageSharp.Formats.Png/ImageSharp.Formats.Png.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Formats.Png - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Formats.Png - ImageSharp.Formats.Png - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - ..\..\ImageSharp.ruleset - - - true - - - - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Formats.Png/Properties/AssemblyInfo.cs b/src/ImageSharp.Formats.Png/Properties/AssemblyInfo.cs deleted file mode 100644 index d6e98c6d6c..0000000000 --- a/src/ImageSharp.Formats.Png/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` \ No newline at end of file diff --git a/src/ImageSharp.Processing/ImageSharp.Processing.csproj b/src/ImageSharp.Processing/ImageSharp.Processing.csproj deleted file mode 100644 index 820c1852d7..0000000000 --- a/src/ImageSharp.Processing/ImageSharp.Processing.csproj +++ /dev/null @@ -1,61 +0,0 @@ - - - A cross-platform library for the processing of image files; written in C# - ImageSharp.Processing - 1.0.0-alpha2 - James Jackson-South and contributors - netstandard1.1;net45;net461 - true - true - ImageSharp.Processing - ImageSharp.Processing - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core - https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png - https://github.com/JimBobSquarePants/ImageSharp - http://www.apache.org/licenses/LICENSE-2.0 - git - https://github.com/JimBobSquarePants/ImageSharp - false - false - false - false - false - false - false - false - false - - - - - - - - - - - - - - - - - - - - - - - ..\..\ImageSharp.ruleset - - - true - - - - - - - - - \ No newline at end of file diff --git a/src/ImageSharp.Processing/Properties/AssemblyInfo.cs b/src/ImageSharp.Processing/Properties/AssemblyInfo.cs deleted file mode 100644 index d6e98c6d6c..0000000000 --- a/src/ImageSharp.Processing/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,6 +0,0 @@ -// -// Copyright (c) James Jackson-South and contributors. -// Licensed under the Apache License, Version 2.0. -// - -// Common values read from `AssemblyInfo.Common.cs` \ No newline at end of file diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index daf68d81b4..e9120aa479 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -78,10 +78,10 @@ namespace ImageSharp Configuration config = new Configuration(); // lets try auto loading the known image formats - config.TryAddImageFormat("ImageSharp.Formats.PngFormat, ImageSharp.Formats.Png"); - config.TryAddImageFormat("ImageSharp.Formats.JpegFormat, ImageSharp.Formats.Jpeg"); - config.TryAddImageFormat("ImageSharp.Formats.GifFormat, ImageSharp.Formats.Gif"); - config.TryAddImageFormat("ImageSharp.Formats.BmpFormat, ImageSharp.Formats.Bmp"); + config.AddImageFormat(new Formats.PngFormat()); + config.AddImageFormat(new Formats.JpegFormat()); + config.AddImageFormat(new Formats.GifFormat()); + config.AddImageFormat(new Formats.BmpFormat()); return config; } diff --git a/src/ImageSharp.Drawing/Brushes/Brushes.cs b/src/ImageSharp/Drawing/Brushes/Brushes.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/Brushes.cs rename to src/ImageSharp/Drawing/Brushes/Brushes.cs diff --git a/src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs b/src/ImageSharp/Drawing/Brushes/Brushes{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs rename to src/ImageSharp/Drawing/Brushes/Brushes{TColor}.cs diff --git a/src/ImageSharp.Drawing/Brushes/IBrush.cs b/src/ImageSharp/Drawing/Brushes/IBrush.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/IBrush.cs rename to src/ImageSharp/Drawing/Brushes/IBrush.cs diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush.cs b/src/ImageSharp/Drawing/Brushes/ImageBrush.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/ImageBrush.cs rename to src/ImageSharp/Drawing/Brushes/ImageBrush.cs diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs b/src/ImageSharp/Drawing/Brushes/ImageBrush{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs rename to src/ImageSharp/Drawing/Brushes/ImageBrush{TColor}.cs diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush.cs b/src/ImageSharp/Drawing/Brushes/PatternBrush.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/PatternBrush.cs rename to src/ImageSharp/Drawing/Brushes/PatternBrush.cs diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs b/src/ImageSharp/Drawing/Brushes/PatternBrush{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs rename to src/ImageSharp/Drawing/Brushes/PatternBrush{TColor}.cs diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp/Drawing/Brushes/Processors/BrushApplicator.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs rename to src/ImageSharp/Drawing/Brushes/Processors/BrushApplicator.cs diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush.cs b/src/ImageSharp/Drawing/Brushes/RecolorBrush.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/RecolorBrush.cs rename to src/ImageSharp/Drawing/Brushes/RecolorBrush.cs diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs b/src/ImageSharp/Drawing/Brushes/RecolorBrush{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs rename to src/ImageSharp/Drawing/Brushes/RecolorBrush{TColor}.cs diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush.cs b/src/ImageSharp/Drawing/Brushes/SolidBrush.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/SolidBrush.cs rename to src/ImageSharp/Drawing/Brushes/SolidBrush.cs diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs b/src/ImageSharp/Drawing/Brushes/SolidBrush{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs rename to src/ImageSharp/Drawing/Brushes/SolidBrush{TColor}.cs diff --git a/src/ImageSharp.Drawing/DrawImage.cs b/src/ImageSharp/Drawing/DrawImage.cs similarity index 100% rename from src/ImageSharp.Drawing/DrawImage.cs rename to src/ImageSharp/Drawing/DrawImage.cs diff --git a/src/ImageSharp.Drawing/DrawPath.cs b/src/ImageSharp/Drawing/DrawPath.cs similarity index 100% rename from src/ImageSharp.Drawing/DrawPath.cs rename to src/ImageSharp/Drawing/DrawPath.cs diff --git a/src/ImageSharp.Drawing/Drawable.cs b/src/ImageSharp/Drawing/Drawable.cs similarity index 100% rename from src/ImageSharp.Drawing/Drawable.cs rename to src/ImageSharp/Drawing/Drawable.cs diff --git a/src/ImageSharp.Drawing/FillRegion.cs b/src/ImageSharp/Drawing/FillRegion.cs similarity index 100% rename from src/ImageSharp.Drawing/FillRegion.cs rename to src/ImageSharp/Drawing/FillRegion.cs diff --git a/src/ImageSharp.Drawing/GraphicsOptions.cs b/src/ImageSharp/Drawing/GraphicsOptions.cs similarity index 100% rename from src/ImageSharp.Drawing/GraphicsOptions.cs rename to src/ImageSharp/Drawing/GraphicsOptions.cs diff --git a/src/ImageSharp.Drawing/Pens/IPen.cs b/src/ImageSharp/Drawing/Pens/IPen.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/IPen.cs rename to src/ImageSharp/Drawing/Pens/IPen.cs diff --git a/src/ImageSharp.Drawing/Pens/Pen.cs b/src/ImageSharp/Drawing/Pens/Pen.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/Pen.cs rename to src/ImageSharp/Drawing/Pens/Pen.cs diff --git a/src/ImageSharp.Drawing/Pens/Pens.cs b/src/ImageSharp/Drawing/Pens/Pens.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/Pens.cs rename to src/ImageSharp/Drawing/Pens/Pens.cs diff --git a/src/ImageSharp.Drawing/Pens/Pens{TColor}.cs b/src/ImageSharp/Drawing/Pens/Pens{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/Pens{TColor}.cs rename to src/ImageSharp/Drawing/Pens/Pens{TColor}.cs diff --git a/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs b/src/ImageSharp/Drawing/Pens/Pen{TColor}.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/Pen{TColor}.cs rename to src/ImageSharp/Drawing/Pens/Pen{TColor}.cs diff --git a/src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs b/src/ImageSharp/Drawing/Pens/Processors/ColoredPointInfo.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs rename to src/ImageSharp/Drawing/Pens/Processors/ColoredPointInfo.cs diff --git a/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp/Drawing/Pens/Processors/PenApplicator.cs similarity index 100% rename from src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs rename to src/ImageSharp/Drawing/Pens/Processors/PenApplicator.cs diff --git a/src/ImageSharp.Drawing/PointInfo.cs b/src/ImageSharp/Drawing/PointInfo.cs similarity index 100% rename from src/ImageSharp.Drawing/PointInfo.cs rename to src/ImageSharp/Drawing/PointInfo.cs diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs similarity index 100% rename from src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs rename to src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs similarity index 100% rename from src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs rename to src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp/Drawing/Processors/FillProcessor.cs similarity index 100% rename from src/ImageSharp.Drawing/Processors/FillProcessor.cs rename to src/ImageSharp/Drawing/Processors/FillProcessor.cs diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp/Drawing/Processors/FillRegionProcessor.cs similarity index 100% rename from src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs rename to src/ImageSharp/Drawing/Processors/FillRegionProcessor.cs diff --git a/src/ImageSharp.Drawing/Region.cs b/src/ImageSharp/Drawing/Region.cs similarity index 100% rename from src/ImageSharp.Drawing/Region.cs rename to src/ImageSharp/Drawing/Region.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpBitsPerPixel.cs b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpBitsPerPixel.cs rename to src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpCompression.cs b/src/ImageSharp/Formats/Bmp/BmpCompression.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpCompression.cs rename to src/ImageSharp/Formats/Bmp/BmpCompression.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpDecoder.cs b/src/ImageSharp/Formats/Bmp/BmpDecoder.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpDecoder.cs rename to src/ImageSharp/Formats/Bmp/BmpDecoder.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpDecoderCore.cs rename to src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpEncoder.cs rename to src/ImageSharp/Formats/Bmp/BmpEncoder.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs rename to src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs rename to src/ImageSharp/Formats/Bmp/BmpEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpFileHeader.cs b/src/ImageSharp/Formats/Bmp/BmpFileHeader.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpFileHeader.cs rename to src/ImageSharp/Formats/Bmp/BmpFileHeader.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpFormat.cs rename to src/ImageSharp/Formats/Bmp/BmpFormat.cs diff --git a/src/ImageSharp.Formats.Bmp/BmpInfoHeader.cs b/src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/BmpInfoHeader.cs rename to src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs diff --git a/src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs rename to src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs similarity index 100% rename from src/ImageSharp.Formats.Bmp/ImageExtensions.cs rename to src/ImageSharp/Formats/Bmp/ImageExtensions.cs diff --git a/src/ImageSharp.Formats.Bmp/README.md b/src/ImageSharp/Formats/Bmp/README.md similarity index 100% rename from src/ImageSharp.Formats.Bmp/README.md rename to src/ImageSharp/Formats/Bmp/README.md diff --git a/src/ImageSharp.Formats.Gif/DisposalMethod.cs b/src/ImageSharp/Formats/Gif/DisposalMethod.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/DisposalMethod.cs rename to src/ImageSharp/Formats/Gif/DisposalMethod.cs diff --git a/src/ImageSharp.Formats.Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifConstants.cs rename to src/ImageSharp/Formats/Gif/GifConstants.cs diff --git a/src/ImageSharp.Formats.Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifDecoder.cs rename to src/ImageSharp/Formats/Gif/GifDecoder.cs diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifDecoderCore.cs rename to src/ImageSharp/Formats/Gif/GifDecoderCore.cs diff --git a/src/ImageSharp.Formats.Gif/GifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/GifDecoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifDecoderOptions.cs rename to src/ImageSharp/Formats/Gif/GifDecoderOptions.cs diff --git a/src/ImageSharp.Formats.Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifEncoder.cs rename to src/ImageSharp/Formats/Gif/GifEncoder.cs diff --git a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifEncoderCore.cs rename to src/ImageSharp/Formats/Gif/GifEncoderCore.cs diff --git a/src/ImageSharp.Formats.Gif/GifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/GifEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifEncoderOptions.cs rename to src/ImageSharp/Formats/Gif/GifEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/GifFormat.cs rename to src/ImageSharp/Formats/Gif/GifFormat.cs diff --git a/src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/IGifDecoderOptions.cs rename to src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs diff --git a/src/ImageSharp.Formats.Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/IGifEncoderOptions.cs rename to src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/ImageExtensions.cs rename to src/ImageSharp/Formats/Gif/ImageExtensions.cs diff --git a/src/ImageSharp.Formats.Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/LzwDecoder.cs rename to src/ImageSharp/Formats/Gif/LzwDecoder.cs diff --git a/src/ImageSharp.Formats.Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/LzwEncoder.cs rename to src/ImageSharp/Formats/Gif/LzwEncoder.cs diff --git a/src/ImageSharp.Formats.Gif/PackedField.cs b/src/ImageSharp/Formats/Gif/PackedField.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/PackedField.cs rename to src/ImageSharp/Formats/Gif/PackedField.cs diff --git a/src/ImageSharp.Formats.Gif/README.md b/src/ImageSharp/Formats/Gif/README.md similarity index 100% rename from src/ImageSharp.Formats.Gif/README.md rename to src/ImageSharp/Formats/Gif/README.md diff --git a/src/ImageSharp.Formats.Gif/Sections/GifGraphicsControlExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifGraphicsControlExtension.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/Sections/GifGraphicsControlExtension.cs rename to src/ImageSharp/Formats/Gif/Sections/GifGraphicsControlExtension.cs diff --git a/src/ImageSharp.Formats.Gif/Sections/GifImageDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/Sections/GifImageDescriptor.cs rename to src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs diff --git a/src/ImageSharp.Formats.Gif/Sections/GifLogicalScreenDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs similarity index 100% rename from src/ImageSharp.Formats.Gif/Sections/GifLogicalScreenDescriptor.cs rename to src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Block8x8F.Generated.cs rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Block8x8F.Generated.tt rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt diff --git a/src/ImageSharp.Formats.Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Block8x8F.cs rename to src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/BlockQuad.cs b/src/ImageSharp/Formats/Jpeg/Components/BlockQuad.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/BlockQuad.cs rename to src/ImageSharp/Formats/Jpeg/Components/BlockQuad.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/DCT.cs b/src/ImageSharp/Formats/Jpeg/Components/DCT.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/DCT.cs rename to src/ImageSharp/Formats/Jpeg/Components/DCT.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/Bits.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/Bits.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/Bits.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/Bytes.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/Bytes.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/Bytes.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/Component.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/Component.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/Component.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/Component.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/ComponentScan.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentScan.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/ComponentScan.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentScan.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlock.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/DecodedBlock.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlock.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/DecodedBlock.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockArray.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/DecodedBlockArray.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/DecodedBlockArray.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/DecodedBlockArray.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderErrorCode.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/DecoderErrorCode.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderErrorCode.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/DecoderErrorCode.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/DecoderThrowHelper.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/DecoderThrowHelper.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/DecoderThrowHelper.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/EOFException.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/EOFException.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/EOFException.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/HuffmanTree.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTree.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/HuffmanTree.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTree.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/InputProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/InputProcessor.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/InputProcessor.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/InputProcessor.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegBlockProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegBlockProcessor.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegPixelArea.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegPixelArea.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.ComputationData.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.DataPointers.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.DataPointers.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.DataPointers.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.DataPointers.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.md similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/JpegScanDecoder.md rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.md diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/MissingFF00Exception.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/MissingFF00Exception.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/MissingFF00Exception.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/MissingFF00Exception.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Decoder/YCbCrImage.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Decoder/YCbCrImage.cs rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Encoder/HuffIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Encoder/HuffIndex.cs rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffIndex.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Encoder/HuffmanLut.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Encoder/HuffmanLut.cs rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanLut.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Encoder/HuffmanSpec.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Encoder/HuffmanSpec.cs rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanSpec.cs diff --git a/src/ImageSharp.Formats.Jpeg/Components/Encoder/QuantIndex.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Components/Encoder/QuantIndex.cs rename to src/ImageSharp/Formats/Jpeg/Components/Encoder/QuantIndex.cs diff --git a/src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/IJpegEncoderOptions.cs rename to src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/ImageExtensions.cs rename to src/ImageSharp/Formats/Jpeg/ImageExtensions.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegConstants.cs b/src/ImageSharp/Formats/Jpeg/JpegConstants.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegConstants.cs rename to src/ImageSharp/Formats/Jpeg/JpegConstants.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoder.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoder.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegDecoder.cs rename to src/ImageSharp/Formats/Jpeg/JpegDecoder.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs rename to src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegEncoder.cs rename to src/ImageSharp/Formats/Jpeg/JpegEncoder.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs rename to src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegEncoderOptions.cs rename to src/ImageSharp/Formats/Jpeg/JpegEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegFormat.cs rename to src/ImageSharp/Formats/Jpeg/JpegFormat.cs diff --git a/src/ImageSharp.Formats.Jpeg/JpegSubsample.cs b/src/ImageSharp/Formats/Jpeg/JpegSubsample.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/JpegSubsample.cs rename to src/ImageSharp/Formats/Jpeg/JpegSubsample.cs diff --git a/src/ImageSharp.Formats.Jpeg/README.md b/src/ImageSharp/Formats/Jpeg/README.md similarity index 100% rename from src/ImageSharp.Formats.Jpeg/README.md rename to src/ImageSharp/Formats/Jpeg/README.md diff --git a/src/ImageSharp.Formats.Jpeg/UnzigData.cs b/src/ImageSharp/Formats/Jpeg/UnzigData.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/UnzigData.cs rename to src/ImageSharp/Formats/Jpeg/UnzigData.cs diff --git a/src/ImageSharp.Formats.Jpeg/Utils/JpegUtils.cs b/src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Utils/JpegUtils.cs rename to src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs diff --git a/src/ImageSharp.Formats.Jpeg/Utils/MutableSpan.cs b/src/ImageSharp/Formats/Jpeg/Utils/MutableSpan.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Utils/MutableSpan.cs rename to src/ImageSharp/Formats/Jpeg/Utils/MutableSpan.cs diff --git a/src/ImageSharp.Formats.Jpeg/Utils/MutableSpanExtensions.cs b/src/ImageSharp/Formats/Jpeg/Utils/MutableSpanExtensions.cs similarity index 100% rename from src/ImageSharp.Formats.Jpeg/Utils/MutableSpanExtensions.cs rename to src/ImageSharp/Formats/Jpeg/Utils/MutableSpanExtensions.cs diff --git a/src/ImageSharp.Formats.Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Filters/AverageFilter.cs rename to src/ImageSharp/Formats/Png/Filters/AverageFilter.cs diff --git a/src/ImageSharp.Formats.Png/Filters/FilterType.cs b/src/ImageSharp/Formats/Png/Filters/FilterType.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Filters/FilterType.cs rename to src/ImageSharp/Formats/Png/Filters/FilterType.cs diff --git a/src/ImageSharp.Formats.Png/Filters/NoneFilter.cs b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Filters/NoneFilter.cs rename to src/ImageSharp/Formats/Png/Filters/NoneFilter.cs diff --git a/src/ImageSharp.Formats.Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Filters/PaethFilter.cs rename to src/ImageSharp/Formats/Png/Filters/PaethFilter.cs diff --git a/src/ImageSharp.Formats.Png/Filters/SubFilter.cs b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Filters/SubFilter.cs rename to src/ImageSharp/Formats/Png/Filters/SubFilter.cs diff --git a/src/ImageSharp.Formats.Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Filters/UpFilter.cs rename to src/ImageSharp/Formats/Png/Filters/UpFilter.cs diff --git a/src/ImageSharp.Formats.Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Png/IPngDecoderOptions.cs rename to src/ImageSharp/Formats/Png/IPngDecoderOptions.cs diff --git a/src/ImageSharp.Formats.Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Png/IPngEncoderOptions.cs rename to src/ImageSharp/Formats/Png/IPngEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs similarity index 100% rename from src/ImageSharp.Formats.Png/ImageExtensions.cs rename to src/ImageSharp/Formats/Png/ImageExtensions.cs diff --git a/src/ImageSharp.Formats.Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngChunk.cs rename to src/ImageSharp/Formats/Png/PngChunk.cs diff --git a/src/ImageSharp.Formats.Png/PngChunkTypes.cs b/src/ImageSharp/Formats/Png/PngChunkTypes.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngChunkTypes.cs rename to src/ImageSharp/Formats/Png/PngChunkTypes.cs diff --git a/src/ImageSharp.Formats.Png/PngColorType.cs b/src/ImageSharp/Formats/Png/PngColorType.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngColorType.cs rename to src/ImageSharp/Formats/Png/PngColorType.cs diff --git a/src/ImageSharp.Formats.Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngDecoder.cs rename to src/ImageSharp/Formats/Png/PngDecoder.cs diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngDecoderCore.cs rename to src/ImageSharp/Formats/Png/PngDecoderCore.cs diff --git a/src/ImageSharp.Formats.Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngDecoderOptions.cs rename to src/ImageSharp/Formats/Png/PngDecoderOptions.cs diff --git a/src/ImageSharp.Formats.Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngEncoder.cs rename to src/ImageSharp/Formats/Png/PngEncoder.cs diff --git a/src/ImageSharp.Formats.Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngEncoderCore.cs rename to src/ImageSharp/Formats/Png/PngEncoderCore.cs diff --git a/src/ImageSharp.Formats.Png/PngEncoderOptions.cs b/src/ImageSharp/Formats/Png/PngEncoderOptions.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngEncoderOptions.cs rename to src/ImageSharp/Formats/Png/PngEncoderOptions.cs diff --git a/src/ImageSharp.Formats.Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngFormat.cs rename to src/ImageSharp/Formats/Png/PngFormat.cs diff --git a/src/ImageSharp.Formats.Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngHeader.cs rename to src/ImageSharp/Formats/Png/PngHeader.cs diff --git a/src/ImageSharp.Formats.Png/PngInterlaceMode.cs b/src/ImageSharp/Formats/Png/PngInterlaceMode.cs similarity index 100% rename from src/ImageSharp.Formats.Png/PngInterlaceMode.cs rename to src/ImageSharp/Formats/Png/PngInterlaceMode.cs diff --git a/src/ImageSharp.Formats.Png/README.md b/src/ImageSharp/Formats/Png/README.md similarity index 100% rename from src/ImageSharp.Formats.Png/README.md rename to src/ImageSharp/Formats/Png/README.md diff --git a/src/ImageSharp.Formats.Png/Zlib/Adler32.cs b/src/ImageSharp/Formats/Png/Zlib/Adler32.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Zlib/Adler32.cs rename to src/ImageSharp/Formats/Png/Zlib/Adler32.cs diff --git a/src/ImageSharp.Formats.Png/Zlib/Crc32.cs b/src/ImageSharp/Formats/Png/Zlib/Crc32.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Zlib/Crc32.cs rename to src/ImageSharp/Formats/Png/Zlib/Crc32.cs diff --git a/src/ImageSharp.Formats.Png/Zlib/IChecksum.cs b/src/ImageSharp/Formats/Png/Zlib/IChecksum.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Zlib/IChecksum.cs rename to src/ImageSharp/Formats/Png/Zlib/IChecksum.cs diff --git a/src/ImageSharp.Formats.Png/Zlib/README.md b/src/ImageSharp/Formats/Png/Zlib/README.md similarity index 100% rename from src/ImageSharp.Formats.Png/Zlib/README.md rename to src/ImageSharp/Formats/Png/Zlib/README.md diff --git a/src/ImageSharp.Formats.Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Zlib/ZlibDeflateStream.cs rename to src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs diff --git a/src/ImageSharp.Formats.Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs similarity index 100% rename from src/ImageSharp.Formats.Png/Zlib/ZlibInflateStream.cs rename to src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 762e68b508..c2e6ee3c20 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -4,7 +4,7 @@ ImageSharp 1.0.0-alpha2 James Jackson-South and contributors - netstandard1.1;net45;net461 + netstandard1.3;netstandard1.1 true true ImageSharp @@ -32,15 +32,7 @@ - - - - - - - - ..\..\ImageSharp.ruleset @@ -48,11 +40,9 @@ true - - - - - - + + + TextTemplatingFileGenerator + \ No newline at end of file diff --git a/src/ImageSharp.Processing/Binarization/BinaryThreshold.cs b/src/ImageSharp/Processing/Binarization/BinaryThreshold.cs similarity index 100% rename from src/ImageSharp.Processing/Binarization/BinaryThreshold.cs rename to src/ImageSharp/Processing/Binarization/BinaryThreshold.cs diff --git a/src/ImageSharp.Processing/Binarization/Dither.cs b/src/ImageSharp/Processing/Binarization/Dither.cs similarity index 100% rename from src/ImageSharp.Processing/Binarization/Dither.cs rename to src/ImageSharp/Processing/Binarization/Dither.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/BlackWhite.cs b/src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/BlackWhite.cs rename to src/ImageSharp/Processing/ColorMatrix/BlackWhite.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/ColorBlindness.cs b/src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/ColorBlindness.cs rename to src/ImageSharp/Processing/ColorMatrix/ColorBlindness.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Grayscale.cs b/src/ImageSharp/Processing/ColorMatrix/Grayscale.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Grayscale.cs rename to src/ImageSharp/Processing/ColorMatrix/Grayscale.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Hue.cs b/src/ImageSharp/Processing/ColorMatrix/Hue.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Hue.cs rename to src/ImageSharp/Processing/ColorMatrix/Hue.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Kodachrome.cs b/src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Kodachrome.cs rename to src/ImageSharp/Processing/ColorMatrix/Kodachrome.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Lomograph.cs b/src/ImageSharp/Processing/ColorMatrix/Lomograph.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Lomograph.cs rename to src/ImageSharp/Processing/ColorMatrix/Lomograph.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Options/ColorBlindness.cs b/src/ImageSharp/Processing/ColorMatrix/Options/ColorBlindness.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Options/ColorBlindness.cs rename to src/ImageSharp/Processing/ColorMatrix/Options/ColorBlindness.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Options/GrayscaleMode.cs b/src/ImageSharp/Processing/ColorMatrix/Options/GrayscaleMode.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Options/GrayscaleMode.cs rename to src/ImageSharp/Processing/ColorMatrix/Options/GrayscaleMode.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Polaroid.cs b/src/ImageSharp/Processing/ColorMatrix/Polaroid.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Polaroid.cs rename to src/ImageSharp/Processing/ColorMatrix/Polaroid.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Saturation.cs b/src/ImageSharp/Processing/ColorMatrix/Saturation.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Saturation.cs rename to src/ImageSharp/Processing/ColorMatrix/Saturation.cs diff --git a/src/ImageSharp.Processing/ColorMatrix/Sepia.cs b/src/ImageSharp/Processing/ColorMatrix/Sepia.cs similarity index 100% rename from src/ImageSharp.Processing/ColorMatrix/Sepia.cs rename to src/ImageSharp/Processing/ColorMatrix/Sepia.cs diff --git a/src/ImageSharp.Processing/Convolution/BoxBlur.cs b/src/ImageSharp/Processing/Convolution/BoxBlur.cs similarity index 100% rename from src/ImageSharp.Processing/Convolution/BoxBlur.cs rename to src/ImageSharp/Processing/Convolution/BoxBlur.cs diff --git a/src/ImageSharp.Processing/Convolution/DetectEdges.cs b/src/ImageSharp/Processing/Convolution/DetectEdges.cs similarity index 100% rename from src/ImageSharp.Processing/Convolution/DetectEdges.cs rename to src/ImageSharp/Processing/Convolution/DetectEdges.cs diff --git a/src/ImageSharp.Processing/Convolution/GaussianBlur.cs b/src/ImageSharp/Processing/Convolution/GaussianBlur.cs similarity index 100% rename from src/ImageSharp.Processing/Convolution/GaussianBlur.cs rename to src/ImageSharp/Processing/Convolution/GaussianBlur.cs diff --git a/src/ImageSharp.Processing/Convolution/GaussianSharpen.cs b/src/ImageSharp/Processing/Convolution/GaussianSharpen.cs similarity index 100% rename from src/ImageSharp.Processing/Convolution/GaussianSharpen.cs rename to src/ImageSharp/Processing/Convolution/GaussianSharpen.cs diff --git a/src/ImageSharp.Processing/Convolution/Options/EdgeDetection.cs b/src/ImageSharp/Processing/Convolution/Options/EdgeDetection.cs similarity index 100% rename from src/ImageSharp.Processing/Convolution/Options/EdgeDetection.cs rename to src/ImageSharp/Processing/Convolution/Options/EdgeDetection.cs diff --git a/src/ImageSharp.Processing/Effects/Alpha.cs b/src/ImageSharp/Processing/Effects/Alpha.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/Alpha.cs rename to src/ImageSharp/Processing/Effects/Alpha.cs diff --git a/src/ImageSharp.Processing/Effects/BackgroundColor.cs b/src/ImageSharp/Processing/Effects/BackgroundColor.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/BackgroundColor.cs rename to src/ImageSharp/Processing/Effects/BackgroundColor.cs diff --git a/src/ImageSharp.Processing/Effects/Brightness.cs b/src/ImageSharp/Processing/Effects/Brightness.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/Brightness.cs rename to src/ImageSharp/Processing/Effects/Brightness.cs diff --git a/src/ImageSharp.Processing/Effects/Contrast.cs b/src/ImageSharp/Processing/Effects/Contrast.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/Contrast.cs rename to src/ImageSharp/Processing/Effects/Contrast.cs diff --git a/src/ImageSharp.Processing/Effects/Invert.cs b/src/ImageSharp/Processing/Effects/Invert.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/Invert.cs rename to src/ImageSharp/Processing/Effects/Invert.cs diff --git a/src/ImageSharp.Processing/Effects/OilPainting.cs b/src/ImageSharp/Processing/Effects/OilPainting.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/OilPainting.cs rename to src/ImageSharp/Processing/Effects/OilPainting.cs diff --git a/src/ImageSharp.Processing/Effects/Pixelate.cs b/src/ImageSharp/Processing/Effects/Pixelate.cs similarity index 100% rename from src/ImageSharp.Processing/Effects/Pixelate.cs rename to src/ImageSharp/Processing/Effects/Pixelate.cs diff --git a/src/ImageSharp.Processing/Overlays/Glow.cs b/src/ImageSharp/Processing/Overlays/Glow.cs similarity index 100% rename from src/ImageSharp.Processing/Overlays/Glow.cs rename to src/ImageSharp/Processing/Overlays/Glow.cs diff --git a/src/ImageSharp.Processing/Overlays/Vignette.cs b/src/ImageSharp/Processing/Overlays/Vignette.cs similarity index 100% rename from src/ImageSharp.Processing/Overlays/Vignette.cs rename to src/ImageSharp/Processing/Overlays/Vignette.cs diff --git a/src/ImageSharp.Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Binarization/BinaryThresholdProcessor.cs rename to src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs rename to src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Binarization/OrderedDitherProcessor.cs rename to src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/BlackWhiteProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatomalyProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/AchromatopsiaProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranomalyProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/DeuteranopiaProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanomalyProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/ProtanopiaProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/README.md b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/README.md similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/README.md rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/README.md diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanomalyProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorBlindness/TritanopiaProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/ColorMatrixFilter.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixFilter.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/ColorMatrixFilter.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixFilter.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt601Processor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/GrayscaleBt709Processor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/HueProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/HueProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/IColorMatrixFilter.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/IColorMatrixFilter.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/IColorMatrixFilter.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/IColorMatrixFilter.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/KodachromeProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/KodachromeProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/KodachromeProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/KodachromeProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/LomographProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/PolaroidProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/SaturationProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/SaturationProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/SaturationProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/ColorMatrix/SepiaProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/SepiaProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/ColorMatrix/SepiaProcessor.cs rename to src/ImageSharp/Processing/Processors/ColorMatrix/SepiaProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/BoxBlurProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/IEdgeDetectorProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/GaussianBlurProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Convolution/GaussianSharpenProcessor.cs rename to src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/AlphaProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/AlphaProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/BackgroundColorProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/BrightnessProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/ContrastProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/InvertProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/OilPaintingProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Effects/PixelateProcessor.cs rename to src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Overlays/GlowProcessor.cs rename to src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Overlays/VignetteProcessor.cs rename to src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/CompandingResizeProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/CompandingResizeProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/CropProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/EntropyCropProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/FlipProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/Matrix3x2Processor.cs b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/Matrix3x2Processor.cs rename to src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/ResamplingWeightedProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/ResizeProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/RotateProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs diff --git a/src/ImageSharp.Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs similarity index 100% rename from src/ImageSharp.Processing/Processors/Transforms/SkewProcessor.cs rename to src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs diff --git a/src/ImageSharp.Processing/Transforms/AutoOrient.cs b/src/ImageSharp/Processing/Transforms/AutoOrient.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/AutoOrient.cs rename to src/ImageSharp/Processing/Transforms/AutoOrient.cs diff --git a/src/ImageSharp.Processing/Transforms/Crop.cs b/src/ImageSharp/Processing/Transforms/Crop.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Crop.cs rename to src/ImageSharp/Processing/Transforms/Crop.cs diff --git a/src/ImageSharp.Processing/Transforms/EntropyCrop.cs b/src/ImageSharp/Processing/Transforms/EntropyCrop.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/EntropyCrop.cs rename to src/ImageSharp/Processing/Transforms/EntropyCrop.cs diff --git a/src/ImageSharp.Processing/Transforms/Flip.cs b/src/ImageSharp/Processing/Transforms/Flip.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Flip.cs rename to src/ImageSharp/Processing/Transforms/Flip.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/AnchorPosition.cs b/src/ImageSharp/Processing/Transforms/Options/AnchorPosition.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/AnchorPosition.cs rename to src/ImageSharp/Processing/Transforms/Options/AnchorPosition.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/FlipType.cs b/src/ImageSharp/Processing/Transforms/Options/FlipType.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/FlipType.cs rename to src/ImageSharp/Processing/Transforms/Options/FlipType.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/Orientation.cs b/src/ImageSharp/Processing/Transforms/Options/Orientation.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/Orientation.cs rename to src/ImageSharp/Processing/Transforms/Options/Orientation.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/ResizeHelper.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/ResizeHelper.cs rename to src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/ResizeMode.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeMode.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/ResizeMode.cs rename to src/ImageSharp/Processing/Transforms/Options/ResizeMode.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/ResizeOptions.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/ResizeOptions.cs rename to src/ImageSharp/Processing/Transforms/Options/ResizeOptions.cs diff --git a/src/ImageSharp.Processing/Transforms/Options/RotateType.cs b/src/ImageSharp/Processing/Transforms/Options/RotateType.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Options/RotateType.cs rename to src/ImageSharp/Processing/Transforms/Options/RotateType.cs diff --git a/src/ImageSharp.Processing/Transforms/Pad.cs b/src/ImageSharp/Processing/Transforms/Pad.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Pad.cs rename to src/ImageSharp/Processing/Transforms/Pad.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/BicubicResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/BicubicResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/BicubicResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/BicubicResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/BoxResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/BoxResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/BoxResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/BoxResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/CatmullRomResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/CatmullRomResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/CatmullRomResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/CatmullRomResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/HermiteResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/HermiteResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/HermiteResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/HermiteResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/IResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/IResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/IResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/IResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/Lanczos2Resampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/Lanczos2Resampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/Lanczos3Resampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/Lanczos3Resampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/Lanczos5Resampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/Lanczos5Resampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/Lanczos8Resampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/Lanczos8Resampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/MitchellNetravaliResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/NearestNeighborResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/NearestNeighborResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/NearestNeighborResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/NearestNeighborResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/RobidouxResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/RobidouxResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/RobidouxResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/RobidouxResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/RobidouxSharpResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/RobidouxSharpResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/RobidouxSharpResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/RobidouxSharpResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/SplineResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/SplineResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/SplineResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/SplineResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/TriangleResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/TriangleResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/TriangleResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/TriangleResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resamplers/WelchResampler.cs b/src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resamplers/WelchResampler.cs rename to src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs diff --git a/src/ImageSharp.Processing/Transforms/Resize.cs b/src/ImageSharp/Processing/Transforms/Resize.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Resize.cs rename to src/ImageSharp/Processing/Transforms/Resize.cs diff --git a/src/ImageSharp.Processing/Transforms/Rotate.cs b/src/ImageSharp/Processing/Transforms/Rotate.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Rotate.cs rename to src/ImageSharp/Processing/Transforms/Rotate.cs diff --git a/src/ImageSharp.Processing/Transforms/RotateFlip.cs b/src/ImageSharp/Processing/Transforms/RotateFlip.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/RotateFlip.cs rename to src/ImageSharp/Processing/Transforms/RotateFlip.cs diff --git a/src/ImageSharp.Processing/Transforms/Skew.cs b/src/ImageSharp/Processing/Transforms/Skew.cs similarity index 100% rename from src/ImageSharp.Processing/Transforms/Skew.cs rename to src/ImageSharp/Processing/Transforms/Skew.cs diff --git a/src/ImageSharp/Properties/AssemblyInfo.cs b/src/ImageSharp/Properties/AssemblyInfo.cs index 407a17b85a..e791dff5a5 100644 --- a/src/ImageSharp/Properties/AssemblyInfo.cs +++ b/src/ImageSharp/Properties/AssemblyInfo.cs @@ -5,9 +5,4 @@ using System.Runtime.CompilerServices; // Ensure the other projects can see the internal helpers -[assembly: InternalsVisibleTo("ImageSharp.Drawing")] -[assembly: InternalsVisibleTo("ImageSharp.Formats.Bmp")] -[assembly: InternalsVisibleTo("ImageSharp.Formats.Gif")] -[assembly: InternalsVisibleTo("ImageSharp.Formats.Jpeg")] -[assembly: InternalsVisibleTo("ImageSharp.Formats.Png")] -[assembly: InternalsVisibleTo("ImageSharp.Processing")] \ No newline at end of file +[assembly: InternalsVisibleTo("ImageSharp.Drawing")] \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index b4bedf8274..b2070c0dee 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -12,11 +12,6 @@ - - - - - \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/project.json b/tests/ImageSharp.Benchmarks/project.json deleted file mode 100644 index 6a8be9f896..0000000000 --- a/tests/ImageSharp.Benchmarks/project.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "version": "1.0.0-*", - "description": "ImageSharp.Benchmarks Console Application", - "authors": [ "James.South" ], - "packOptions": { - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "emitEntryPoint": true, - "allowUnsafe": true - }, - "dependencies": { - "ImageSharp": { - "target": "project" - }, - "ImageSharp.Drawing": { - "target": "project" - }, - "ImageSharp.Drawing.Paths": { - "target": "project" - }, - "ImageSharp.Formats.Jpeg": { - "target": "project" - }, - "ImageSharp.Formats.Png": { - "target": "project" - }, - "ImageSharp.Formats.Bmp": { - "target": "project" - }, - "ImageSharp.Formats.Gif": { - "target": "project" - }, - "ImageSharp.Processing": { - "target": "project" - } - }, - "commands": { - "ImageSharp.Benchmarks": "ImageSharp.Benchmarks" - }, - "frameworks": { - "net46": { - "dependencies": { - "BenchmarkDotNet.Diagnostics.Windows": "0.10.1" - }, - "frameworkAssemblies": { - "System.Drawing": "" - } - }, - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.1.0-*" - }, - "BenchmarkDotNet": "0.10.2", - "CoreCompat.System.Drawing": "1.0.0-beta006", - "runtime.linux-x64.CoreCompat.System.Drawing": "1.0.0-beta009", - "System.Reflection": "4.3.0" - } - } - } -} diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 1dfe948ee5..418f70cc7b 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,28 +1,18 @@  - netcoreapp1.0;net45 - win7-x64 + netcoreapp1.0 True - - - + + + + - - - - - - - - - - diff --git a/tests/ImageSharp.Tests/project.json b/tests/ImageSharp.Tests/project.json deleted file mode 100644 index 7c67a5c706..0000000000 --- a/tests/ImageSharp.Tests/project.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "version": "1.0.0-*", - "description": "ImageSharp.Tests Class Library", - "authors": [ "James Jackson-South and contributors" ], - "packOptions": { - "projectUrl": "https://github.com/JimBobSquarePants/ImageSharp", - "licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0", - "tags": [ - "Image Resize Crop Gif Jpg Jpeg Bitmap Png Core" - ] - }, - "buildOptions": { - "allowUnsafe": true - }, - "configurations": { - "Release": { - "buildOptions": { - "warningsAsErrors": true - } - } - }, - "dependencies": { - "ImageSharp": { - "target": "project" - }, - "xunit": "2.2.0-*", - "dotnet-test-xunit": "2.2.0-*", - "ImageSharp.Drawing": { - "target": "project" - }, - "ImageSharp.Drawing.Paths": { - "target": "project" - }, - "ImageSharp.Drawing.Text": { - "target": "project" - }, - "ImageSharp.Formats.Png": { - "target": "project" - }, - "ImageSharp.Formats.Jpeg": { - "target": "project" - }, - "ImageSharp.Formats.Bmp": { - "target": "project" - }, - "ImageSharp.Formats.Gif": { - "target": "project" - }, - "ImageSharp.Processing": { - "target": "project" - }, - //alpha supports netstandard - "Moq": "4.6.38-alpha" - }, - "frameworks": { - "netcoreapp1.1": { - "dependencies": { - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0-*" - }, - "Microsoft.CodeCoverage": "1.0.2" - } - }, - "net451": { - "dependencies": { - } - } - }, - "testRunner": "xunit" -} \ No newline at end of file From b37160606efe24899425f78e6614aa06d9ce08b4 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 9 Mar 2017 19:14:52 +0000 Subject: [PATCH 64/85] fix build script proj --- build/build.csproj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/build.csproj b/build/build.csproj index 56b6f82bf4..c7fd9c8f35 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -1,6 +1,6 @@  - netcoreapp1.0 + netcoreapp1.1 portable true build @@ -9,6 +9,7 @@ ..\ImageSharp.ruleset + From 97f1c38711abcad4c6942eac2606c75ba3fd46b5 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 9 Mar 2017 20:16:01 +0000 Subject: [PATCH 65/85] produce full pdb for codecov --- ImageSharp.sln | 19 ------------------- .../ImageSharp.Drawing.csproj | 1 + src/ImageSharp/ImageSharp.csproj | 1 + tests/CodeCoverage/CodeCoverage.cmd | 8 +++----- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 3 ++- 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/ImageSharp.sln b/ImageSharp.sln index 485fca7fbb..320c01e9ca 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -39,12 +39,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Drawing", "src\I EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "build", "build\build.csproj", "{575A5002-DD9F-4335-AA47-1DD87FA13645}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" - ProjectSection(ProjectDependencies) = postProject - {2E33181E-6E28-4662-A801-E2E7DC206029} = {2E33181E-6E28-4662-A801-E2E7DC206029} - {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests", "tests\ImageSharp.Tests\ImageSharp.Tests.csproj", "{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}" @@ -95,18 +89,6 @@ Global {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x64.Build.0 = Release|Any CPU {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x86.ActiveCfg = Release|Any CPU {575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x86.Build.0 = Release|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.ActiveCfg = Debug|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.Build.0 = Debug|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x86.ActiveCfg = Debug|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x86.Build.0 = Debug|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.Build.0 = Release|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.ActiveCfg = Release|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.Build.0 = Release|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.ActiveCfg = Release|Any CPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.Build.0 = Release|Any CPU {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -140,7 +122,6 @@ Global {2AA31A1F-142C-43F4-8687-09ABCA4B3A26} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {2E33181E-6E28-4662-A801-E2E7DC206029} = {815C0625-CD3D-440F-9F80-2D83856AB7AE} {575A5002-DD9F-4335-AA47-1DD87FA13645} = {E919DF0B-2607-4462-8FC0-5C98FE50F8C9} - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} EndGlobalSection diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index de759859b1..4b8a11b4d5 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -24,6 +24,7 @@ false false false + full diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index c2e6ee3c20..94c6c82d2c 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -24,6 +24,7 @@ false false false + full diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index 99c218f02a..ba108d2479 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -4,15 +4,13 @@ cd tests\CodeCoverage nuget restore packages.config -PackagesDirectory . -cd ..\ImageSharp.Tests - -dotnet restore - cd .. cd .. +dotnet restore ImageSharp.sln +dotnet build ImageSharp.sln --no-incremental -c release /p:codecov=true rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj -c Release -f net45" -threshold:10 -register:user -filter:"+[ImageSharp*]*" -excludebyattribute:*.ExcludeFromCodeCoverage* -hideskipped:All -returntargetcode -output:.\ImageSharp.Coverage.xml +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj --no-build -c release" -searchdirs:"tests\ImageSharp\bin\Release\netcoreapp1.1" -register:user -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -oldStyle -filter:"+[ImageSharp*]*" if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 418f70cc7b..249d78bdea 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,7 +1,8 @@  - netcoreapp1.0 + netcoreapp1.1 True + full From 2ad4fefa88869db20262978508cce4606d3040c1 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 9 Mar 2017 22:25:42 +0000 Subject: [PATCH 66/85] add stylecop back --- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 4 +++- .../TestUtilities/Tests/TestImageProviderTests.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 249d78bdea..c6f916e00c 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -1,8 +1,10 @@  - netcoreapp1.1 + netcoreapp1.1 True full + portable + True diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 09c81b7610..1acb9e1492 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -154,7 +154,7 @@ namespace ImageSharp.Tests TestImageProvider.Blank(10, 20), TestImageProvider.Blank( 10, - 20) + 20), }; [Theory] From eb4e79740c2e1a07fd96d8bb857ce1d8273dddd0 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 9 Mar 2017 22:53:17 +0000 Subject: [PATCH 67/85] fix stylecop --- .editorconfig | 13 +++++++++++++ ImageSharp.ruleset | 5 +++-- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 8 ++++++++ src/ImageSharp/ImageSharp.csproj | 8 ++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index f39b267256..c3fb970c3b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,16 @@ +# top-most EditorConfig file +root = true + [*.cs] indent_style = space indent_size = 4 +csharp_style_var_for_built_in_types = false:warning +csharp_style_var_elsewhere = false:warning +csharp_style_var_when_type_is_apparent = false:warning +end_of_line = crlf +dotnet_sort_system_directives_first = true +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +dotnet_style_predefined_type_for_member_access = true:warning +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_property = true:warning \ No newline at end of file diff --git a/ImageSharp.ruleset b/ImageSharp.ruleset index 2daf6243ae..fb344621f9 100644 --- a/ImageSharp.ruleset +++ b/ImageSharp.ruleset @@ -1,7 +1,8 @@  - + + - + \ No newline at end of file diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 4b8a11b4d5..72d5aa8905 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -25,14 +25,22 @@ false false full + portable + True + + + + + All + diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 94c6c82d2c..95cf56790d 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -25,11 +25,19 @@ false false full + portable + True + + + + + All + From 9adfa26ba4edc4e08b09714ea75db03fb64c4de1 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Thu, 9 Mar 2017 23:15:23 +0000 Subject: [PATCH 68/85] try local stylecop.json --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 2 +- src/ImageSharp/ImageSharp.csproj | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 72d5aa8905..ec4cb1e9b3 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -32,7 +32,7 @@ - + diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 95cf56790d..2dfb283ef9 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -32,7 +32,9 @@ - + + + From 12882c030a351d606c87fde98c0dac009960fb5d Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 10 Mar 2017 08:18:23 +0000 Subject: [PATCH 69/85] disable header rules as stylecop.json not working at command line --- .vscode/tasks.json | 4 ++-- ImageSharp.ruleset | 3 +++ src/ImageSharp/ImageSharp.csproj | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 128265ff6f..3edf90c5b6 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,7 +8,7 @@ "tasks": [ { "taskName": "build", - "args": [ "src/*/project.json", "-f", "netstandard1.1" ], + "args": [ "ImageSharp.sln" ], "isBuildCommand": true, "showOutput": "always", "problemMatcher": "$msCompile" @@ -22,7 +22,7 @@ }, { "taskName": "test", - "args": ["tests/ImageSharp.Tests/project.json", "-f", "netcoreapp1.1"], + "args": ["tests/ImageSharp.Tests/ImageSharp.Tests.csproj", "-f", "netcoreapp1.1"], "isTestCommand": true, "showOutput": "always", "problemMatcher": "$msCompile" diff --git a/ImageSharp.ruleset b/ImageSharp.ruleset index fb344621f9..3f10206fca 100644 --- a/ImageSharp.ruleset +++ b/ImageSharp.ruleset @@ -4,5 +4,8 @@ + + + \ No newline at end of file diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 2dfb283ef9..db37a60366 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -27,6 +27,7 @@ full portable True + IOperation @@ -34,7 +35,7 @@ - + From 52ab6949e3e191282ae9dad86502f56e103afdad Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 10 Mar 2017 08:22:32 +0000 Subject: [PATCH 70/85] vscode run tests in release mode for speed --- .vscode/tasks.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 3edf90c5b6..a1a55a389a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -22,7 +22,7 @@ }, { "taskName": "test", - "args": ["tests/ImageSharp.Tests/ImageSharp.Tests.csproj", "-f", "netcoreapp1.1"], + "args": ["tests/ImageSharp.Tests/ImageSharp.Tests.csproj", "-c", "release", "-f", "netcoreapp1.1"], "isTestCommand": true, "showOutput": "always", "problemMatcher": "$msCompile" From 5608f7a764e32433acb7ff611eddab8cc59161c0 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 10 Mar 2017 13:46:19 +0000 Subject: [PATCH 71/85] tweak file location --- ImageSharp.ruleset | 4 ++-- build/build.csproj | 2 +- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 2 +- src/ImageSharp/ImageSharp.csproj | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ImageSharp.ruleset b/ImageSharp.ruleset index 3f10206fca..24a9370494 100644 --- a/ImageSharp.ruleset +++ b/ImageSharp.ruleset @@ -5,7 +5,7 @@ - - + \ No newline at end of file diff --git a/build/build.csproj b/build/build.csproj index c7fd9c8f35..dc431284ed 100644 --- a/build/build.csproj +++ b/build/build.csproj @@ -9,7 +9,7 @@ ..\ImageSharp.ruleset - + diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index ec4cb1e9b3..72d5aa8905 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -32,7 +32,7 @@ - + diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index db37a60366..7be788d7e9 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -35,7 +35,7 @@ - + From 0946956c92c41e72ffffd2b86c7036015d05d3fe Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 10 Mar 2017 20:30:16 +0000 Subject: [PATCH 72/85] disable header style cop settings dotnet build failing to see stylecop.json --- ImageSharp.ruleset | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImageSharp.ruleset b/ImageSharp.ruleset index 24a9370494..3f10206fca 100644 --- a/ImageSharp.ruleset +++ b/ImageSharp.ruleset @@ -5,7 +5,7 @@ - + + \ No newline at end of file From e8359d9eb9d37e58941ce9f046e19e2e176a9a01 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 11 Mar 2017 14:26:25 +0000 Subject: [PATCH 73/85] allow codecov to finish --- tests/CodeCoverage/CodeCoverage.cmd | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/CodeCoverage/CodeCoverage.cmd b/tests/CodeCoverage/CodeCoverage.cmd index ba108d2479..1e16d5c14a 100644 --- a/tests/CodeCoverage/CodeCoverage.cmd +++ b/tests/CodeCoverage/CodeCoverage.cmd @@ -1,5 +1,6 @@ @echo off + cd tests\CodeCoverage nuget restore packages.config -PackagesDirectory . @@ -7,10 +8,10 @@ nuget restore packages.config -PackagesDirectory . cd .. cd .. -dotnet restore ImageSharp.sln -dotnet build ImageSharp.sln --no-incremental -c release /p:codecov=true +dotnet restore ImageSharp.sln +dotnet build ImageSharp.sln --no-incremental -c release /p:codecov=true rem The -threshold options prevents this taking ages... -tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj --no-build -c release" -searchdirs:"tests\ImageSharp\bin\Release\netcoreapp1.1" -register:user -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -oldStyle -filter:"+[ImageSharp*]*" +tests\CodeCoverage\OpenCover.4.6.519\tools\OpenCover.Console.exe -target:"dotnet.exe" -targetargs:"test tests\ImageSharp.Tests\ImageSharp.Tests.csproj --no-build -c release /p:codecov=true" -register:user -threshold:10 -oldStyle -safemode:off -output:.\ImageSharp.Coverage.xml -hideskipped:All -returntargetcode -filter:"+[ImageSharp*]*" if %errorlevel% neq 0 exit /b %errorlevel% From d970b73253869e08328f454de25b19a6974d06ba Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 11 Mar 2017 15:03:09 +0000 Subject: [PATCH 74/85] fix travis --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 172079df24..da8f3809ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,8 @@ matrix: - os: linux # Ubuntu 14.04 dist: trusty sudo: required - dotnet: 1.0.0-preview2-003121 - mono: latest + dotnet: 1.0.1 +# mono: latest # - os: osx # OSX 10.11 # osx_image: xcode7.3.1 # dotnet: 1.0.0-preview2-003121 @@ -20,8 +20,8 @@ branches: script: - dotnet restore - - dotnet build -c Release src/*/project.json - - dotnet test tests/ImageSharp.Tests/project.json -c Release -f "netcoreapp1.1" + - dotnet build -c Release ImageSharp.sln + - dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj --no-build -c Release -f "netcoreapp1.1" env: global: From 3cdca134eb4316355696e3c115a2c7e2069b42cd Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 11 Mar 2017 15:17:14 +0000 Subject: [PATCH 75/85] just run tests on travis Running tests will cause the tests + its dependencies to be rebuild thus this tests building & testing the core projects --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index da8f3809ed..507fd4b9df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,8 +20,7 @@ branches: script: - dotnet restore - - dotnet build -c Release ImageSharp.sln - - dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj --no-build -c Release -f "netcoreapp1.1" + - dotnet test tests/ImageSharp.Tests/ImageSharp.Tests.csproj -c Release -f "netcoreapp1.1" env: global: From e095566fabdc59814810328d609b74905c4a4aee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 12 Mar 2017 09:22:51 +1100 Subject: [PATCH 76/85] Fix stylecop.json reference in project --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 2 -- src/ImageSharp/ImageSharp.csproj | 6 +----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 72d5aa8905..480cdbddd9 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -30,8 +30,6 @@ - - diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 7be788d7e9..8ce04bae71 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -31,11 +31,7 @@ - - - - - + From a27258fef96e66e1c9f198cf70503868b403dbbd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 12 Mar 2017 09:35:38 +1100 Subject: [PATCH 77/85] Remove unneeded package references from drawing. --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 480cdbddd9..52f120596f 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -41,10 +41,6 @@ - - - - ..\..\ImageSharp.ruleset From b67f7265d0d348e41c803fe6bec1df5b80e3821a Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 12 Mar 2017 10:18:18 +0000 Subject: [PATCH 78/85] update sandbox --- .travis.yml | 2 +- ImageSharp.sln | 15 + .../ImageSharp.Sandbox46.csproj | 405 +----------------- tests/ImageSharp.Sandbox46/packages.config | 61 --- 4 files changed, 29 insertions(+), 454 deletions(-) delete mode 100644 tests/ImageSharp.Sandbox46/packages.config diff --git a/.travis.yml b/.travis.yml index 507fd4b9df..af8d4ad9de 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ matrix: dist: trusty sudo: required dotnet: 1.0.1 -# mono: latest + mono: latest # - os: osx # OSX 10.11 # osx_image: xcode7.3.1 # dotnet: 1.0.0-preview2-003121 diff --git a/ImageSharp.sln b/ImageSharp.sln index 320c01e9ca..9c729493b2 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -43,6 +43,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Tests", "tests\I EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Benchmarks", "tests\ImageSharp.Benchmarks\ImageSharp.Benchmarks.csproj", "{2BF743D8-2A06-412D-96D7-F448F00C5EA5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{96188137-5FA6-4924-AB6E-4EFF79C6E0BB}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -113,6 +115,18 @@ Global {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.Build.0 = Release|Any CPU {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.ActiveCfg = Release|Any CPU {2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x86.Build.0 = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.ActiveCfg = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x64.Build.0 = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x86.ActiveCfg = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Debug|x86.Build.0 = Debug|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|Any CPU.Build.0 = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.ActiveCfg = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x64.Build.0 = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.ActiveCfg = Release|Any CPU + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -124,5 +138,6 @@ Global {575A5002-DD9F-4335-AA47-1DD87FA13645} = {E919DF0B-2607-4462-8FC0-5C98FE50F8C9} {EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} {2BF743D8-2A06-412D-96D7-F448F00C5EA5} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} + {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} = {56801022-D71A-4FBE-BC5B-CBA08E2284EC} EndGlobalSection EndGlobal diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index 8837f8733a..e6a2e162fc 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -1,403 +1,24 @@ - - - - + - Debug - AnyCPU - {96188137-5FA6-4924-AB6E-4EFF79C6E0BB} Exe - Properties - ImageSharp - ImageSharp.Sandbox46 - v4.6.1 - 512 - - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - false - - - pdbonly - true - bin\Release\ - TRACE;BENCHMARKING - prompt - 4 - true + net461 + win7-x64 + True false - - ImageSharp.Sandbox46.Program - - - - ..\..\packages\BenchmarkDotNet.0.10.2\lib\net45\BenchmarkDotNet.dll - True - - - ..\..\packages\BenchmarkDotNet.Core.0.10.2\lib\net45\BenchmarkDotNet.Core.dll - True - - - ..\..\packages\BenchmarkDotNet.Diagnostics.Windows.0.10.2\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll - True - - - ..\..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.10.2\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll - True - - - ..\..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll - True - - - ..\..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll - True - - - ..\..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll - True - - - - ..\..\packages\System.AppContext.4.1.0\lib\net46\System.AppContext.dll - True - - - ..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll - True - - - - ..\..\packages\System.Console.4.0.0\lib\net46\System.Console.dll - True - - - - ..\..\packages\System.Diagnostics.FileVersionInfo.4.0.0\lib\net46\System.Diagnostics.FileVersionInfo.dll - True - - - ..\..\packages\System.Diagnostics.StackTrace.4.0.1\lib\net46\System.Diagnostics.StackTrace.dll - True - - - ..\..\packages\System.IO.FileSystem.4.0.1\lib\net46\System.IO.FileSystem.dll - True - - - ..\..\packages\System.IO.FileSystem.Primitives.4.0.1\lib\net46\System.IO.FileSystem.Primitives.dll - True - - - - - ..\..\packages\System.Numerics.Vectors.4.1.1\lib\net46\System.Numerics.Vectors.dll - True - - - ..\..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll - True - - - ..\..\packages\System.Runtime.CompilerServices.Unsafe.4.3.0\lib\netstandard1.0\System.Runtime.CompilerServices.Unsafe.dll - True - - - ..\..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net461\System.Security.Cryptography.Algorithms.dll - True - - - ..\..\packages\System.Security.Cryptography.Encoding.4.0.0\lib\net46\System.Security.Cryptography.Encoding.dll - True - - - ..\..\packages\System.Security.Cryptography.Primitives.4.0.0\lib\net46\System.Security.Cryptography.Primitives.dll - True - - - ..\..\packages\System.Security.Cryptography.X509Certificates.4.1.0\lib\net461\System.Security.Cryptography.X509Certificates.dll - True - - - ..\..\packages\System.Text.Encoding.CodePages.4.0.1\lib\net46\System.Text.Encoding.CodePages.dll - True - - - ..\..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll - True - - - ..\..\packages\System.Threading.Thread.4.0.0\lib\net46\System.Threading.Thread.dll - True - - - - - - - - - ..\..\packages\System.Xml.XmlDocument.4.0.1\lib\net46\System.Xml.XmlDocument.dll - True - - - ..\..\packages\System.Xml.XPath.4.0.1\lib\net46\System.Xml.XPath.dll - True - - - ..\..\packages\System.Xml.XPath.XDocument.4.0.1\lib\net46\System.Xml.XPath.XDocument.dll - True - - - ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll - True - - - ..\..\packages\xunit.assert.2.2.0-beta4-build3444\lib\netstandard1.0\xunit.assert.dll - True - - - ..\..\packages\xunit.extensibility.core.2.2.0-beta4-build3444\lib\net45\xunit.core.dll - True - - - ..\..\packages\xunit.extensibility.execution.2.2.0-beta4-build3444\lib\net45\xunit.execution.desktop.dll - True - - - - - ..\..\src\ImageSharp\bin\$(Configuration)\net461\ImageSharp.dll - - - ..\..\src\ImageSharp.Drawing\bin\$(Configuration)\net461\ImageSharp.Drawing.dll - - - ..\..\src\ImageSharp.Drawing.Paths\bin\$(Configuration)\net461\ImageSharp.Drawing.Paths.dll - - - ..\..\src\ImageSharp.Drawing.Paths\bin\$(Configuration)\net461\SixLabors.Shapes.dll - - - ..\..\src\ImageSharp.Formats.Bmp\bin\$(Configuration)\net461\ImageSharp.Formats.Bmp.dll - - - ..\..\src\ImageSharp.Formats.Gif\bin\$(Configuration)\net461\ImageSharp.Formats.Gif.dll - - - ..\..\src\ImageSharp.Formats.Jpeg\bin\$(Configuration)\net461\ImageSharp.Formats.Jpeg.dll - - - ..\..\src\ImageSharp.Formats.Png\bin\$(Configuration)\net461\ImageSharp.Formats.Png.dll - - - ..\..\src\ImageSharp.Processing\bin\$(Configuration)\net461\ImageSharp.Processing.dll - - - - - Tests\Colors\BulkPixelOperationsTests.cs - - - Tests\Common\BufferPointerTests.cs - - - Tests\Common\PinnedBufferTests.cs - - - Tests\Drawing\PolygonTests.cs - - - Tests\FileTestBase.cs - - - Tests\Formats\Jpg\BadEofJpegTests.cs - - - Tests\Formats\Jpg\Block8x8FTests.cs - - - Tests\Formats\Jpg\JpegDecoderTests.cs - - - Tests\Formats\Jpg\JpegEncoderTests.cs - - - Tests\Formats\Jpg\JpegProfilingBenchmarks.cs - - - Tests\Formats\Jpg\JpegUtilityTestFixture.cs - - - Tests\Formats\Jpg\JpegUtilsTests.cs - - - Tests\Formats\Jpg\ReferenceImplementations.cs - - - Tests\Formats\Jpg\ReferenceImplementationsTests.cs - - - Tests\Formats\Jpg\YCbCrImageTests.cs - - - Tests\MetaData\ImagePropertyTests.cs - - - Tests\Image\ImageTests.cs - - - Tests\Image\PixelAccessorTests.cs - - - Tests\Processors\Filters\ResizeTests.cs - - - Tests\TestBase.cs - - - Tests\TestFile.cs - - - Tests\TestImages.cs - - - Tests\TestUtilities\ApproximateFloatComparer.cs - - - Tests\TestUtilities\Attributes\ImageDataAttributeBase.cs - - - Tests\TestUtilities\Attributes\WithBlankImageAttribute.cs - - - Tests\TestUtilities\Attributes\WithFileAttribute.cs - - - Tests\TestUtilities\Attributes\WithFileCollectionAttribute.cs - - - Tests\TestUtilities\Attributes\WithMemberFactoryAttribute.cs - - - Tests\TestUtilities\Attributes\WithSolidFilledImagesAttribute.cs - - - Tests\TestUtilities\Factories\GenericFactory.cs - - - Tests\TestUtilities\Factories\ImageFactory.cs - - - Tests\TestUtilities\ImageProviders\BlankProvider.cs - - - Tests\TestUtilities\ImageProviders\FileProvider.cs - - - Tests\TestUtilities\ImageProviders\LambdaProvider.cs - - - Tests\TestUtilities\ImageProviders\SolidProvider.cs - - - Tests\TestUtilities\ImageProviders\TestImageProvider.cs - - - Tests\TestUtilities\ImagingTestCaseUtility.cs - - - Tests\TestUtilities\MeasureFixture.cs - - - Tests\TestUtilities\PixelTypes.cs - - - Tests\TestUtilities\Tests\TestImageProviderTests.cs - - - Tests\TestUtilities\Tests\TestUtilityExtensionsTests.cs - - - Tests\TestUtilities\TestUtilityExtensions.cs - - - - - - - - - - - - - + + - - + + + + - - {2e33181e-6e28-4662-a801-e2e7dc206029} - ImageSharp.Drawing - - - {c77661b9-f793-422e-8e27-ac60ecc5f215} - ImageSharp.Formats.Bmp - - - {27ad4b5f-ecc4-4c63-9ecb-04ec772fdb6f} - ImageSharp.Formats.Gif - - - {7213767c-0003-41ca-ab18-0223cfa7ce4b} - ImageSharp.Formats.Jpeg - - - {556abdcf-ed93-4327-be98-f6815f78b9b8} - ImageSharp.Formats.Png - - - {a623cfe9-9d2b-4528-ad1f-2e834b061134} - ImageSharp.Processing - - - {2aa31a1f-142c-43f4-8687-09abca4b3a26} - ImageSharp - - - {2bf743d8-2a06-412d-96d7-f448f00c5ea5} - ImageSharp.Benchmarks - + + + - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/packages.config b/tests/ImageSharp.Sandbox46/packages.config deleted file mode 100644 index 426f5f1b52..0000000000 --- a/tests/ImageSharp.Sandbox46/packages.config +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 3eda81fb0f258a2e2b80df7169a8517e88f7fd52 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 12 Mar 2017 23:50:26 +1100 Subject: [PATCH 79/85] Move all drawing code into drawing project --- .../Drawing => ImageSharp.Drawing}/Brushes/Brushes.cs | 0 .../Drawing => ImageSharp.Drawing}/Brushes/Brushes{TColor}.cs | 0 .../Drawing => ImageSharp.Drawing}/Brushes/IBrush.cs | 0 .../Drawing => ImageSharp.Drawing}/Brushes/ImageBrush.cs | 0 .../Brushes/ImageBrush{TColor}.cs | 0 .../Drawing => ImageSharp.Drawing}/Brushes/PatternBrush.cs | 0 .../Brushes/PatternBrush{TColor}.cs | 0 .../Brushes/Processors/BrushApplicator.cs | 0 .../Drawing => ImageSharp.Drawing}/Brushes/RecolorBrush.cs | 0 .../Brushes/RecolorBrush{TColor}.cs | 0 .../Drawing => ImageSharp.Drawing}/Brushes/SolidBrush.cs | 0 .../Brushes/SolidBrush{TColor}.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/DrawImage.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/DrawPath.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/Drawable.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/FillRegion.cs | 0 .../Drawing => ImageSharp.Drawing}/GraphicsOptions.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/IPen.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Pen.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Pens.cs | 0 .../Drawing => ImageSharp.Drawing}/Pens/Pens{TColor}.cs | 0 .../Drawing => ImageSharp.Drawing}/Pens/Pen{TColor}.cs | 0 .../Pens/Processors/ColoredPointInfo.cs | 0 .../Pens/Processors/PenApplicator.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/PointInfo.cs | 0 .../Processors/DrawImageProcessor.cs | 0 .../Processors/DrawPathProcessor.cs | 0 .../Drawing => ImageSharp.Drawing}/Processors/FillProcessor.cs | 0 .../Processors/FillRegionProcessor.cs | 0 src/{ImageSharp/Drawing => ImageSharp.Drawing}/Region.cs | 0 src/Shared/AssemblyInfo.Common.cs | 3 ++- 31 files changed, 2 insertions(+), 1 deletion(-) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/Brushes.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/Brushes{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/IBrush.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/ImageBrush.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/ImageBrush{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/PatternBrush.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/PatternBrush{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/Processors/BrushApplicator.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/RecolorBrush.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/RecolorBrush{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/SolidBrush.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Brushes/SolidBrush{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/DrawImage.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/DrawPath.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Drawable.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/FillRegion.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/GraphicsOptions.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/IPen.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Pen.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Pens.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Pens{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Pen{TColor}.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Processors/ColoredPointInfo.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Pens/Processors/PenApplicator.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/PointInfo.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Processors/DrawImageProcessor.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Processors/DrawPathProcessor.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Processors/FillProcessor.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Processors/FillRegionProcessor.cs (100%) rename src/{ImageSharp/Drawing => ImageSharp.Drawing}/Region.cs (100%) diff --git a/src/ImageSharp/Drawing/Brushes/Brushes.cs b/src/ImageSharp.Drawing/Brushes/Brushes.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/Brushes.cs rename to src/ImageSharp.Drawing/Brushes/Brushes.cs diff --git a/src/ImageSharp/Drawing/Brushes/Brushes{TColor}.cs b/src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/Brushes{TColor}.cs rename to src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs diff --git a/src/ImageSharp/Drawing/Brushes/IBrush.cs b/src/ImageSharp.Drawing/Brushes/IBrush.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/IBrush.cs rename to src/ImageSharp.Drawing/Brushes/IBrush.cs diff --git a/src/ImageSharp/Drawing/Brushes/ImageBrush.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/ImageBrush.cs rename to src/ImageSharp.Drawing/Brushes/ImageBrush.cs diff --git a/src/ImageSharp/Drawing/Brushes/ImageBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/ImageBrush{TColor}.cs rename to src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs diff --git a/src/ImageSharp/Drawing/Brushes/PatternBrush.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/PatternBrush.cs rename to src/ImageSharp.Drawing/Brushes/PatternBrush.cs diff --git a/src/ImageSharp/Drawing/Brushes/PatternBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/PatternBrush{TColor}.cs rename to src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs diff --git a/src/ImageSharp/Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/Processors/BrushApplicator.cs rename to src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs diff --git a/src/ImageSharp/Drawing/Brushes/RecolorBrush.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/RecolorBrush.cs rename to src/ImageSharp.Drawing/Brushes/RecolorBrush.cs diff --git a/src/ImageSharp/Drawing/Brushes/RecolorBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/RecolorBrush{TColor}.cs rename to src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs diff --git a/src/ImageSharp/Drawing/Brushes/SolidBrush.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/SolidBrush.cs rename to src/ImageSharp.Drawing/Brushes/SolidBrush.cs diff --git a/src/ImageSharp/Drawing/Brushes/SolidBrush{TColor}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Brushes/SolidBrush{TColor}.cs rename to src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs diff --git a/src/ImageSharp/Drawing/DrawImage.cs b/src/ImageSharp.Drawing/DrawImage.cs similarity index 100% rename from src/ImageSharp/Drawing/DrawImage.cs rename to src/ImageSharp.Drawing/DrawImage.cs diff --git a/src/ImageSharp/Drawing/DrawPath.cs b/src/ImageSharp.Drawing/DrawPath.cs similarity index 100% rename from src/ImageSharp/Drawing/DrawPath.cs rename to src/ImageSharp.Drawing/DrawPath.cs diff --git a/src/ImageSharp/Drawing/Drawable.cs b/src/ImageSharp.Drawing/Drawable.cs similarity index 100% rename from src/ImageSharp/Drawing/Drawable.cs rename to src/ImageSharp.Drawing/Drawable.cs diff --git a/src/ImageSharp/Drawing/FillRegion.cs b/src/ImageSharp.Drawing/FillRegion.cs similarity index 100% rename from src/ImageSharp/Drawing/FillRegion.cs rename to src/ImageSharp.Drawing/FillRegion.cs diff --git a/src/ImageSharp/Drawing/GraphicsOptions.cs b/src/ImageSharp.Drawing/GraphicsOptions.cs similarity index 100% rename from src/ImageSharp/Drawing/GraphicsOptions.cs rename to src/ImageSharp.Drawing/GraphicsOptions.cs diff --git a/src/ImageSharp/Drawing/Pens/IPen.cs b/src/ImageSharp.Drawing/Pens/IPen.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/IPen.cs rename to src/ImageSharp.Drawing/Pens/IPen.cs diff --git a/src/ImageSharp/Drawing/Pens/Pen.cs b/src/ImageSharp.Drawing/Pens/Pen.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/Pen.cs rename to src/ImageSharp.Drawing/Pens/Pen.cs diff --git a/src/ImageSharp/Drawing/Pens/Pens.cs b/src/ImageSharp.Drawing/Pens/Pens.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/Pens.cs rename to src/ImageSharp.Drawing/Pens/Pens.cs diff --git a/src/ImageSharp/Drawing/Pens/Pens{TColor}.cs b/src/ImageSharp.Drawing/Pens/Pens{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/Pens{TColor}.cs rename to src/ImageSharp.Drawing/Pens/Pens{TColor}.cs diff --git a/src/ImageSharp/Drawing/Pens/Pen{TColor}.cs b/src/ImageSharp.Drawing/Pens/Pen{TColor}.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/Pen{TColor}.cs rename to src/ImageSharp.Drawing/Pens/Pen{TColor}.cs diff --git a/src/ImageSharp/Drawing/Pens/Processors/ColoredPointInfo.cs b/src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/Processors/ColoredPointInfo.cs rename to src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs diff --git a/src/ImageSharp/Drawing/Pens/Processors/PenApplicator.cs b/src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs similarity index 100% rename from src/ImageSharp/Drawing/Pens/Processors/PenApplicator.cs rename to src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs diff --git a/src/ImageSharp/Drawing/PointInfo.cs b/src/ImageSharp.Drawing/PointInfo.cs similarity index 100% rename from src/ImageSharp/Drawing/PointInfo.cs rename to src/ImageSharp.Drawing/PointInfo.cs diff --git a/src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs similarity index 100% rename from src/ImageSharp/Drawing/Processors/DrawImageProcessor.cs rename to src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs diff --git a/src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs similarity index 100% rename from src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs rename to src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs diff --git a/src/ImageSharp/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs similarity index 100% rename from src/ImageSharp/Drawing/Processors/FillProcessor.cs rename to src/ImageSharp.Drawing/Processors/FillProcessor.cs diff --git a/src/ImageSharp/Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs similarity index 100% rename from src/ImageSharp/Drawing/Processors/FillRegionProcessor.cs rename to src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs diff --git a/src/ImageSharp/Drawing/Region.cs b/src/ImageSharp.Drawing/Region.cs similarity index 100% rename from src/ImageSharp/Drawing/Region.cs rename to src/ImageSharp.Drawing/Region.cs diff --git a/src/Shared/AssemblyInfo.Common.cs b/src/Shared/AssemblyInfo.Common.cs index 11f16769b1..252ef3eae0 100644 --- a/src/Shared/AssemblyInfo.Common.cs +++ b/src/Shared/AssemblyInfo.Common.cs @@ -33,7 +33,8 @@ using System.Runtime.CompilerServices; [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0.0")] -// Ensure the internals can be tested. +// Ensure the internals can be built and tested. +[assembly: InternalsVisibleTo("ImageSharp.Drawing")] [assembly: InternalsVisibleTo("ImageSharp.Benchmarks")] [assembly: InternalsVisibleTo("ImageSharp.Tests")] [assembly: InternalsVisibleTo("ImageSharp.Sandbox46")] \ No newline at end of file From f0f1941a0fad48679bc1afd0a12d8fa3be3f5d3a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 12 Mar 2017 23:52:35 +1100 Subject: [PATCH 80/85] Fix sandbox build --- tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj | 8 ++++++++ tests/ImageSharp.Sandbox46/Properties/AssemblyInfo.cs | 10 ---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj index e6a2e162fc..23a5c59a30 100644 --- a/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj +++ b/tests/ImageSharp.Sandbox46/ImageSharp.Sandbox46.csproj @@ -5,6 +5,11 @@ win7-x64 True false + ImageSharp.Sandbox46 + A cross-platform library for processing of image files written in C# + Copyright © James Jackson-South and contributors. + James Jackson-South and contributors + James Jackson-South @@ -21,4 +26,7 @@ + + + \ No newline at end of file diff --git a/tests/ImageSharp.Sandbox46/Properties/AssemblyInfo.cs b/tests/ImageSharp.Sandbox46/Properties/AssemblyInfo.cs index 51b205188d..a10fc12fe7 100644 --- a/tests/ImageSharp.Sandbox46/Properties/AssemblyInfo.cs +++ b/tests/ImageSharp.Sandbox46/Properties/AssemblyInfo.cs @@ -6,16 +6,6 @@ using System.Runtime.InteropServices; // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("ImageSharp.Sandbox46")] -[assembly: AssemblyDescription("A cross-platform library for processing of image files written in C#")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ImageSharp.Sandbox46")] -[assembly: AssemblyCopyright("Copyright © James Jackson-South and contributors.")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - - // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. From 42ec55aaf980e2af4545709ea5130111ac8b7dd3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 13 Mar 2017 00:09:14 +1100 Subject: [PATCH 81/85] Bump version and fix metadata --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 6 +++--- src/ImageSharp/ImageSharp.csproj | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 52f120596f..9224325ead 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -1,15 +1,15 @@  - A cross-platform library for the processing of image files; written in C# + An extension to ImageSharp that allows the drawing of images, paths, and text. ImageSharp.Drawing - 1.0.0-alpha2 + 1.0.0-alpha3 James Jackson-South and contributors netstandard1.1 true true ImageSharp.Drawing ImageSharp.Drawing - Image Resize Crop Gif Jpg Jpeg Bitmap Png Core + Image Draw Shape Path Font https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png https://github.com/JimBobSquarePants/ImageSharp http://www.apache.org/licenses/LICENSE-2.0 diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 8ce04bae71..de3e764734 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -2,7 +2,7 @@ A cross-platform library for the processing of image files; written in C# ImageSharp - 1.0.0-alpha2 + 1.0.0-alpha3 James Jackson-South and contributors netstandard1.3;netstandard1.1 true From 503a8435072b4b46473c7f46fc8abb3e1bb4d7c8 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 12 Mar 2017 14:11:46 +0000 Subject: [PATCH 82/85] update appveyor to user 2017 build image use the 2017 build image to save having to manually download the latest sdk as part of the build --- appveyor.yml | 19 +------------------ dotnet-latest.ps1 | 41 ----------------------------------------- 2 files changed, 1 insertion(+), 59 deletions(-) delete mode 100644 dotnet-latest.ps1 diff --git a/appveyor.yml b/appveyor.yml index 90f5d8e62a..c456a8d722 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,26 +1,9 @@ version: 1.0.0.{build} -os: Visual Studio 2015 +image: Visual Studio 2017 init: - ps: iex ((new-object net.webclient).DownloadString('https://gist.githubusercontent.com/PureKrome/0f79e25693d574807939/raw/8cf3160c9516ef1f4effc825c0a44acc918a0b5a/appveyor-build-info.ps')) -environment: - # Version Suffix - version_suffix: alpha - # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - # Disable sending usage data to Microsoft - DOTNET_CLI_TELEMETRY_OPTOUT: true - -install: -# Use the install script to grab the latest dotnet install -- ps: iex .\dotnet-latest.ps1 - -# Prepend newly installed dotnet cli to the PATH of this build (this cannot be -# done from inside the powershell script as it would require to restart -# the parent CMD process). -- "SET PATH=C:\\Program Files\\dotnet\\bin;%PATH%" - build_script: - cmd: build.cmd diff --git a/dotnet-latest.ps1 b/dotnet-latest.ps1 deleted file mode 100644 index 2a77d2ec9f..0000000000 --- a/dotnet-latest.ps1 +++ /dev/null @@ -1,41 +0,0 @@ -# Set up everything for using the dotnet cli. This should mean we do not have to wait for Appveyor images to be updated. - -# Clean and recreate the folder in which all output packages should be placed -$ArtifactsPath = "artifacts" - -if (Test-Path $ArtifactsPath) { - Remove-Item -Path $ArtifactsPath -Recurse -Force -ErrorAction Ignore -} - -New-Item $ArtifactsPath -ItemType Directory -ErrorAction Ignore | Out-Null - -Write-Host "Created artifacts folder '$ArtifactsPath'" -$installRequired = $TRUE - -# Install the latest dotnet cli -if (Get-Command "dotnet.exe" -ErrorAction SilentlyContinue) { - Write-Host "dotnet SDK already installed" - - $version = dotnet --version 2>&1 - if($version -ne "1.0.1"){ - Write-Host "$version installed but require 1.0.1" - $installRequired = $TRUE - }else{ - Write-Host "$version already installed" - $installRequired = $FALSE - } -} - -if($installRequired -eq $TRUE) -{ - Write-Host "Installing dotnet SDK" - - $installScript = Join-Path $ArtifactsPath "dotnet-install.ps1" - - Write-Host $installScript - - Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.1/scripts/obtain/dotnet-install.ps1" ` - -OutFile $installScript - - & $installScript -} \ No newline at end of file From 87f7dd0570486f0959ec4f72e5d444bd01121fc1 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sun, 12 Mar 2017 15:14:57 +0000 Subject: [PATCH 83/85] update sixlabors.* dependencies --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 9224325ead..cc1c526ae3 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -39,8 +39,8 @@ All - - + + ..\..\ImageSharp.ruleset From 5712d67ecbc41c1814009241eea7657b2cb99211 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 13 Mar 2017 09:28:05 +1100 Subject: [PATCH 84/85] Update readme to match new config/requirements --- README.md | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9d5c9788a7..368afc3b3f 100644 --- a/README.md +++ b/README.md @@ -28,32 +28,25 @@ We already have a [MyGet package repository](https://www.myget.org/gallery/image ### Packages -The **ImageSharp** library is made up of multiple packages, to make **ImageSharp** do anything useful you will want to make sure you include at least one format as a dependency otherwise you will not be able to save/load any images. +The **ImageSharp** library is made up of multiple packages. Packages include: - **ImageSharp** - Contains the Image classes, Colors, Primitives, Bootstrapper, IImageFormat interface, and other core functionality. -- **ImageSharp.Formats.Jpeg** - The jpeg decoder/encoder (Auto registered) -- **ImageSharp.Formats.Png** - The png decoder/encoder (Auto registered) -- **ImageSharp.Formats.Gif** - The gif decoder/encoder (Auto registered) -- **ImageSharp.Formats.Bmp** - The bmp decoder/encoder (Auto registered) -- **ImageSharp.Processing** - Contains methods like Resize, Crop, Skew, Rotate - Anything that alters the dimensions of the image. - Contains methods like Gaussian Blur, Pixelate, Edge Detection - Anything that maintains the original image dimensions. + - Contains the Image classes, Colors, Primitives, Configuration, and other core functionality. + - The IImageFormat interface, Jpeg, Png, Bmp, and Gif formats. + - Transform methods like Resize, Crop, Skew, Rotate - Anything that alters the dimensions of the image. + - Non-transform methods like Gaussian Blur, Pixelate, Edge Detection - Anything that maintains the original image dimensions. + - **ImageSharp.Drawing** - Brushes and various drawing algorithms, including drawing Images - - **ImageSharp.Drawing.Paths** - Various vector drawing methods for drawing paths, polygons etc. + - Brushes and various drawing algorithms, including drawing images. + - Various vector drawing methods for drawing paths, polygons etc. + - Text drawing. ### Manual build If you prefer, you can compile ImageSharp yourself (please do and help!), you'll need: -- [Visual Studio 2015 with Update 3 (or above)](https://www.visualstudio.com/news/releasenotes/vs2015-update3-vs) +- [Visual Studio 2017 (or above)](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes) - The [.NET Core 1.0 SDK Installer](https://www.microsoft.com/net/core#windows) - Non VSCode link. Alternatively on Linux you can use: From f0c896ae5a208ae6a9ea5e1a04b29b5eb1d1ebb5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 14 Mar 2017 13:12:24 +1100 Subject: [PATCH 85/85] Remove specific .NETCore version numbers [skip ci] They're are not on the linked pages --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 368afc3b3f..967bccf8aa 100644 --- a/README.md +++ b/README.md @@ -47,12 +47,12 @@ Packages include: If you prefer, you can compile ImageSharp yourself (please do and help!), you'll need: - [Visual Studio 2017 (or above)](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes) -- The [.NET Core 1.0 SDK Installer](https://www.microsoft.com/net/core#windows) - Non VSCode link. +- The [.NET Core SDK Installer](https://www.microsoft.com/net/core#windows) - Non VSCode link. Alternatively on Linux you can use: - [Visual Studio Code](https://code.visualstudio.com/) with [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp) -- [.Net Core 1.1](https://www.microsoft.com/net/core#linuxubuntu) +- [.Net Core](https://www.microsoft.com/net/core#linuxubuntu) To clone it locally click the "Clone in Windows" button above or run the following git commands.