Browse Source

Merge branch 'master' into 2017-v2

# Conflicts:
#	global.json
#	src/ImageSharp.Drawing/project.json
#	src/ImageSharp.Formats.Bmp/project.json
#	src/ImageSharp.Formats.Gif/project.json
#	src/ImageSharp.Formats.Jpeg/project.json
#	src/ImageSharp.Formats.Png/project.json
#	src/ImageSharp.Processing/project.json
#	src/ImageSharp/project.json
#	tests/ImageSharp.Benchmarks/Program.cs
#	tests/ImageSharp.Benchmarks/project.json
#	tests/ImageSharp.Tests/project.json
af/merge-core
Scott Williams 9 years ago
parent
commit
cfd749f27d
  1. 31
      .vscode/tasks.json
  2. 1
      ImageSharp.ruleset
  3. 195
      ImageSharp.sln
  4. 25
      README.md
  5. 4
      build/icons/imagesharp-logo-128.png
  6. 4
      build/icons/imagesharp-logo-256.png
  7. 4
      build/icons/imagesharp-logo-32.png
  8. 4
      build/icons/imagesharp-logo-512.png
  9. 4
      build/icons/imagesharp-logo-64.png
  10. 3
      build/icons/imagesharp-logo-heading.png
  11. 4
      build/icons/imagesharp-logo.png
  12. 60
      build/icons/imagesharp-logo.svg
  13. 8
      dotnet-latest.ps1
  14. 16
      features.md
  15. 112
      src/ImageSharp.Drawing.Paths/DrawBeziers.cs
  16. 112
      src/ImageSharp.Drawing.Paths/DrawLines.cs
  17. 112
      src/ImageSharp.Drawing.Paths/DrawPath.cs
  18. 112
      src/ImageSharp.Drawing.Paths/DrawPolygon.cs
  19. 69
      src/ImageSharp.Drawing.Paths/DrawRectangle.cs
  20. 78
      src/ImageSharp.Drawing.Paths/FillPaths.cs
  21. 78
      src/ImageSharp.Drawing.Paths/FillPolygon.cs
  22. 42
      src/ImageSharp.Drawing.Paths/FillRectangle.cs
  23. 84
      src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.csproj
  24. 6
      src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs
  25. 29
      src/ImageSharp.Drawing.Paths/RectangleExtensions.cs
  26. 104
      src/ImageSharp.Drawing.Paths/ShapePath.cs
  27. 87
      src/ImageSharp.Drawing.Paths/ShapeRegion.cs
  28. 203
      src/ImageSharp.Drawing.Text/DrawText.cs
  29. 126
      src/ImageSharp.Drawing.Text/GlyphBuilder.cs
  30. 84
      src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.csproj
  31. 6
      src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs
  32. 68
      src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs
  33. 2
      src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs
  34. 2
      src/ImageSharp.Drawing/Brushes/IBrush.cs
  35. 22
      src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs
  36. 20
      src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs
  37. 17
      src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
  38. 33
      src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs
  39. 10
      src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs
  40. 507
      src/ImageSharp.Drawing/Draw.cs
  41. 7
      src/ImageSharp.Drawing/DrawImage.cs
  42. 111
      src/ImageSharp.Drawing/DrawPath.cs
  43. 51
      src/ImageSharp.Drawing/Drawable.cs
  44. 173
      src/ImageSharp.Drawing/Fill.cs
  45. 103
      src/ImageSharp.Drawing/FillRegion.cs
  46. 119
      src/ImageSharp.Drawing/Paths/BezierLineSegment.cs
  47. 21
      src/ImageSharp.Drawing/Paths/ILineSegment.cs
  48. 48
      src/ImageSharp.Drawing/Paths/IPath.cs
  49. 516
      src/ImageSharp.Drawing/Paths/InternalPath.cs
  50. 55
      src/ImageSharp.Drawing/Paths/LinearLineSegment.cs
  51. 51
      src/ImageSharp.Drawing/Paths/Path.cs
  52. 35
      src/ImageSharp.Drawing/Paths/PointInfo.cs
  53. 2
      src/ImageSharp.Drawing/Pens/IPen.cs
  54. 2
      src/ImageSharp.Drawing/Pens/Pens{TColor}.cs
  55. 11
      src/ImageSharp.Drawing/Pens/Pen{TColor}.cs
  56. 2
      src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs
  57. 16
      src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs
  58. 23
      src/ImageSharp.Drawing/PointInfo.cs
  59. 2
      src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
  60. 142
      src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
  61. 9
      src/ImageSharp.Drawing/Processors/FillProcessor.cs
  62. 204
      src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
  63. 46
      src/ImageSharp.Drawing/Region.cs
  64. 93
      src/ImageSharp.Drawing/Shapes/BezierPolygon.cs
  65. 246
      src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs
  66. 56
      src/ImageSharp.Drawing/Shapes/IShape.cs
  67. 93
      src/ImageSharp.Drawing/Shapes/LinearPolygon.cs
  68. 156
      src/ImageSharp.Drawing/Shapes/Polygon.cs
  69. 3860
      src/ImageSharp.Drawing/Shapes/PolygonClipper/Clipper.cs
  70. 31
      src/ImageSharp.Drawing/Shapes/PolygonClipper/ClipperException.cs
  71. 31
      src/ImageSharp.Drawing/Shapes/PolygonClipper/Direction.cs
  72. 31
      src/ImageSharp.Drawing/Shapes/PolygonClipper/EdgeSide.cs
  73. 38
      src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNode.cs
  74. 48
      src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNodeSort.cs
  75. 38
      src/ImageSharp.Drawing/Shapes/PolygonClipper/Join.cs
  76. 44
      src/ImageSharp.Drawing/Shapes/PolygonClipper/LocalMinima.cs
  77. 38
      src/ImageSharp.Drawing/Shapes/PolygonClipper/Maxima.cs
  78. 43
      src/ImageSharp.Drawing/Shapes/PolygonClipper/OutPt.cs
  79. 64
      src/ImageSharp.Drawing/Shapes/PolygonClipper/OutRec.cs
  80. 179
      src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyNode.cs
  81. 81
      src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyTree.cs
  82. 31
      src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyType.cs
  83. 40
      src/ImageSharp.Drawing/Shapes/PolygonClipper/README.md
  84. 33
      src/ImageSharp.Drawing/Shapes/PolygonClipper/Scanbeam.cs
  85. 118
      src/ImageSharp.Drawing/Shapes/PolygonClipper/TEdge.cs
  86. 281
      src/ImageSharp.Drawing/Shapes/RectangularPolygon.cs
  87. 6
      src/ImageSharp.Formats.Bmp/BmpDecoder.cs
  88. 10
      src/ImageSharp.Formats.Bmp/BmpDecoderCore.cs
  89. 28
      src/ImageSharp.Formats.Bmp/BmpEncoder.cs
  90. 50
      src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs
  91. 45
      src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs
  92. 18
      src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs
  93. 2
      src/ImageSharp.Formats.Bmp/ImageExtensions.cs
  94. 14
      src/ImageSharp.Formats.Gif/GifConstants.cs
  95. 23
      src/ImageSharp.Formats.Gif/GifDecoder.cs
  96. 69
      src/ImageSharp.Formats.Gif/GifDecoderCore.cs
  97. 47
      src/ImageSharp.Formats.Gif/GifDecoderOptions.cs
  98. 41
      src/ImageSharp.Formats.Gif/GifEncoder.cs
  99. 115
      src/ImageSharp.Formats.Gif/GifEncoderCore.cs
  100. 65
      src/ImageSharp.Formats.Gif/GifEncoderOptions.cs

31
.vscode/tasks.json

@ -0,0 +1,31 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "0.1.0",
"command": "dotnet",
"isShellCommand": true,
"args": [],
"tasks": [
{
"taskName": "build",
"args": [ "src/*/project.json", "-f", "netstandard1.1" ],
"isBuildCommand": true,
"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"],
"isTestCommand": true,
"showOutput": "always",
"problemMatcher": "$msCompile"
}
]
}

1
ImageSharp.ruleset

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="ImageSharp" ToolsVersion="14.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1405" Action="None" />
<Rule Id="SA1413" Action="None" />
</Rules>
</RuleSet>

195
ImageSharp.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26127.0
VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
@ -55,15 +55,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Sandbox46", "tes
{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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImageSharp.Tests", "tests\ImageSharp.Tests\ImageSharp.Tests.csproj", "{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}"
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
@ -76,100 +81,100 @@ Global
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}.Debug|x64.ActiveCfg = Debug|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x64.Build.0 = Debug|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x86.ActiveCfg = Debug|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Debug|x86.Build.0 = Debug|Any CPU
{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
{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
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.ActiveCfg = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x64.Build.0 = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.ActiveCfg = Release|Any CPU
{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}.Release|x86.Build.0 = Release|Any CPU
{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}.Debug|x64.ActiveCfg = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x64.Build.0 = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x86.ActiveCfg = Debug|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Debug|x86.Build.0 = Debug|Any CPU
{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
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x64.ActiveCfg = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x64.Build.0 = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x86.ActiveCfg = Release|Any CPU
{2E33181E-6E28-4662-A801-E2E7DC206029}.Release|x86.Build.0 = Release|Any CPU
{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}.Debug|x64.ActiveCfg = Debug|Any CPU
{575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x64.Build.0 = Debug|Any CPU
{575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x86.ActiveCfg = Debug|Any CPU
{575A5002-DD9F-4335-AA47-1DD87FA13645}.Debug|x86.Build.0 = Debug|Any CPU
{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
{575A5002-DD9F-4335-AA47-1DD87FA13645}.Release|x64.ActiveCfg = Release|Any CPU
{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|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}.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|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
{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|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}.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|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
{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|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}.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|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
{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|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}.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|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
{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|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}.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|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
{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
@ -184,28 +189,52 @@ Global
{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}.Debug|x64.ActiveCfg = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x64.Build.0 = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x86.ActiveCfg = Debug|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Debug|x86.Build.0 = Debug|Any CPU
{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
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x64.ActiveCfg = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x64.Build.0 = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x86.ActiveCfg = Release|Any CPU
{EA3000E9-2A91-4EC4-8A68-E566DEBDC4F6}.Release|x86.Build.0 = Release|Any CPU
{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}.Debug|x64.ActiveCfg = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x64.Build.0 = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Debug|x86.Build.0 = Debug|Any CPU
{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
{2BF743D8-2A06-412D-96D7-F448F00C5EA5}.Release|x64.ActiveCfg = Release|Any CPU
{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
@ -223,5 +252,7 @@ Global
{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

25
README.md

@ -1,5 +1,5 @@
# <img src="build/icons/imagesharp-logo-64.png" width="52" height="52"/> ImageSharp
# <img src="build/icons/imagesharp-logo-heading.png" alt="ImageSharp"/>
**ImageSharp** is a new cross-platform 2D graphics API designed to allow the processing of images without the use of `System.Drawing`.
@ -45,7 +45,9 @@ Packages include:
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.
- **ImageSharp.Drawing**
Brushes and various drawing algorithms.
Brushes and various drawing algorithms, including drawing Images
- **ImageSharp.Drawing.Paths**
Various vector drawing methods for drawing paths, polygons etc.
### Manual build
@ -54,6 +56,11 @@ If you prefer, you can compile ImageSharp yourself (please do and help!), you'll
- [Visual Studio 2015 with Update 3 (or above)](https://www.visualstudio.com/news/releasenotes/vs2015-update3-vs)
- The [.NET Core 1.0 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)
To clone it locally click the "Clone in Windows" button above or run the following git commands.
```bash
@ -72,11 +79,21 @@ Many `Image` methods are also fluent.
Here's an example of the code required to resize an image using the default Bicubic resampler then turn the colors into their grayscale equivalent using the BT709 standard matrix.
On platforms supporting netstandard 1.3+
```csharp
using (Image image = new Image("foo.jpg"))
{
image.Resize(image.Width / 2, image.Height / 2)
.Grayscale()
.Save("bar.jpg"); // automatic encoder selected based on extension.
}
```
on netstandard 1.1 - 1.2
```csharp
using (FileStream stream = File.OpenRead("foo.jpg"))
using (FileStream output = File.OpenWrite("bar.jpg"))
using (Image image = new Image(stream))
{
Image image = new Image(stream);
image.Resize(image.Width / 2, image.Height / 2)
.Grayscale()
.Save(output);
@ -92,7 +109,7 @@ new BrightnessProcessor(50).Apply(sourceImage, sourceImage.Bounds);
Setting individual pixel values is perfomed as follows:
```csharp
Image image = new Image(400, 400);
using (image = new Image(400, 400)
using (var pixels = image.Lock())
{
pixels[200, 200] = Color.White;

4
build/icons/imagesharp-logo-128.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:01f79400a4a77c764273a97fbc76982546e88510fa4cc64a7b2e83e265b0e141
size 2490
oid sha256:47f14bb7d24f7228cd8833d8d1881a72750b2c7813f391bd2a0dd0eeea936841
size 6569

4
build/icons/imagesharp-logo-256.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5598d4cb5bad33aefc1084c4f389b071143a59505f00f7b7831c81254f1140f8
size 4225
oid sha256:757ec2f45cc5f9c2083fc65a236100f1a7776eee16bd1095a550e05783106a9f
size 13949

4
build/icons/imagesharp-logo-32.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:536e75abeaa2c35f34a95d34bee4f8bd13cf5514a979960566945da4ec8827d1
size 979
oid sha256:0f3a5375ce20321c2cfdc888a21dcb629d3e6a85641df5cca7c66e5b2a5f70f6
size 1439

4
build/icons/imagesharp-logo-512.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c8288a69f4182b25e04ba6419b452c6cdbca0013856352c0aeb08abc67f67e4d
size 7951
oid sha256:0e4cd18406375999c2bee1c39ad439b37f9524485d6e247ab0f14d2eb90a65f3
size 31256

4
build/icons/imagesharp-logo-64.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6ab6d98a7a55caf570016a62a2f4d72842e22cbe03460ad60a4dc196b7b1d303
size 1698
oid sha256:fa25e5dbe84f942107a1c29f4f68ff2a73f497412ae91b6e60fc5464bc9b5f05
size 3132

3
build/icons/imagesharp-logo-heading.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:bf2335642c6fd291befa0b203dbfb3387d99434369399b35aeea037c0f9eba45
size 10474

4
build/icons/imagesharp-logo.png

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2f20a3b2613811efa3455ee65b532284d88636d8796ee2279c08a584aa01744e
size 19129
oid sha256:e4217fe820af06a593903441f0719cab1ca650fd4de795f0e6808c4240a89819
size 59646

60
build/icons/imagesharp-logo.svg

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 22 KiB

8
dotnet-latest.ps1

@ -17,8 +17,8 @@ if (Get-Command "dotnet.exe" -ErrorAction SilentlyContinue) {
Write-Host "dotnet SDK already installed"
$version = dotnet --version 2>&1
if($version -ne "1.0.0-rc3-004530"){
Write-Host "$version installed but require 1.0.0-rc3-004530"
if($version -ne "1.0.1"){
Write-Host "$version installed but require 1.0.1"
$installRequired = $TRUE
}else{
Write-Host "$version already installed"
@ -34,8 +34,8 @@ if($installRequired -eq $TRUE)
Write-Host $installScript
Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0-rc3/scripts/obtain/dotnet-install.ps1" `
Invoke-WebRequest "https://raw.githubusercontent.com/dotnet/cli/rel/1.0.1/scripts/obtain/dotnet-install.ps1" `
-OutFile $installScript
& $installScript
}
}

16
features.md

@ -10,13 +10,23 @@ We've achieved a lot so far and hope to do a lot more in the future. We're alway
- [x] Bmp (Read: 32bit, 24bit, 16 bit. Write: 32bit, 24bit just now)
- [x] Png (Read: Rgb, Rgba, Grayscale, Grayscale + alpha, Palette. Write: Rgb, Rgba, Grayscale, Grayscale + alpha, Palette) Supports interlaced decoding
- [x] Gif (Includes animated)
- [ ] Tiff
- [ ] Tiff (Help needed)
- **Metadata**
- [x] EXIF Read/Write (Jpeg just now)
- **Quantizers (IQuantizer with alpha channel support + thresholding)**
- **Quantizers (IQuantizer with alpha channel support, dithering, and thresholding)**
- [x] Octree
- [x] Xiaolin Wu
- [x] Palette
- **DIthering (Error diffusion and Ordered)**
- [x] Atkinson
- [x] Burks
- [x] FloydSteinburg
- [x] JarvisJudiceNinke
- [x] Sieera2
- [x] Sierra3
- [x] SerraLite
- [x] Bayer
- [x] Ordered
- **Basic color structs with implicit operators.**
- [x] Color - 32bit color in RGBA order (IPackedPixel\<TPacked\>).
- [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.

112
src/ImageSharp.Drawing.Paths/DrawBeziers.cs

@ -0,0 +1,112 @@
// <copyright file="DrawBeziers.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using SixLabors.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), new Path(new BezierLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), new Path(new BezierLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.DrawBeziers(new SolidBrush<TColor>(color), thickness, points);
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawBeziers(new SolidBrush<TColor>(color), thickness, points, options);
}
/// <summary>
/// Draws the provided Points as an open Bezier path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new Path(new BezierLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Bezier path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new Path(new BezierLineSegment(points)));
}
}
}

112
src/ImageSharp.Drawing.Paths/DrawLines.cs

@ -0,0 +1,112 @@
// <copyright file="DrawLines.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using SixLabors.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), new Path(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), new Path(new LinearLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.DrawLines(new SolidBrush<TColor>(color), thickness, points);
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawLines(new SolidBrush<TColor>(color), thickness, points, options);
}
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new Path(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new Path(new LinearLineSegment(points)));
}
}
}

112
src/ImageSharp.Drawing.Paths/DrawPath.cs

@ -0,0 +1,112 @@
// <copyright file="DrawPath.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using SixLabors.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IPen<TColor> pen, IPath path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new ShapePath(path), options);
}
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IPen<TColor> pen, IPath path)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, path, GraphicsOptions.Default);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, IPath path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), path, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, IPath path)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), path);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, TColor color, float thickness, IPath path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new SolidBrush<TColor>(color), thickness, path, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, TColor color, float thickness, IPath path)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new SolidBrush<TColor>(color), thickness, path);
}
}
}

112
src/ImageSharp.Drawing.Paths/DrawPolygon.cs

@ -0,0 +1,112 @@
// <copyright file="DrawPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using SixLabors.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), new Polygon(new LinearLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, points);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, points, options);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new Polygon(new LinearLineSegment(points)), GraphicsOptions.Default);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, new Polygon(new LinearLineSegment(points)), options);
}
}
}

69
src/ImageSharp.Drawing/DrawRectangle.cs → src/ImageSharp.Drawing.Paths/DrawRectangle.cs

@ -9,10 +9,7 @@ namespace ImageSharp
using Drawing;
using Drawing.Brushes;
using Drawing.Paths;
using Drawing.Pens;
using Drawing.Processors;
using Drawing.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
@ -23,97 +20,91 @@ namespace ImageSharp
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, RectangleF shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IPen<TColor> pen, Rectangle shape, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Apply(new DrawPathProcessor<TColor>(pen, (IPath)new RectangularPolygon(shape), options));
return source.Draw(pen, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options);
}
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, RectangleF shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IPen<TColor> pen, Rectangle shape)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(pen, shape, GraphicsOptions.Default);
return source.Draw(pen, shape, GraphicsOptions.Default);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, RectangleF shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Rectangle shape, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(new Pen<TColor>(brush, thickness), shape, options);
return source.Draw(new Pen<TColor>(brush, thickness), shape, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, RectangleF shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Rectangle shape)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(new Pen<TColor>(brush, thickness), shape);
return source.Draw(new Pen<TColor>(brush, thickness), shape);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, RectangleF shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, TColor color, float thickness, Rectangle shape, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, shape, options);
return source.Draw(new SolidBrush<TColor>(color), thickness, shape, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, RectangleF shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, TColor color, float thickness, Rectangle shape)
where TColor : struct, IPixel<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, shape);
return source.Draw(new SolidBrush<TColor>(color), thickness, shape);
}
}
}

78
src/ImageSharp.Drawing.Paths/FillPaths.cs

@ -0,0 +1,78 @@
// <copyright file="FillPaths.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using Drawing;
using Drawing.Brushes;
using SixLabors.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, IPath path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Fill(brush, new ShapeRegion(path), options);
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, IPath path)
where TColor : struct, IPixel<TColor>
{
return source.Fill(brush, new ShapeRegion(path), GraphicsOptions.Default);
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, IPath path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), path, options);
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, IPath path)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), path);
}
}
}

78
src/ImageSharp.Drawing.Paths/FillPolygon.cs

@ -0,0 +1,78 @@
// <copyright file="FillPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using SixLabors.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Fill(brush, new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Fill(brush, new Polygon(new LinearLineSegment(points)));
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, TColor color, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, TColor color, Vector2[] points)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), new Polygon(new LinearLineSegment(points)));
}
}
}

42
src/ImageSharp.Drawing/FillRectangle.cs → src/ImageSharp.Drawing.Paths/FillRectangle.cs

@ -9,8 +9,6 @@ namespace ImageSharp
using Drawing;
using Drawing.Brushes;
using Drawing.Processors;
using Drawing.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
@ -21,46 +19,42 @@ namespace ImageSharp
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, RectangleF shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, Rectangle shape, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Apply(new FillShapeProcessor<TColor>(brush, new RectangularPolygon(shape), options));
return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height), options);
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, RectangleF shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, Rectangle shape)
where TColor : struct, IPixel<TColor>
{
return source.Apply(new FillShapeProcessor<TColor>(brush, new RectangularPolygon(shape), GraphicsOptions.Default));
return source.Fill(brush, new SixLabors.Shapes.Rectangle(shape.X, shape.Y, shape.Width, shape.Height));
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, RectangleF shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, Rectangle shape, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), shape, options);
}
@ -69,12 +63,12 @@ namespace ImageSharp
/// Flood fills the image in the shape of the provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, RectangleF shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, Rectangle shape)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), shape);
}

84
src/ImageSharp.Drawing.Paths/ImageSharp.Drawing.Paths.csproj

@ -0,0 +1,84 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A cross-platform library for the processing of image files; written in C#</Description>
<AssemblyTitle>ImageSharp.Drawing.Paths</AssemblyTitle>
<VersionPrefix>1.0.0-alpha2</VersionPrefix>
<Authors>James Jackson-South and contributors</Authors>
<TargetFrameworks>netstandard1.1;net45;net461</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>ImageSharp.Drawing.Paths</AssemblyName>
<PackageId>ImageSharp.Drawing.Paths</PackageId>
<PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Core</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/JimBobSquarePants/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/JimBobSquarePants/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
<ProjectReference Include="..\ImageSharp.Drawing\ImageSharp.Drawing.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Shapes" Version="0.1.0-alpha0007" />
<PackageReference Include="System.Buffers" Version="4.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
<PackageReference Include="System.Collections" Version="4.0.11" />
<PackageReference Include="System.Diagnostics.Debug" Version="4.0.11" />
<PackageReference Include="System.Diagnostics.Tools" Version="4.0.1" />
<PackageReference Include="System.IO" Version="4.1.0" />
<PackageReference Include="System.IO.Compression" Version="4.1.0" />
<PackageReference Include="System.Linq" Version="4.1.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.1.1" />
<PackageReference Include="System.ObjectModel" Version="4.0.12" />
<PackageReference Include="System.Resources.ResourceManager" Version="4.0.1" />
<PackageReference Include="System.Runtime.Extensions" Version="4.1.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.1.0" />
<PackageReference Include="System.Runtime.Numerics" Version="4.0.1" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.0.11" />
<PackageReference Include="System.Threading" Version="4.0.11" />
<PackageReference Include="System.Threading.Tasks" Version="4.0.11" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<PackageReference Include="System.Numerics.Vectors" Version="4.1.1" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.0.1" />
<Reference Include="System.Runtime" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.0.1" />
<Reference Include="System.Runtime" />
<Reference Include="System.Numerics" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
</Project>

6
src/ImageSharp.Drawing.Paths/Properties/AssemblyInfo.cs

@ -0,0 +1,6 @@
// <copyright file="AssemblyInfo.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// Common values read from `AssemblyInfo.Common.cs`

29
src/ImageSharp.Drawing.Paths/RectangleExtensions.cs

@ -0,0 +1,29 @@
// <copyright file="RectangleExtensions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
using System;
/// <summary>
/// Extension methods for helping to bridge Shaper2D and ImageSharp primitives.
/// </summary>
internal static class RectangleExtensions
{
/// <summary>
/// Converts a Shaper2D <see cref="SixLabors.Shapes.Rectangle"/> to an ImageSharp <see cref="Rectangle"/> by creating a <see cref="Rectangle"/> the entirely surrounds the source.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <returns>A <see cref="Rectangle"/> representation of this <see cref="SixLabors.Shapes.Rectangle"/></returns>
public static Rectangle Convert(this SixLabors.Shapes.Rectangle source)
{
int left = (int)Math.Floor(source.Left);
int right = (int)Math.Ceiling(source.Right);
int top = (int)Math.Floor(source.Top);
int bottom = (int)Math.Ceiling(source.Bottom);
return new Rectangle(left, top, right - left, bottom - top);
}
}
}

104
src/ImageSharp.Drawing.Paths/ShapePath.cs

@ -0,0 +1,104 @@
// <copyright file="ShapePath.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
using System.Buffers;
using System.Collections.Immutable;
using System.Numerics;
using SixLabors.Shapes;
using Rectangle = ImageSharp.Rectangle;
/// <summary>
/// A drawable mapping between a <see cref="IPath"/> and a drawable region.
/// </summary>
internal class ShapePath : Drawable
{
/// <summary>
/// Initializes a new instance of the <see cref="ShapePath"/> class.
/// </summary>
/// <param name="path">The path.</param>
public ShapePath(IPath path)
{
this.Path = path;
this.Bounds = path.Bounds.Convert();
}
/// <summary>
/// Gets the fillable shape
/// </summary>
public IPath Path { get; }
/// <inheritdoc/>
public override int MaxIntersections => this.Path.MaxIntersections;
/// <inheritdoc/>
public override Rectangle Bounds { get; }
/// <inheritdoc/>
public override int ScanX(int x, float[] buffer, int length, int offset)
{
Vector2 start = new Vector2(x, this.Bounds.Top - 1);
Vector2 end = new Vector2(x, this.Bounds.Bottom + 1);
Vector2[] innerbuffer = ArrayPool<Vector2>.Shared.Rent(length);
try
{
int count = this.Path.FindIntersections(start, end, innerbuffer, length, 0);
for (int i = 0; i < count; i++)
{
buffer[i + offset] = innerbuffer[i].Y;
}
return count;
}
finally
{
ArrayPool<Vector2>.Shared.Return(innerbuffer);
}
}
/// <inheritdoc/>
public override int ScanY(int y, float[] buffer, int length, int offset)
{
Vector2 start = new Vector2(this.Bounds.Left - 1, y);
Vector2 end = new Vector2(this.Bounds.Right + 1, y);
Vector2[] innerbuffer = ArrayPool<Vector2>.Shared.Rent(length);
try
{
int count = this.Path.FindIntersections(start, end, innerbuffer, length, 0);
for (int i = 0; i < count; i++)
{
buffer[i + offset] = innerbuffer[i].X;
}
return count;
}
finally
{
ArrayPool<Vector2>.Shared.Return(innerbuffer);
}
}
/// <inheritdoc/>
public override PointInfo GetPointInfo(int x, int y)
{
Vector2 point = new Vector2(x, y);
SixLabors.Shapes.PointInfo dist = this.Path.Distance(point);
return new PointInfo
{
DistanceAlongPath = dist.DistanceAlongPath,
DistanceFromPath =
dist.DistanceFromPath < 0
? -dist.DistanceFromPath
: dist.DistanceFromPath
};
}
}
}

87
src/ImageSharp.Drawing.Paths/ShapeRegion.cs

@ -0,0 +1,87 @@
// <copyright file="ShapeRegion.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
using System.Buffers;
using System.Numerics;
using SixLabors.Shapes;
using Rectangle = ImageSharp.Rectangle;
/// <summary>
/// A mapping between a <see cref="IPath"/> and a region.
/// </summary>
internal class ShapeRegion : Region
{
/// <summary>
/// Initializes a new instance of the <see cref="ShapeRegion"/> class.
/// </summary>
/// <param name="shape">The shape.</param>
public ShapeRegion(IPath shape)
{
this.Shape = shape.AsClosedPath();
this.Bounds = shape.Bounds.Convert();
}
/// <summary>
/// Gets the fillable shape
/// </summary>
public IPath Shape { get; }
/// <inheritdoc/>
public override int MaxIntersections => this.Shape.MaxIntersections;
/// <inheritdoc/>
public override Rectangle Bounds { get; }
/// <inheritdoc/>
public override int ScanX(int x, float[] buffer, int length, int offset)
{
Vector2 start = new Vector2(x, this.Bounds.Top - 1);
Vector2 end = new Vector2(x, this.Bounds.Bottom + 1);
Vector2[] innerbuffer = ArrayPool<Vector2>.Shared.Rent(length);
try
{
int count = this.Shape.FindIntersections(start, end, innerbuffer, length, 0);
for (int i = 0; i < count; i++)
{
buffer[i + offset] = innerbuffer[i].Y;
}
return count;
}
finally
{
ArrayPool<Vector2>.Shared.Return(innerbuffer);
}
}
/// <inheritdoc/>
public override int ScanY(int y, float[] buffer, int length, int offset)
{
Vector2 start = new Vector2(this.Bounds.Left - 1, y);
Vector2 end = new Vector2(this.Bounds.Right + 1, y);
Vector2[] innerbuffer = ArrayPool<Vector2>.Shared.Rent(length);
try
{
int count = this.Shape.FindIntersections(start, end, innerbuffer, length, 0);
for (int i = 0; i < count; i++)
{
buffer[i + offset] = innerbuffer[i].X;
}
return count;
}
finally
{
ArrayPool<Vector2>.Shared.Return(innerbuffer);
}
}
}
}

203
src/ImageSharp.Drawing.Text/DrawText.cs

@ -0,0 +1,203 @@
// <copyright file="DrawText.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using SixLabors.Fonts;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, TColor color, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, color, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="color">The color.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, TColor color, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, Brushes<TColor>.Solid(color), null, location, options);
}
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, brush, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image filled via the brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, brush, null, location, options);
}
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IPen<TColor> pen, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, pen, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image outlined via the pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="pen">The pen.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IPen<TColor> pen, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, null, pen, location, options);
}
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="location">The location.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, IPen<TColor> pen, Vector2 location)
where TColor : struct, IPixel<TColor>
{
return source.DrawText(text, font, brush, pen, location, TextGraphicsOptions.Default);
}
/// <summary>
/// Draws the text onto the the image filled via the brush then outlined via the pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="text">The text.</param>
/// <param name="font">The font.</param>
/// <param name="brush">The brush.</param>
/// <param name="pen">The pen.</param>
/// <param name="location">The location.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The <see cref="Image{TColor}" />.
/// </returns>
public static Image<TColor> DrawText<TColor>(this Image<TColor> source, string text, Font font, IBrush<TColor> brush, IPen<TColor> pen, Vector2 location, TextGraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
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<SixLabors.Shapes.IPath> 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;
}
}
}

126
src/ImageSharp.Drawing.Text/GlyphBuilder.cs

@ -0,0 +1,126 @@
// <copyright file="GlyphBuilder.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
using System.Collections.Generic;
using System.Numerics;
using SixLabors.Fonts;
using SixLabors.Shapes;
/// <summary>
/// rendering surface that Fonts can use to generate Shapes.
/// </summary>
internal class GlyphBuilder : IGlyphRenderer
{
private readonly PathBuilder builder = new PathBuilder();
private readonly List<IPath> paths = new List<IPath>();
private Vector2 currentPoint = default(Vector2);
/// <summary>
/// Initializes a new instance of the <see cref="GlyphBuilder"/> class.
/// </summary>
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();
}
/// <summary>
/// Initializes a new instance of the <see cref="GlyphBuilder"/> class.
/// </summary>
/// <param name="origin">The origin.</param>
public GlyphBuilder(Vector2 origin)
{
this.builder = new PathBuilder();
this.builder.SetOrigin(origin);
}
/// <summary>
/// Gets the paths that have been rendered by this.
/// </summary>
public IEnumerable<IPath> Paths => this.paths;
/// <summary>
/// Begins the glyph.
/// </summary>
void IGlyphRenderer.BeginGlyph()
{
this.builder.Clear();
}
/// <summary>
/// Begins the figure.
/// </summary>
void IGlyphRenderer.BeginFigure()
{
this.builder.StartFigure();
}
/// <summary>
/// Draws a cubic bezier from the current point to the <paramref name="point"/>
/// </summary>
/// <param name="secondControlPoint">The second control point.</param>
/// <param name="thirdControlPoint">The third control point.</param>
/// <param name="point">The point.</param>
void IGlyphRenderer.CubicBezierTo(Vector2 secondControlPoint, Vector2 thirdControlPoint, Vector2 point)
{
this.builder.AddBezier(this.currentPoint, secondControlPoint, thirdControlPoint, point);
this.currentPoint = point;
}
/// <summary>
/// Ends the glyph.
/// </summary>
void IGlyphRenderer.EndGlyph()
{
this.paths.Add(this.builder.Build());
}
/// <summary>
/// Ends the figure.
/// </summary>
void IGlyphRenderer.EndFigure()
{
this.builder.CloseFigure();
}
/// <summary>
/// Draws a line from the current point to the <paramref name="point"/>.
/// </summary>
/// <param name="point">The point.</param>
void IGlyphRenderer.LineTo(Vector2 point)
{
this.builder.AddLine(this.currentPoint, point);
this.currentPoint = point;
}
/// <summary>
/// Moves to current point to the supplied vector.
/// </summary>
/// <param name="point">The point.</param>
void IGlyphRenderer.MoveTo(Vector2 point)
{
this.builder.StartFigure();
this.currentPoint = point;
}
/// <summary>
/// Draws a quadratics bezier from the current point to the <paramref name="point"/>
/// </summary>
/// <param name="secondControlPoint">The second control point.</param>
/// <param name="point">The point.</param>
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;
}
}
}

84
src/ImageSharp.Drawing.Text/ImageSharp.Drawing.Text.csproj

@ -0,0 +1,84 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A cross-platform library for the processing of image files; written in C#</Description>
<AssemblyTitle>ImageSharp.Drawing.Text</AssemblyTitle>
<VersionPrefix>1.0.0-alpha2</VersionPrefix>
<Authors>James Jackson-South and contributors</Authors>
<TargetFrameworks>netstandard1.1;net45;net461</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>ImageSharp.Drawing.Text</AssemblyName>
<PackageId>ImageSharp.Drawing.Text</PackageId>
<PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Core</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/JimBobSquarePants/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/JimBobSquarePants/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
<ProjectReference Include="..\ImageSharp.Drawing.Paths\ImageSharp.Drawing.Paths.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Fonts" Version="0.1.0-alpha0001" />
<PackageReference Include="System.Buffers" Version="4.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
<PackageReference Include="System.Collections" Version="4.0.11" />
<PackageReference Include="System.Diagnostics.Debug" Version="4.0.11" />
<PackageReference Include="System.Diagnostics.Tools" Version="4.0.1" />
<PackageReference Include="System.IO" Version="4.1.0" />
<PackageReference Include="System.IO.Compression" Version="4.1.0" />
<PackageReference Include="System.Linq" Version="4.1.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.1.1" />
<PackageReference Include="System.ObjectModel" Version="4.0.12" />
<PackageReference Include="System.Resources.ResourceManager" Version="4.0.1" />
<PackageReference Include="System.Runtime.Extensions" Version="4.1.0" />
<PackageReference Include="System.Runtime.InteropServices" Version="4.1.0" />
<PackageReference Include="System.Runtime.Numerics" Version="4.0.1" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.0.11" />
<PackageReference Include="System.Threading" Version="4.0.11" />
<PackageReference Include="System.Threading.Tasks" Version="4.0.11" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.0.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<PackageReference Include="System.Numerics.Vectors" Version="4.1.1" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.0.1" />
<Reference Include="System.Runtime" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net461' ">
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.0.1" />
<Reference Include="System.Runtime" />
<Reference Include="System.Numerics" />
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>
</Project>

6
src/ImageSharp.Drawing.Text/Properties/AssemblyInfo.cs

@ -0,0 +1,6 @@
// <copyright file="AssemblyInfo.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// Common values read from `AssemblyInfo.Common.cs`

68
src/ImageSharp.Drawing.Text/TextGraphicsOptions.cs

@ -0,0 +1,68 @@
// <copyright file="TextGraphicsOptions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
/// <summary>
/// Options for influencing the drawing functions.
/// </summary>
public struct TextGraphicsOptions
{
/// <summary>
/// Represents the default <see cref="TextGraphicsOptions"/>.
/// </summary>
public static readonly TextGraphicsOptions Default = new TextGraphicsOptions(true);
/// <summary>
/// Whether antialiasing should be applied.
/// </summary>
public bool Antialias;
/// <summary>
/// Whether the text should be drawing with kerning enabled.
/// </summary>
public bool ApplyKerning;
/// <summary>
/// The number of space widths a tab should lock to.
/// </summary>
public float TabWidth;
/// <summary>
/// Initializes a new instance of the <see cref="TextGraphicsOptions" /> struct.
/// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
public TextGraphicsOptions(bool enableAntialiasing)
{
this.Antialias = enableAntialiasing;
this.ApplyKerning = true;
this.TabWidth = 4;
}
/// <summary>
/// Performs an implicit conversion from <see cref="GraphicsOptions"/> to <see cref="TextGraphicsOptions"/>.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>
/// The result of the conversion.
/// </returns>
public static implicit operator TextGraphicsOptions(GraphicsOptions options)
{
return new TextGraphicsOptions(options.Antialias);
}
/// <summary>
/// Performs an explicit conversion from <see cref="TextGraphicsOptions"/> to <see cref="GraphicsOptions"/>.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>
/// The result of the conversion.
/// </returns>
public static explicit operator GraphicsOptions(TextGraphicsOptions options)
{
return new GraphicsOptions(options.Antialias);
}
}
}

2
src/ImageSharp.Drawing/Brushes/Brushes{TColor}.cs

@ -13,7 +13,7 @@ namespace ImageSharp.Drawing.Brushes
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <returns>A Brush</returns>
public class Brushes<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Percent10 Hatch Pattern

2
src/ImageSharp.Drawing/Brushes/IBrush.cs

@ -18,7 +18,7 @@ namespace ImageSharp.Drawing
/// logic for converting a pixel location to a <typeparamref name="TColor"/>.
/// </remarks>
public interface IBrush<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Creates the applicator for this brush.

22
src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs

@ -15,7 +15,7 @@ namespace ImageSharp.Drawing.Brushes
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public class ImageBrush<TColor> : IBrush<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The image to paint.
@ -82,18 +82,24 @@ namespace ImageSharp.Drawing.Brushes
/// <summary>
/// Gets the color for a single pixel.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>
/// The color
/// </returns>
public override TColor GetColor(Vector2 point)
public override TColor this[int x, int y]
{
// Offset the requested pixel by the value in the rectangle (the shapes position)
point = point - this.offset;
int x = (int)point.X % this.xLength;
int y = (int)point.Y % this.yLength;
get
{
var point = new Vector2(x, y);
return this.source[x, y];
// Offset the requested pixel by the value in the rectangle (the shapes position)
point = point - this.offset;
x = (int)point.X % this.xLength;
y = (int)point.Y % this.yLength;
return this.source[x, y];
}
}
/// <inheritdoc />

20
src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs

@ -42,7 +42,7 @@ namespace ImageSharp.Drawing.Brushes
/// </remarks>
/// <typeparam name="TColor">The pixel format.</typeparam>
public class PatternBrush<TColor> : IBrush<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The pattern.
@ -134,17 +134,21 @@ namespace ImageSharp.Drawing.Brushes
/// <summary>
/// Gets the color for a single pixel.
/// </summary>
/// <param name="point">The point.</param>
/// </summary>#
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>
/// The color
/// The Color.
/// </returns>
public override TColor GetColor(Vector2 point)
public override TColor this[int x, int y]
{
int x = (int)point.X % this.xLength;
int y = (int)point.Y % this.stride;
get
{
x = x % this.xLength;
y = y % this.stride;
return this.pattern[x][y];
return this.pattern[x][y];
}
}
/// <inheritdoc />

17
src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs

@ -14,18 +14,17 @@ namespace ImageSharp.Drawing.Processors
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <seealso cref="System.IDisposable" />
public abstract class BrushApplicator<TColor> : IDisposable // disposable will be required if/when there is an ImageBrush
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public abstract void Dispose();
/// <summary>
/// Gets the color for a single pixel.
/// </summary>
/// <param name="point">The point.</param>
/// <returns>The color</returns>
public abstract TColor GetColor(Vector2 point);
/// <param name="x">The x cordinate.</param>
/// <param name="y">The y cordinate.</param>
/// <returns>The a <typeparamref name="TColor"/> that should be applied to the pixel.</returns>
public abstract TColor this[int x, int y] { get; }
/// <inheritdoc/>
public abstract void Dispose();
}
}

33
src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs

@ -15,7 +15,7 @@ namespace ImageSharp.Drawing.Brushes
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public class RecolorBrush<TColor> : IBrush<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Initializes a new instance of the <see cref="RecolorBrush{TColor}" /> class.
@ -109,24 +109,31 @@ namespace ImageSharp.Drawing.Brushes
/// <summary>
/// Gets the color for a single pixel.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>
/// The color
/// </returns>
public override TColor GetColor(Vector2 point)
public override TColor this[int x, int y]
{
// Offset the requested pixel by the value in the rectangle (the shapes position)
TColor result = this.source[(int)point.X, (int)point.Y];
Vector4 background = result.ToVector4();
float distance = Vector4.DistanceSquared(background, this.sourceColor);
if (distance <= this.threshold)
get
{
var lerpAmount = (this.threshold - distance) / this.threshold;
Vector4 blended = Vector4BlendTransforms.PremultipliedLerp(background, this.targetColor, lerpAmount);
result.PackFromVector4(blended);
// Offset the requested pixel by the value in the rectangle (the shapes position)
TColor result = this.source[x, y];
Vector4 background = result.ToVector4();
float distance = Vector4.DistanceSquared(background, this.sourceColor);
if (distance <= this.threshold)
{
var lerpAmount = (this.threshold - distance) / this.threshold;
Vector4 blended = Vector4BlendTransforms.PremultipliedLerp(
background,
this.targetColor,
lerpAmount);
result.PackFromVector4(blended);
}
return result;
}
return result;
}
/// <inheritdoc />

10
src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs

@ -15,7 +15,7 @@ namespace ImageSharp.Drawing.Brushes
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public class SolidBrush<TColor> : IBrush<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The color to paint.
@ -67,14 +67,12 @@ namespace ImageSharp.Drawing.Brushes
/// <summary>
/// Gets the color for a single pixel.
/// </summary>
/// <param name="point">The point.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>
/// The color
/// </returns>
public override TColor GetColor(Vector2 point)
{
return this.color;
}
public override TColor this[int x, int y] => this.color;
/// <inheritdoc />
public override void Dispose()

507
src/ImageSharp.Drawing/Draw.cs

@ -1,507 +0,0 @@
// <copyright file="Draw.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Paths;
using Drawing.Pens;
using Drawing.Processors;
using Drawing.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, IShape shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new DrawPathProcessor<TColor>(pen, shape, options));
}
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, IShape shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(pen, shape, GraphicsOptions.Default);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, IShape shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new Pen<TColor>(brush, thickness), shape, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, IShape shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new Pen<TColor>(brush, thickness), shape);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, IShape shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, shape, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, IShape shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, shape);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new Pen<TColor>(brush, thickness), new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new Pen<TColor>(brush, thickness), new Polygon(new LinearLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, points);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(new SolidBrush<TColor>(color), thickness, points, options);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(pen, new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as a closed Linear Polygon with the provided Pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPolygon<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPolygon(pen, new Polygon(new LinearLineSegment(points)));
}
/// <summary>
/// Draws the path with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPath<TColor>(this Image<TColor> source, IPen<TColor> pen, IPath path, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new DrawPathProcessor<TColor>(pen, path, options));
}
/// <summary>
/// Draws the path with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPath<TColor>(this Image<TColor> source, IPen<TColor> pen, IPath path)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new DrawPathProcessor<TColor>(pen, path, GraphicsOptions.Default));
}
/// <summary>
/// Draws the path with the bursh at the privdied thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPath<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, IPath path, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new Pen<TColor>(brush, thickness), path, options);
}
/// <summary>
/// Draws the path with the bursh at the privdied thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPath<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, IPath path)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new Pen<TColor>(brush, thickness), path);
}
/// <summary>
/// Draws the path with the bursh at the privdied thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawPath<TColor>(this Image<TColor> source, TColor color, float thickness, IPath path, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new SolidBrush<TColor>(color), thickness, path, options);
}
/// <summary>
/// Draws the path with the bursh at the privdied thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawPath<TColor>(this Image<TColor> source, TColor color, float thickness, IPath path)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new SolidBrush<TColor>(color), thickness, path);
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new Pen<TColor>(brush, thickness), new Path(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new Pen<TColor>(brush, thickness), new Path(new LinearLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawLines(new SolidBrush<TColor>(color), thickness, points);
}
/// <summary>
/// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawLines(new SolidBrush<TColor>(color), thickness, points, options);
}
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(pen, new Path(new LinearLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Linear path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawLines<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(pen, new Path(new LinearLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new Pen<TColor>(brush, thickness), new Path(new BezierLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(new Pen<TColor>(brush, thickness), new Path(new BezierLineSegment(points)));
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawBeziers(new SolidBrush<TColor>(color), thickness, points);
}
/// <summary>
/// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, TColor color, float thickness, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawBeziers(new SolidBrush<TColor>(color), thickness, points, options);
}
/// <summary>
/// Draws the provided Points as an open Bezier path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(pen, new Path(new BezierLineSegment(points)), options);
}
/// <summary>
/// Draws the provided Points as an open Bezier path with the supplied pen
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="pen">The pen.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> DrawBeziers<TColor>(this Image<TColor> source, IPen<TColor> pen, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.DrawPath(pen, new Path(new BezierLineSegment(points)));
}
}
}

7
src/ImageSharp.Drawing/DrawImage.cs

@ -23,7 +23,7 @@ namespace ImageSharp
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Blend<TColor>(this Image<TColor> source, Image<TColor> image, int percent = 50)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
return DrawImage(source, image, percent, default(Size), default(Point));
}
@ -39,7 +39,7 @@ namespace ImageSharp
/// <param name="location">The location to draw the blended image.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> DrawImage<TColor>(this Image<TColor> source, Image<TColor> image, int percent, Size size, Point location)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
if (size == default(Size))
{
@ -51,7 +51,8 @@ namespace ImageSharp
location = Point.Empty;
}
return source.Apply(source.Bounds, new DrawImageProcessor<TColor>(image, size, location, percent));
source.ApplyProcessor(new DrawImageProcessor<TColor>(image, size, location, percent), source.Bounds);
return source;
}
}
}

111
src/ImageSharp.Drawing/DrawPath.cs

@ -0,0 +1,111 @@
// <copyright file="DrawPath.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using Drawing;
using Drawing.Brushes;
using Drawing.Pens;
using Drawing.Processors;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Draws the outline of the region with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IPen<TColor> pen, Drawable path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Apply(new DrawPathProcessor<TColor>(pen, path, options));
}
/// <summary>
/// Draws the outline of the polygon with the provided pen.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IPen<TColor> pen, Drawable path)
where TColor : struct, IPixel<TColor>
{
return source.Draw(pen, path, GraphicsOptions.Default);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Drawable path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), path, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, IBrush<TColor> brush, float thickness, Drawable path)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new Pen<TColor>(brush, thickness), path);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, TColor color, float thickness, Drawable path, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new SolidBrush<TColor>(color), thickness, path, options);
}
/// <summary>
/// Draws the outline of the polygon with the provided brush at the provided thickness.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="thickness">The thickness.</param>
/// <param name="path">The path.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Draw<TColor>(this Image<TColor> source, TColor color, float thickness, Drawable path)
where TColor : struct, IPixel<TColor>
{
return source.Draw(new SolidBrush<TColor>(color), thickness, path);
}
}
}

51
src/ImageSharp.Drawing/Drawable.cs

@ -0,0 +1,51 @@
// <copyright file="Drawable.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
/// <summary>
/// Represents a path or set of paths that can be drawn as an outline.
/// </summary>
public abstract class Drawable
{
/// <summary>
/// Gets the maximum number of intersections to could be returned.
/// </summary>
public abstract int MaxIntersections { get; }
/// <summary>
/// Gets the bounds.
/// </summary>
public abstract Rectangle Bounds { get; }
/// <summary>
/// Gets the point information for the specified x and y location.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>Information about the point in relation to a drawable edge</returns>
public abstract PointInfo GetPointInfo(int x, int y);
/// <summary>
/// Scans the X axis for intersections.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="length">The length.</param>
/// <param name="offset">The offset.</param>
/// <returns>The number of intersections found.</returns>
public abstract int ScanX(int x, float[] buffer, int length, int offset);
/// <summary>
/// Scans the Y axis for intersections.
/// </summary>
/// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="length">The length.</param>
/// <param name="offset">The offset.</param>
/// <returns>The number of intersections found.</returns>
public abstract int ScanY(int y, float[] buffer, int length, int offset);
}
}

173
src/ImageSharp.Drawing/Fill.cs

@ -1,173 +0,0 @@
// <copyright file="Fill.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using System.Numerics;
using Drawing;
using Drawing.Brushes;
using Drawing.Paths;
using Drawing.Processors;
using Drawing.Shapes;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Flood fills the image with the specified brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillProcessor<TColor>(brush));
}
/// <summary>
/// Flood fills the image with the specified color.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Fill(new SolidBrush<TColor>(color));
}
/// <summary>
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, IShape shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillShapeProcessor<TColor>(brush, shape, options));
}
/// <summary>
/// Flood fills the image in the shape of the provided polygon with the specified brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, IShape shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Apply(new FillShapeProcessor<TColor>(brush, shape, GraphicsOptions.Default));
}
/// <summary>
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, IShape shape, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), shape, options);
}
/// <summary>
/// Flood fills the image in the shape o fhte provided polygon with the specified brush..
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="shape">The shape.</param>
/// <returns>The Image</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, IShape shape)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), shape);
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
// using Polygon directly instead of LinearPolygon as its will have less indirection
return source.Fill(brush, new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="brush">The brush.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, IBrush<TColor> brush, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
// using Polygon directly instead of LinearPolygon as its will have less indirection
return source.Fill(brush, new Polygon(new LinearLineSegment(points)));
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <param name="options">The options.</param>
/// <returns>
/// The Image
/// </returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, TColor color, Vector2[] points, GraphicsOptions options)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
// using Polygon directly instead of LinearPolygon as its will have less indirection
return source.Fill(new SolidBrush<TColor>(color), new Polygon(new LinearLineSegment(points)), options);
}
/// <summary>
/// Flood fills the image in the shape of a Linear polygon described by the points
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The source.</param>
/// <param name="color">The color.</param>
/// <param name="points">The points.</param>
/// <returns>The Image</returns>
public static Image<TColor> FillPolygon<TColor>(this Image<TColor> source, TColor color, Vector2[] points)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
// using Polygon directly instead of LinearPolygon as its will have less indirection
return source.Fill(new SolidBrush<TColor>(color), new Polygon(new LinearLineSegment(points)));
}
}
}

103
src/ImageSharp.Drawing/FillRegion.cs

@ -0,0 +1,103 @@
// <copyright file="FillRegion.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System;
using Drawing;
using Drawing.Brushes;
using Drawing.Processors;
/// <summary>
/// Extension methods for the <see cref="Image{TColor}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Flood fills the image with the specified brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The details how to fill the region of interest.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush)
where TColor : struct, IPixel<TColor>
{
return source.Apply(new FillProcessor<TColor>(brush));
}
/// <summary>
/// Flood fills the image with the specified color.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color));
}
/// <summary>
/// Flood fills the image with in the region with the specified brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="region">The region.</param>
/// <param name="options">The graphics options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, Region region, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Apply(new FillRegionProcessor<TColor>(brush, region, options));
}
/// <summary>
/// Flood fills the image with in the region with the specified brush.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="brush">The brush.</param>
/// <param name="region">The region.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, IBrush<TColor> brush, Region region)
where TColor : struct, IPixel<TColor>
{
return source.Fill(brush, region, GraphicsOptions.Default);
}
/// <summary>
/// Flood fills the image with in the region with the specified color.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="region">The region.</param>
/// <param name="options">The options.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, Region region, GraphicsOptions options)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), region, options);
}
/// <summary>
/// Flood fills the image with in the region with the specified color.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="color">The color.</param>
/// <param name="region">The region.</param>
/// <returns>The <see cref="Image{TColor}"/>.</returns>
public static Image<TColor> Fill<TColor>(this Image<TColor> source, TColor color, Region region)
where TColor : struct, IPixel<TColor>
{
return source.Fill(new SolidBrush<TColor>(color), region);
}
}
}

119
src/ImageSharp.Drawing/Paths/BezierLineSegment.cs

@ -1,119 +0,0 @@
// <copyright file="BezierLineSegment.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System.Numerics;
/// <summary>
/// Represents a line segment that conistst of control points that will be rendered as a cubic bezier curve
/// </summary>
/// <seealso cref="ImageSharp.Drawing.Paths.ILineSegment" />
public class BezierLineSegment : ILineSegment
{
/// <summary>
/// The segments per curve.
/// code for this taken from <see href="http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/"/>
/// </summary>
private const int SegmentsPerCurve = 50;
/// <summary>
/// The line points.
/// </summary>
private readonly Vector2[] linePoints;
/// <summary>
/// Initializes a new instance of the <see cref="BezierLineSegment"/> class.
/// </summary>
/// <param name="points">The points.</param>
public BezierLineSegment(params Vector2[] points)
{
Guard.NotNull(points, nameof(points));
Guard.MustBeGreaterThanOrEqualTo(points.Length, 4, nameof(points));
this.linePoints = this.GetDrawingPoints(points);
}
/// <summary>
/// Returns the current <see cref="ILineSegment" /> a simple linear path.
/// </summary>
/// <returns>
/// Returns the current <see cref="ILineSegment" /> as simple linear path.
/// </returns>
public Vector2[] AsSimpleLinearPath()
{
return this.linePoints;
}
/// <summary>
/// Returns the drawing points along the line.
/// </summary>
/// <param name="controlPoints">The control points.</param>
/// <returns>
/// The <see cref="T:Vector2[]"/>.
/// </returns>
private Vector2[] GetDrawingPoints(Vector2[] controlPoints)
{
// TODO we need to calculate an optimal SegmentsPerCurve value
// depending on the calcualted length of this curve
int curveCount = (controlPoints.Length - 1) / 3;
int finalPointCount = (SegmentsPerCurve * curveCount) + 1; // we have SegmentsPerCurve for each curve plus the origon point;
Vector2[] drawingPoints = new Vector2[finalPointCount];
int position = 0;
int targetPoint = controlPoints.Length - 3;
for (int i = 0; i < targetPoint; i += 3)
{
Vector2 p0 = controlPoints[i];
Vector2 p1 = controlPoints[i + 1];
Vector2 p2 = controlPoints[i + 2];
Vector2 p3 = controlPoints[i + 3];
// only do this for the first end point. When i != 0, this coincides with the end point of the previous segment,
if (i == 0)
{
drawingPoints[position++] = this.CalculateBezierPoint(0, p0, p1, p2, p3);
}
for (int j = 1; j <= SegmentsPerCurve; j++)
{
float t = j / (float)SegmentsPerCurve;
drawingPoints[position++] = this.CalculateBezierPoint(t, p0, p1, p2, p3);
}
}
return drawingPoints;
}
/// <summary>
/// Calculates the bezier point along the line.
/// </summary>
/// <param name="t">The position within the line.</param>
/// <param name="p0">The p 0.</param>
/// <param name="p1">The p 1.</param>
/// <param name="p2">The p 2.</param>
/// <param name="p3">The p 3.</param>
/// <returns>
/// The <see cref="Vector2"/>.
/// </returns>
private Vector2 CalculateBezierPoint(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
{
float u = 1 - t;
float tt = t * t;
float uu = u * u;
float uuu = uu * u;
float ttt = tt * t;
Vector2 p = uuu * p0; // first term
p += 3 * uu * t * p1; // second term
p += 3 * u * tt * p2; // third term
p += ttt * p3; // fourth term
return p;
}
}
}

21
src/ImageSharp.Drawing/Paths/ILineSegment.cs

@ -1,21 +0,0 @@
// <copyright file="ILineSegment.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System.Numerics;
/// <summary>
/// Represents a simple path segment
/// </summary>
public interface ILineSegment
{
/// <summary>
/// Converts the <see cref="ILineSegment" /> into a simple linear path..
/// </summary>
/// <returns>Returns the current <see cref="ILineSegment" /> as simple linear path.</returns>
Vector2[] AsSimpleLinearPath(); // TODO move this over to ReadonlySpan<Vector2> once available
}
}

48
src/ImageSharp.Drawing/Paths/IPath.cs

@ -1,48 +0,0 @@
// <copyright file="IPath.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System.Numerics;
/// <summary>
/// Represents a logic path that can be drawn
/// </summary>
public interface IPath : ILineSegment
{
/// <summary>
/// Gets the bounds enclosing the path
/// </summary>
/// <value>
/// The bounds.
/// </value>
RectangleF Bounds { get; }
/// <summary>
/// Gets a value indicating whether this instance is closed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is closed; otherwise, <c>false</c>.
/// </value>
bool IsClosed { get; }
/// <summary>
/// Gets the length of the path
/// </summary>
/// <value>
/// The length.
/// </value>
float Length { get; }
/// <summary>
/// Calculates the distance along and away from the path for a specified point.
/// </summary>
/// <param name="point">The point along the path.</param>
/// <returns>
/// Returns details about the point and its distance away from the path.
/// </returns>
PointInfo Distance(Vector2 point);
}
}

516
src/ImageSharp.Drawing/Paths/InternalPath.cs

@ -1,516 +0,0 @@
// <copyright file="InternalPath.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
/// <summary>
/// Internal logic for integrating linear paths.
/// </summary>
internal class InternalPath
{
/// <summary>
/// The maximum vector
/// </summary>
private static readonly Vector2 MaxVector = new Vector2(float.MaxValue);
/// <summary>
/// The locker.
/// </summary>
private static readonly object Locker = new object();
/// <summary>
/// The points.
/// </summary>
private readonly Vector2[] points;
/// <summary>
/// The closed path.
/// </summary>
private readonly bool closedPath;
/// <summary>
/// The total distance.
/// </summary>
private readonly Lazy<float> totalDistance;
/// <summary>
/// The constant.
/// </summary>
private float[] constant;
/// <summary>
/// The multiples.
/// </summary>
private float[] multiple;
/// <summary>
/// The distances.
/// </summary>
private float[] distance;
/// <summary>
/// The calculated.
/// </summary>
private bool calculated = false;
/// <summary>
/// Initializes a new instance of the <see cref="InternalPath"/> class.
/// </summary>
/// <param name="segments">The segments.</param>
/// <param name="isClosedPath">if set to <c>true</c> [is closed path].</param>
internal InternalPath(ILineSegment[] segments, bool isClosedPath)
: this(Simplify(segments), isClosedPath)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="InternalPath" /> class.
/// </summary>
/// <param name="segment">The segment.</param>
/// <param name="isClosedPath">if set to <c>true</c> [is closed path].</param>
internal InternalPath(ILineSegment segment, bool isClosedPath)
: this(segment.AsSimpleLinearPath(), isClosedPath)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="InternalPath" /> class.
/// </summary>
/// <param name="points">The points.</param>
/// <param name="isClosedPath">if set to <c>true</c> [is closed path].</param>
internal InternalPath(Vector2[] points, bool isClosedPath)
{
this.points = points;
this.closedPath = isClosedPath;
float minX = this.points.Min(x => x.X);
float maxX = this.points.Max(x => x.X);
float minY = this.points.Min(x => x.Y);
float maxY = this.points.Max(x => x.Y);
this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
this.totalDistance = new Lazy<float>(this.CalculateLength);
}
/// <summary>
/// Gets the bounds.
/// </summary>
/// <value>
/// The bounds.
/// </value>
public RectangleF Bounds
{
get;
}
/// <summary>
/// Gets the length.
/// </summary>
/// <value>
/// The length.
/// </value>
public float Length => this.totalDistance.Value;
/// <summary>
/// Gets the points.
/// </summary>
/// <value>
/// The points.
/// </value>
internal Vector2[] Points => this.points;
/// <summary>
/// Calculates the distance from the path.
/// </summary>
/// <param name="point">The point.</param>
/// <returns>Returns the distance from the path</returns>
public PointInfo DistanceFromPath(Vector2 point)
{
this.CalculateConstants();
PointInfoInternal internalInfo = default(PointInfoInternal);
internalInfo.DistanceSquared = float.MaxValue; // Set it to max so that CalculateShorterDistance can reduce it back down
int polyCorners = this.points.Length;
if (!this.closedPath)
{
polyCorners -= 1;
}
int closestPoint = 0;
for (int i = 0; i < polyCorners; i++)
{
int next = i + 1;
if (this.closedPath && next == polyCorners)
{
next = 0;
}
if (this.CalculateShorterDistance(this.points[i], this.points[next], point, ref internalInfo))
{
closestPoint = i;
}
}
return new PointInfo
{
DistanceAlongPath = this.distance[closestPoint] + Vector2.Distance(this.points[closestPoint], point),
DistanceFromPath = (float)Math.Sqrt(internalInfo.DistanceSquared),
SearchPoint = point,
ClosestPointOnPath = internalInfo.PointOnLine
};
}
/// <summary>
/// Based on a line described by <paramref name="start" /> and <paramref name="end" />
/// populate a buffer for all points on the path that the line intersects.
/// </summary>
/// <param name="start">The start.</param>
/// <param name="end">The end.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>number iof intersections hit</returns>
public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset)
{
int polyCorners = this.points.Length;
if (!this.closedPath)
{
polyCorners -= 1;
}
int position = 0;
for (int i = 0; i < polyCorners && count > 0; i++)
{
int next = i + 1;
if (this.closedPath && next == polyCorners)
{
next = 0;
}
Vector2 point = FindIntersection(this.points[i], this.points[next], start, end);
if (point != MaxVector)
{
buffer[position + offset] = point;
position++;
count--;
}
}
return position;
}
/// <summary>
/// Determines if the specified point is inside or outside the path.
/// </summary>
/// <param name="point">The point.</param>
/// <returns>Returns true if the point is inside the closed path.</returns>
public bool PointInPolygon(Vector2 point)
{
// You can only be inside a path if its "closed"
if (!this.closedPath)
{
return false;
}
if (!this.Bounds.Contains(point.X, point.Y))
{
return false;
}
this.CalculateConstants();
Vector2[] poly = this.points;
int polyCorners = poly.Length;
int j = polyCorners - 1;
bool oddNodes = false;
for (int i = 0; i < polyCorners; i++)
{
if ((poly[i].Y < point.Y && poly[j].Y >= point.Y)
|| (poly[j].Y < point.Y && poly[i].Y >= point.Y))
{
oddNodes ^= (point.Y * this.multiple[i]) + this.constant[i] < point.X;
}
j = i;
}
return oddNodes;
}
/// <summary>
/// Determins if the bounding box for 2 lines
/// described by <paramref name="line1Start" /> and <paramref name="line1End" />
/// and <paramref name="line2Start" /> and <paramref name="line2End" /> overlap.
/// </summary>
/// <param name="line1Start">The line1 start.</param>
/// <param name="line1End">The line1 end.</param>
/// <param name="line2Start">The line2 start.</param>
/// <param name="line2End">The line2 end.</param>
/// <returns>Returns true it the bounding box of the 2 lines intersect</returns>
private static bool BoundingBoxesIntersect(Vector2 line1Start, Vector2 line1End, Vector2 line2Start, Vector2 line2End)
{
Vector2 topLeft1 = Vector2.Min(line1Start, line1End);
Vector2 bottomRight1 = Vector2.Max(line1Start, line1End);
Vector2 topLeft2 = Vector2.Min(line2Start, line2End);
Vector2 bottomRight2 = Vector2.Max(line2Start, line2End);
float left1 = topLeft1.X;
float right1 = bottomRight1.X;
float top1 = topLeft1.Y;
float bottom1 = bottomRight1.Y;
float left2 = topLeft2.X;
float right2 = bottomRight2.X;
float top2 = topLeft2.Y;
float bottom2 = bottomRight2.Y;
return left1 <= right2 && right1 >= left2
&&
top1 <= bottom2 && bottom1 >= top2;
}
/// <summary>
/// Finds the point on line described by <paramref name="line1Start" /> and <paramref name="line1End" />
/// that intersects with line described by <paramref name="line2Start" /> and <paramref name="line2End" />
/// </summary>
/// <param name="line1Start">The line1 start.</param>
/// <param name="line1End">The line1 end.</param>
/// <param name="line2Start">The line2 start.</param>
/// <param name="line2End">The line2 end.</param>
/// <returns>
/// A <see cref="Vector2"/> describing the point that the 2 lines cross or <see cref="MaxVector"/> if they do not.
/// </returns>
private static Vector2 FindIntersection(Vector2 line1Start, Vector2 line1End, Vector2 line2Start, Vector2 line2End)
{
// do bounding boxes overlap, if not then the lines can't and return fast.
if (!BoundingBoxesIntersect(line1Start, line1End, line2Start, line2End))
{
return MaxVector;
}
Vector2 line1Diff = line1End - line1Start;
Vector2 line2Diff = line2End - line2Start;
Vector2 point;
if (line1Diff.X == 0)
{
float slope = line2Diff.Y / line2Diff.X;
float yinter = line2Start.Y - (slope * line2Start.X);
float y = (line1Start.X * slope) + yinter;
point = new Vector2(line1Start.X, y);
// horizontal and vertical lines
}
else if (line2Diff.X == 0)
{
float slope = line1Diff.Y / line1Diff.X;
float yinter = line1Start.Y - (slope * line1Start.X);
float y = (line2Start.X * slope) + yinter;
point = new Vector2(line2Start.X, y);
// horizontal and vertical lines
}
else
{
float slope1 = line1Diff.Y / line1Diff.X;
float slope2 = line2Diff.Y / line2Diff.X;
float yinter1 = line1Start.Y - (slope1 * line1Start.X);
float yinter2 = line2Start.Y - (slope2 * line2Start.X);
if (slope1 == slope2 && yinter1 != yinter2)
{
return MaxVector;
}
float x = (yinter2 - yinter1) / (slope1 - slope2);
float y = (slope1 * x) + yinter1;
point = new Vector2(x, y);
}
if (BoundingBoxesIntersect(line1Start, line1End, point, point))
{
return point;
}
else if (BoundingBoxesIntersect(line2Start, line2End, point, point))
{
return point;
}
return MaxVector;
}
/// <summary>
/// Simplifies the collection of segments.
/// </summary>
/// <param name="segments">The segments.</param>
/// <returns>
/// The <see cref="T:Vector2[]"/>.
/// </returns>
private static Vector2[] Simplify(ILineSegment[] segments)
{
List<Vector2> simplified = new List<Vector2>();
foreach (ILineSegment seg in segments)
{
simplified.AddRange(seg.AsSimpleLinearPath());
}
return simplified.ToArray();
}
/// <summary>
/// Returns the length of the path.
/// </summary>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
private float CalculateLength()
{
float length = 0;
int polyCorners = this.points.Length;
if (!this.closedPath)
{
polyCorners -= 1;
}
for (int i = 0; i < polyCorners; i++)
{
int next = i + 1;
if (this.closedPath && next == polyCorners)
{
next = 0;
}
length += Vector2.Distance(this.points[i], this.points[next]);
}
return length;
}
/// <summary>
/// Calculate the constants.
/// </summary>
private void CalculateConstants()
{
// http://alienryderflex.com/polygon/ source for point in polygon logic
if (this.calculated)
{
return;
}
lock (Locker)
{
if (this.calculated)
{
return;
}
Vector2[] poly = this.points;
int polyCorners = poly.Length;
this.constant = new float[polyCorners];
this.multiple = new float[polyCorners];
this.distance = new float[polyCorners];
int i, j = polyCorners - 1;
this.distance[0] = 0;
for (i = 0; i < polyCorners; i++)
{
this.distance[j] = this.distance[i] + Vector2.Distance(poly[i], poly[j]);
if (poly[j].Y == poly[i].Y)
{
this.constant[i] = poly[i].X;
this.multiple[i] = 0;
}
else
{
Vector2 subtracted = poly[j] - poly[i];
this.constant[i] = (poly[i].X - ((poly[i].Y * poly[j].X) / subtracted.Y)) + ((poly[i].Y * poly[i].X) / subtracted.Y);
this.multiple[i] = subtracted.X / subtracted.Y;
}
j = i;
}
this.calculated = true;
}
}
/// <summary>
/// Calculate any shorter distances along the path.
/// </summary>
/// <param name="start">The start position.</param>
/// <param name="end">The end position.</param>
/// <param name="point">The current point.</param>
/// <param name="info">The info.</param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
private bool CalculateShorterDistance(Vector2 start, Vector2 end, Vector2 point, ref PointInfoInternal info)
{
Vector2 diffEnds = end - start;
float lengthSquared = diffEnds.LengthSquared();
Vector2 diff = point - start;
Vector2 multiplied = diff * diffEnds;
float u = (multiplied.X + multiplied.Y) / lengthSquared;
if (u > 1)
{
u = 1;
}
else if (u < 0)
{
u = 0;
}
Vector2 multipliedByU = diffEnds * u;
Vector2 pointOnLine = start + multipliedByU;
Vector2 d = pointOnLine - point;
float dist = d.LengthSquared();
if (info.DistanceSquared > dist)
{
info.DistanceSquared = dist;
info.PointOnLine = pointOnLine;
return true;
}
return false;
}
/// <summary>
/// Contains information about the current point.
/// </summary>
private struct PointInfoInternal
{
/// <summary>
/// The distance squared.
/// </summary>
public float DistanceSquared;
/// <summary>
/// The point on the current line.
/// </summary>
public Vector2 PointOnLine;
}
}
}

55
src/ImageSharp.Drawing/Paths/LinearLineSegment.cs

@ -1,55 +0,0 @@
// <copyright file="LinearLineSegment.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System.Linq;
using System.Numerics;
/// <summary>
/// Represents a series of control points that will be joined by straight lines
/// </summary>
/// <seealso cref="ILineSegment" />
public class LinearLineSegment : ILineSegment
{
/// <summary>
/// The collection of points.
/// </summary>
private readonly Vector2[] points;
/// <summary>
/// Initializes a new instance of the <see cref="LinearLineSegment"/> class.
/// </summary>
/// <param name="start">The start.</param>
/// <param name="end">The end.</param>
public LinearLineSegment(Vector2 start, Vector2 end)
: this(new[] { start, end })
{
}
/// <summary>
/// Initializes a new instance of the <see cref="LinearLineSegment"/> class.
/// </summary>
/// <param name="points">The points.</param>
public LinearLineSegment(params Vector2[] points)
{
Guard.NotNull(points, nameof(points));
Guard.MustBeGreaterThanOrEqualTo(points.Count(), 2, nameof(points));
this.points = points;
}
/// <summary>
/// Converts the <see cref="ILineSegment" /> into a simple linear path..
/// </summary>
/// <returns>
/// Returns the current <see cref="ILineSegment" /> as simple linear path.
/// </returns>
public Vector2[] AsSimpleLinearPath()
{
return this.points;
}
}
}

51
src/ImageSharp.Drawing/Paths/Path.cs

@ -1,51 +0,0 @@
// <copyright file="Path.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System.Numerics;
/// <summary>
/// A aggregate of <see cref="ILineSegment"/>s making a single logical path
/// </summary>
/// <seealso cref="IPath" />
public class Path : IPath
{
/// <summary>
/// The inner path.
/// </summary>
private readonly InternalPath innerPath;
/// <summary>
/// Initializes a new instance of the <see cref="Path"/> class.
/// </summary>
/// <param name="segment">The segment.</param>
public Path(params ILineSegment[] segment)
{
this.innerPath = new InternalPath(segment, false);
}
/// <inheritdoc />
public RectangleF Bounds => this.innerPath.Bounds;
/// <inheritdoc />
public bool IsClosed => false;
/// <inheritdoc />
public float Length => this.innerPath.Length;
/// <inheritdoc />
public Vector2[] AsSimpleLinearPath()
{
return this.innerPath.Points;
}
/// <inheritdoc />
public PointInfo Distance(Vector2 point)
{
return this.innerPath.DistanceFromPath(point);
}
}
}

35
src/ImageSharp.Drawing/Paths/PointInfo.cs

@ -1,35 +0,0 @@
// <copyright file="PointInfo.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Paths
{
using System.Numerics;
/// <summary>
/// Returns meta data about the nearest point on a path from a vector
/// </summary>
public struct PointInfo
{
/// <summary>
/// The search point
/// </summary>
public Vector2 SearchPoint;
/// <summary>
/// The distance along path <see cref="ClosestPointOnPath"/> is away from the start of the path
/// </summary>
public float DistanceAlongPath;
/// <summary>
/// The distance <see cref="SearchPoint"/> is away from <see cref="ClosestPointOnPath"/>.
/// </summary>
public float DistanceFromPath;
/// <summary>
/// The closest point to <see cref="SearchPoint"/> that lies on the path.
/// </summary>
public Vector2 ClosestPointOnPath;
}
}

2
src/ImageSharp.Drawing/Pens/IPen.cs

@ -13,7 +13,7 @@ namespace ImageSharp.Drawing.Pens
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
public interface IPen<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Creates the applicator for applying this pen to an Image

2
src/ImageSharp.Drawing/Pens/Pens{TColor}.cs

@ -12,7 +12,7 @@ namespace ImageSharp.Drawing.Pens
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
public class Pens<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
private static readonly float[] DashDotPattern = new[] { 3f, 1f, 1f, 1f };
private static readonly float[] DashDotDotPattern = new[] { 3f, 1f, 1f, 1f, 1f, 1f };

11
src/ImageSharp.Drawing/Pens/Pen{TColor}.cs

@ -9,7 +9,6 @@ namespace ImageSharp.Drawing.Pens
using System.Numerics;
using ImageSharp.Drawing.Brushes;
using ImageSharp.Drawing.Paths;
using Processors;
/// <summary>
@ -25,7 +24,7 @@ namespace ImageSharp.Drawing.Pens
/// the the pattern will imidiatly repeat without gap.
/// </remarks>
public class Pen<TColor> : IPen<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
private static readonly float[] EmptyPattern = new float[0];
private readonly float[] pattern;
@ -145,10 +144,10 @@ namespace ImageSharp.Drawing.Pens
this.brush.Dispose();
}
public override ColoredPointInfo<TColor> GetColor(PointInfo info)
public override ColoredPointInfo<TColor> GetColor(int x, int y, PointInfo info)
{
var result = default(ColoredPointInfo<TColor>);
result.Color = this.brush.GetColor(info.SearchPoint);
result.Color = this.brush[x, y];
if (info.DistanceFromPath < this.halfWidth)
{
@ -198,7 +197,7 @@ namespace ImageSharp.Drawing.Pens
this.brush.Dispose();
}
public override ColoredPointInfo<TColor> GetColor(PointInfo info)
public override ColoredPointInfo<TColor> GetColor(int x, int y, PointInfo info)
{
var infoResult = default(ColoredPointInfo<TColor>);
infoResult.DistanceFromElement = float.MaxValue; // is really outside the element
@ -208,7 +207,7 @@ namespace ImageSharp.Drawing.Pens
// we can treat the DistanceAlongPath and DistanceFromPath as x,y coords for the pattern
// we need to calcualte the distance from the outside edge of the pattern
// and set them on the ColoredPointInfo<TColor> along with the color.
infoResult.Color = this.brush.GetColor(info.SearchPoint);
infoResult.Color = this.brush[x, y];
float distanceWAway = 0;

2
src/ImageSharp.Drawing/Pens/Processors/ColoredPointInfo.cs

@ -12,7 +12,7 @@ namespace ImageSharp.Drawing.Processors
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
public struct ColoredPointInfo<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The color

16
src/ImageSharp.Drawing/Pens/Processors/PenApplicator.cs

@ -6,14 +6,14 @@
namespace ImageSharp.Drawing.Processors
{
using System;
using Paths;
using System.Numerics;
/// <summary>
/// primitive that converts a <see cref="PointInfo"/> into a color and a distance away from the drawable part of the path.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
public abstract class PenApplicator<TColor> : IDisposable
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Gets the required region.
@ -23,16 +23,18 @@ namespace ImageSharp.Drawing.Processors
/// </value>
public abstract RectangleF RequiredRegion { get; }
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <inheritdoc/>
public abstract void Dispose();
/// <summary>
/// Gets a <see cref="ColoredPointInfo{TColor}" /> from a point represented by a <see cref="PointInfo" />.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="info">The information to extract color details about.</param>
/// <returns>Returns the color details and distance from a solid bit of the line.</returns>
public abstract ColoredPointInfo<TColor> GetColor(PointInfo info);
/// <returns>
/// Returns the color details and distance from a solid bit of the line.
/// </returns>
public abstract ColoredPointInfo<TColor> GetColor(int x, int y, PointInfo info);
}
}

23
src/ImageSharp.Drawing/PointInfo.cs

@ -0,0 +1,23 @@
// <copyright file="PointInfo.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
/// <summary>
/// Returns details about how far away from the inside of a shape and the color the pixel could be.
/// </summary>
public struct PointInfo
{
/// <summary>
/// The distance along path
/// </summary>
public float DistanceAlongPath;
/// <summary>
/// The distance from path
/// </summary>
public float DistanceFromPath;
}
}

2
src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs

@ -16,7 +16,7 @@ namespace ImageSharp.Drawing.Processors
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public class DrawImageProcessor<TColor> : ImageProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TColor}"/> class.

142
src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs

@ -6,14 +6,11 @@
namespace ImageSharp.Drawing.Processors
{
using System;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Processing;
using Paths;
using Pens;
using Shapes;
using Rectangle = ImageSharp.Rectangle;
/// <summary>
/// Draws a path using the processor pipeline
@ -21,72 +18,46 @@ namespace ImageSharp.Drawing.Processors
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <seealso cref="ImageSharp.Processing.ImageProcessor{TColor}" />
public class DrawPathProcessor<TColor> : ImageProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
private const float AntialiasFactor = 1f;
private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor
private readonly IPen<TColor> pen;
private readonly IPath[] paths;
private readonly RectangleF region;
private readonly GraphicsOptions options;
/// <summary>
/// Initializes a new instance of the <see cref="DrawPathProcessor{TColor}" /> class.
/// </summary>
/// <param name="pen">The pen.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
public DrawPathProcessor(IPen<TColor> pen, IShape shape, GraphicsOptions options)
: this(pen, shape.ToArray(), options)
/// <param name="pen">The details how to draw the outline/path.</param>
/// <param name="drawable">The details of the paths and outlines to draw.</param>
/// <param name="options">The drawing configuration options.</param>
public DrawPathProcessor(IPen<TColor> pen, Drawable drawable, GraphicsOptions options)
{
this.Path = drawable;
this.Pen = pen;
this.Options = options;
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawPathProcessor{TColor}"/> class.
/// Gets the graphics options.
/// </summary>
/// <param name="pen">The pen.</param>
/// <param name="path">The path.</param>
/// <param name="options">The options.</param>
public DrawPathProcessor(IPen<TColor> pen, IPath path, GraphicsOptions options)
: this(pen, new[] { path }, options)
{
}
public GraphicsOptions Options { get; }
/// <summary>
/// Initializes a new instance of the <see cref="DrawPathProcessor{TColor}" /> class.
/// Gets the pen.
/// </summary>
/// <param name="pen">The pen.</param>
/// <param name="paths">The paths.</param>
/// <param name="options">The options.</param>
public DrawPathProcessor(IPen<TColor> pen, IPath[] paths, GraphicsOptions options)
{
this.paths = paths;
this.pen = pen;
this.options = options;
if (paths.Length != 1)
{
var maxX = paths.Max(x => x.Bounds.Right);
var minX = paths.Min(x => x.Bounds.Left);
var maxY = paths.Max(x => x.Bounds.Bottom);
var minY = paths.Min(x => x.Bounds.Top);
public IPen<TColor> Pen { get; }
this.region = new RectangleF(minX, minY, maxX - minX, maxY - minY);
}
else
{
this.region = paths[0].Bounds;
}
}
/// <summary>
/// Gets the path.
/// </summary>
public Drawable Path { get; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TColor> source, Rectangle sourceRectangle)
{
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PenApplicator<TColor> applicator = this.pen.CreateApplicator(sourcePixels, this.region))
using (PenApplicator<TColor> applicator = this.Pen.CreateApplicator(sourcePixels, this.Path.Bounds))
{
var rect = RectangleF.Ceiling(applicator.RequiredRegion);
Rectangle rect = RectangleF.Ceiling(applicator.RequiredRegion);
int polyStartY = rect.Y - PaddingFactor;
int polyEndY = rect.Bottom + PaddingFactor;
@ -116,69 +87,52 @@ namespace ImageSharp.Drawing.Processors
}
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
{
int offsetY = y - polyStartY;
var currentPoint = default(Vector2);
for (int x = minX; x < maxX; x++)
minY,
maxY,
this.ParallelOptions,
y =>
{
int offsetX = x - startX;
currentPoint.X = offsetX;
currentPoint.Y = offsetY;
int offsetY = y - polyStartY;
var dist = this.Closest(currentPoint);
var color = applicator.GetColor(dist);
var opacity = this.Opacity(color.DistanceFromElement);
if (opacity > Constants.Epsilon)
for (int x = minX; x < maxX; x++)
{
int offsetColorX = x - minX;
// TODO add find intersections code to skip and scan large regions of this.
int offsetX = x - startX;
PointInfo info = this.Path.GetPointInfo(offsetX, offsetY);
Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4();
Vector4 sourceVector = color.Color.ToVector4();
ColoredPointInfo<TColor> color = applicator.GetColor(offsetX, offsetY, info);
var finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
finalColor.W = backgroundVector.W;
float opacity = this.Opacity(color.DistanceFromElement);
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
sourcePixels[offsetX, offsetY] = packed;
}
}
});
}
}
if (opacity > Constants.Epsilon)
{
Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4();
Vector4 sourceVector = color.Color.ToVector4();
private PointInfo Closest(Vector2 point)
{
PointInfo result = default(PointInfo);
float distance = float.MaxValue;
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
for (int i = 0; i < this.paths.Length; i++)
{
var p = this.paths[i].Distance(point);
if (p.DistanceFromPath < distance)
{
distance = p.DistanceFromPath;
result = p;
}
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
sourcePixels[offsetX, offsetY] = packed;
}
}
});
}
return result;
}
/// <summary>
/// Returns the correct opacity for the given distance.
/// </summary>
/// <param name="distance">Thw distance from the central point.</param>
/// <returns>The <see cref="float"/></returns>
private float Opacity(float distance)
{
if (distance <= 0)
{
return 1;
}
else if (this.options.Antialias && distance < AntialiasFactor)
if (this.Options.Antialias && distance < AntialiasFactor)
{
return 1 - (distance / AntialiasFactor);
}

9
src/ImageSharp.Drawing/Processors/FillProcessor.cs

@ -17,7 +17,7 @@ namespace ImageSharp.Drawing.Processors
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public class FillProcessor<TColor> : ImageProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The brush.
@ -71,17 +71,12 @@ namespace ImageSharp.Drawing.Processors
y =>
{
int offsetY = y - startY;
Vector2 currentPoint = default(Vector2);
for (int x = minX; x < maxX; x++)
{
int offsetX = x - startX;
int offsetColorX = x - minX;
currentPoint.X = offsetX;
currentPoint.Y = offsetY;
Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 sourceVector = applicator[offsetX, offsetY].ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, 1);

204
src/ImageSharp.Drawing/Processors/FillShapeProcessor.cs → src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs

@ -1,4 +1,4 @@
// <copyright file="FillShapeProcessor.cs" company="James Jackson-South">
// <copyright file="FillRegionProcessor.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -11,45 +11,58 @@ namespace ImageSharp.Drawing.Processors
using System.Threading.Tasks;
using Drawing;
using ImageSharp.Processing;
using Shapes;
using Rectangle = ImageSharp.Rectangle;
/// <summary>
/// Usinf a brsuh and a shape fills shape with contents of brush the
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
/// <seealso cref="ImageSharp.Processing.ImageProcessor{TColor}" />
public class FillShapeProcessor<TColor> : ImageProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
public class FillRegionProcessor<TColor> : ImageProcessor<TColor>
where TColor : struct, IPixel<TColor>
{
private const float AntialiasFactor = 1f;
private const int DrawPadding = 1;
private readonly IBrush<TColor> fillColor;
private readonly IShape poly;
private readonly GraphicsOptions options;
/// <summary>
/// Initializes a new instance of the <see cref="FillShapeProcessor{TColor}"/> class.
/// Initializes a new instance of the <see cref="FillRegionProcessor{TColor}" /> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="shape">The shape.</param>
/// <param name="options">The options.</param>
public FillShapeProcessor(IBrush<TColor> brush, IShape shape, GraphicsOptions options)
/// <param name="brush">The details how to fill the region of interest.</param>
/// <param name="region">The region of interest to be filled.</param>
/// <param name="options">The configuration options.</param>
public FillRegionProcessor(IBrush<TColor> brush, Region region, GraphicsOptions options)
{
this.poly = shape;
this.fillColor = brush;
this.options = options;
this.Region = region;
this.Brush = brush;
this.Options = options;
}
/// <summary>
/// Gets the brush.
/// </summary>
public IBrush<TColor> Brush { get; }
/// <summary>
/// Gets the region that this processor applies to.
/// </summary>
public Region Region { get; }
/// <summary>
/// Gets the options.
/// </summary>
/// <value>
/// The options.
/// </value>
public GraphicsOptions Options { get; }
/// <inheritdoc/>
protected override void OnApply(ImageBase<TColor> source, Rectangle sourceRectangle)
{
Rectangle rect = RectangleF.Ceiling(this.poly.Bounds); // rounds the points out away from the center
Rectangle rect = this.Region.Bounds;
int polyStartY = rect.Y - DrawPadding;
int polyEndY = rect.Bottom + DrawPadding;
int startX = rect.X - DrawPadding;
int endX = rect.Right + DrawPadding;
int polyStartY = sourceRectangle.Y - DrawPadding;
int polyEndY = sourceRectangle.Bottom + DrawPadding;
int startX = sourceRectangle.X - DrawPadding;
int endX = sourceRectangle.Right + DrawPadding;
int minX = Math.Max(sourceRectangle.Left, startX);
int maxX = Math.Min(sourceRectangle.Right - 1, endX);
@ -62,53 +75,47 @@ namespace ImageSharp.Drawing.Processors
minY = Math.Max(0, minY);
maxY = Math.Min(source.Height, maxY);
ArrayPool<Vector2> arrayPool = ArrayPool<Vector2>.Shared;
ArrayPool<float> arrayPool = ArrayPool<float>.Shared;
int maxIntersections = this.poly.MaxIntersections;
int maxIntersections = this.Region.MaxIntersections;
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (BrushApplicator<TColor> applicator = this.fillColor.CreateApplicator(sourcePixels, rect))
using (BrushApplicator<TColor> applicator = this.Brush.CreateApplicator(sourcePixels, rect))
{
Parallel.For(
minY,
maxY,
this.ParallelOptions,
y =>
(int y) =>
{
Vector2[] buffer = arrayPool.Rent(maxIntersections);
float[] buffer = arrayPool.Rent(maxIntersections);
try
{
Vector2 left = new Vector2(startX, y);
Vector2 right = new Vector2(endX, y);
float right = endX;
// foreach line we get all the points where this line crosses the polygon
int pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0);
int pointsFound = this.Region.ScanY(y, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
// nothign on this line skip
// nothing on this line skip
return;
}
QuickSortX(buffer, pointsFound);
QuickSort(buffer, pointsFound);
int currentIntersection = 0;
float nextPoint = buffer[0].X;
float nextPoint = buffer[0];
float lastPoint = float.MinValue;
bool isInside = false;
// every odd point is the start of a line
Vector2 currentPoint = default(Vector2);
for (int x = minX; x < maxX; x++)
{
currentPoint.X = x;
currentPoint.Y = y;
if (!isInside)
{
if (x < (nextPoint - DrawPadding) && x > (lastPoint + DrawPadding))
{
if (nextPoint == right.X)
if (nextPoint == right)
{
// we are in the ends run skip it
x = maxX;
@ -129,11 +136,11 @@ namespace ImageSharp.Drawing.Processors
lastPoint = nextPoint;
if (currentIntersection == pointsFound)
{
nextPoint = right.X;
nextPoint = right;
}
else
{
nextPoint = buffer[currentIntersection].X;
nextPoint = buffer[currentIntersection];
// double point from a corner flip the bit back and move on again
if (nextPoint == lastPoint)
@ -143,11 +150,11 @@ namespace ImageSharp.Drawing.Processors
currentIntersection++;
if (currentIntersection == pointsFound)
{
nextPoint = right.X;
nextPoint = right;
}
else
{
nextPoint = buffer[currentIntersection].X;
nextPoint = buffer[currentIntersection];
}
}
}
@ -158,7 +165,7 @@ namespace ImageSharp.Drawing.Processors
float opacity = 1;
if (!isInside && !onCorner)
{
if (this.options.Antialias)
if (this.Options.Antialias)
{
float distance = float.MaxValue;
if (x == lastPoint || x == nextPoint)
@ -192,10 +199,9 @@ namespace ImageSharp.Drawing.Processors
if (opacity > Constants.Epsilon)
{
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 sourceVector = applicator[x, y].ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
finalColor.W = backgroundVector.W;
TColor packed = default(TColor);
packed.PackFromVector4(finalColor);
@ -209,49 +215,44 @@ namespace ImageSharp.Drawing.Processors
}
});
if (this.options.Antialias)
if (this.Options.Antialias)
{
// we only need to do the X can for antialiasing purposes
Parallel.For(
minX,
maxX,
this.ParallelOptions,
x =>
(int x) =>
{
Vector2[] buffer = arrayPool.Rent(maxIntersections);
float[] buffer = arrayPool.Rent(maxIntersections);
try
{
Vector2 left = new Vector2(x, polyStartY);
Vector2 right = new Vector2(x, polyEndY);
float left = polyStartY;
float right = polyEndY;
// foreach line we get all the points where this line crosses the polygon
int pointsFound = this.poly.FindIntersections(left, right, buffer, maxIntersections, 0);
int pointsFound = this.Region.ScanX(x, buffer, maxIntersections, 0);
if (pointsFound == 0)
{
// nothign on this line skip
return;
}
QuickSortY(buffer, pointsFound);
QuickSort(buffer, pointsFound);
int currentIntersection = 0;
float nextPoint = buffer[0].Y;
float lastPoint = left.Y;
float nextPoint = buffer[0];
float lastPoint = left;
bool isInside = false;
// every odd point is the start of a line
Vector2 currentPoint = default(Vector2);
for (int y = minY; y < maxY; y++)
{
currentPoint.X = x;
currentPoint.Y = y;
if (!isInside)
{
if (y < (nextPoint - DrawPadding) && y > (lastPoint + DrawPadding))
{
if (nextPoint == right.Y)
if (nextPoint == right)
{
// we are in the ends run skip it
y = maxY;
@ -266,7 +267,7 @@ namespace ImageSharp.Drawing.Processors
{
if (y < nextPoint - DrawPadding)
{
if (nextPoint == right.Y)
if (nextPoint == right)
{
// we are in the ends run skip it
y = maxY;
@ -286,11 +287,11 @@ namespace ImageSharp.Drawing.Processors
lastPoint = nextPoint;
if (currentIntersection == pointsFound)
{
nextPoint = right.Y;
nextPoint = right;
}
else
{
nextPoint = buffer[currentIntersection].Y;
nextPoint = buffer[currentIntersection];
// double point from a corner flip the bit back and move on again
if (nextPoint == lastPoint)
@ -300,11 +301,11 @@ namespace ImageSharp.Drawing.Processors
currentIntersection++;
if (currentIntersection == pointsFound)
{
nextPoint = right.Y;
nextPoint = right;
}
else
{
nextPoint = buffer[currentIntersection].Y;
nextPoint = buffer[currentIntersection];
}
}
}
@ -315,7 +316,7 @@ namespace ImageSharp.Drawing.Processors
float opacity = 1;
if (!isInside && !onCorner)
{
if (this.options.Antialias)
if (this.Options.Antialias)
{
float distance = float.MaxValue;
if (y == lastPoint || y == nextPoint)
@ -350,8 +351,7 @@ namespace ImageSharp.Drawing.Processors
if (opacity > Constants.Epsilon && opacity < 1)
{
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();
Vector4 sourceVector = applicator[x, y].ToVector4();
Vector4 finalColor = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, opacity);
finalColor.W = backgroundVector.W;
@ -370,76 +370,32 @@ namespace ImageSharp.Drawing.Processors
}
}
private static void Swap(Vector2[] data, int left, int right)
private static void Swap(float[] data, int left, int right)
{
Vector2 tmp = data[left];
float tmp = data[left];
data[left] = data[right];
data[right] = tmp;
}
private static void QuickSortY(Vector2[] data, int size)
private static void QuickSort(float[] data, int size)
{
int hi = Math.Min(data.Length - 1, size - 1);
QuickSortY(data, 0, hi);
QuickSort(data, 0, hi);
}
private static void QuickSortY(Vector2[] data, int lo, int hi)
private static void QuickSort(float[] data, int lo, int hi)
{
if (lo < hi)
{
int p = PartitionY(data, lo, hi);
QuickSortY(data, lo, p);
QuickSortY(data, p + 1, hi);
}
}
private static void QuickSortX(Vector2[] data, int size)
{
int hi = Math.Min(data.Length - 1, size - 1);
QuickSortX(data, 0, hi);
}
private static void QuickSortX(Vector2[] data, int lo, int hi)
{
if (lo < hi)
{
int p = PartitionX(data, lo, hi);
QuickSortX(data, lo, p);
QuickSortX(data, p + 1, hi);
}
}
private static int PartitionX(Vector2[] data, int lo, int hi)
{
float pivot = data[lo].X;
int i = lo - 1;
int j = hi + 1;
while (true)
{
do
{
i = i + 1;
}
while (data[i].X < pivot && i < hi);
do
{
j = j - 1;
}
while (data[j].X > pivot && j > lo);
if (i >= j)
{
return j;
}
Swap(data, i, j);
int p = Partition(data, lo, hi);
QuickSort(data, lo, p);
QuickSort(data, p + 1, hi);
}
}
private static int PartitionY(Vector2[] data, int lo, int hi)
private static int Partition(float[] data, int lo, int hi)
{
float pivot = data[lo].Y;
float pivot = data[lo];
int i = lo - 1;
int j = hi + 1;
while (true)
@ -448,13 +404,13 @@ namespace ImageSharp.Drawing.Processors
{
i = i + 1;
}
while (data[i].Y < pivot && i < hi);
while (data[i] < pivot && i < hi);
do
{
j = j - 1;
}
while (data[j].Y > pivot && j > lo);
while (data[j] > pivot && j > lo);
if (i >= j)
{

46
src/ImageSharp.Drawing/Region.cs

@ -0,0 +1,46 @@
// <copyright file="Region.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing
{
/// <summary>
/// Represents a region of an image.
/// </summary>
public abstract class Region
{
/// <summary>
/// Gets the maximum number of intersections to could be returned.
/// </summary>
public abstract int MaxIntersections { get; }
/// <summary>
/// Gets the bounding box that entirely surrounds this region.
/// </summary>
/// <remarks>
/// This should always contains all possible points returned from either <see cref="ScanX(int, float[], int, int)"/> or <see cref="ScanY(int, float[], int, int)"/>.
/// </remarks>
public abstract Rectangle Bounds { get; }
/// <summary>
/// Scans the X axis for intersections.
/// </summary>
/// <param name="x">The position along the X axis to find intersections.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="length">The length.</param>
/// <param name="offset">The offset.</param>
/// <returns>The number of intersections found.</returns>
public abstract int ScanX(int x, float[] buffer, int length, int offset);
/// <summary>
/// Scans the Y axis for intersections.
/// </summary>
/// <param name="y">The position along the y axis to find intersections.</param>
/// <param name="buffer">The buffer.</param>
/// <param name="length">The length.</param>
/// <param name="offset">The offset.</param>
/// <returns>The number of intersections found.</returns>
public abstract int ScanY(int y, float[] buffer, int length, int offset);
}
}

93
src/ImageSharp.Drawing/Shapes/BezierPolygon.cs

@ -1,93 +0,0 @@
// <copyright file="BezierPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes
{
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using Paths;
/// <summary>
/// Represents a polygon made up exclusivly of a single close cubic Bezier curve.
/// </summary>
public sealed class BezierPolygon : IShape
{
private Polygon innerPolygon;
/// <summary>
/// Initializes a new instance of the <see cref="BezierPolygon"/> class.
/// </summary>
/// <param name="points">The points.</param>
public BezierPolygon(params Vector2[] points)
{
this.innerPolygon = new Polygon(new BezierLineSegment(points));
}
/// <summary>
/// Gets the bounding box of this shape.
/// </summary>
/// <value>
/// The bounds.
/// </value>
public RectangleF Bounds => this.innerPolygon.Bounds;
/// <summary>
/// Gets the maximum number intersections that a shape can have when testing a line.
/// </summary>
/// <value>
/// The maximum intersections.
/// </value>
public int MaxIntersections => this.innerPolygon.MaxIntersections;
/// <summary>
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
/// </summary>
/// <param name="point">The point.</param>
/// <returns>
/// The distance from the shape.
/// </returns>
public float Distance(Vector2 point) => this.innerPolygon.Distance(point);
/// <summary>
/// Based on a line described by <paramref name="start"/> and <paramref name="end"/>
/// populate a buffer for all points on the polygon that the line intersects.
/// </summary>
/// <param name="start">The start point of the line.</param>
/// <param name="end">The end point of the line.</param>
/// <param name="buffer">The buffer that will be populated with intersections.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>
/// The number of intersections populated into the buffer.
/// </returns>
public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset)
{
return this.innerPolygon.FindIntersections(start, end, buffer, count, offset);
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<IPath> GetEnumerator()
{
return this.innerPolygon.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.innerPolygon.GetEnumerator();
}
}
}

246
src/ImageSharp.Drawing/Shapes/ComplexPolygon.cs

@ -1,246 +0,0 @@
// <copyright file="ComplexPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Paths;
using PolygonClipper;
/// <summary>
/// Represents a complex polygon made up of one or more outline
/// polygons and one or more holes to punch out of them.
/// </summary>
/// <seealso cref="ImageSharp.Drawing.Shapes.IShape" />
public sealed class ComplexPolygon : IShape
{
private const float ClipperScaleFactor = 100f;
private IShape[] shapes;
private IEnumerable<IPath> paths;
/// <summary>
/// Initializes a new instance of the <see cref="ComplexPolygon"/> class.
/// </summary>
/// <param name="outline">The outline.</param>
/// <param name="holes">The holes.</param>
public ComplexPolygon(IShape outline, params IShape[] holes)
: this(new[] { outline }, holes)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ComplexPolygon"/> class.
/// </summary>
/// <param name="outlines">The outlines.</param>
/// <param name="holes">The holes.</param>
public ComplexPolygon(IShape[] outlines, IShape[] holes)
{
Guard.NotNull(outlines, nameof(outlines));
Guard.MustBeGreaterThanOrEqualTo(outlines.Length, 1, nameof(outlines));
this.MaxIntersections = this.FixAndSetShapes(outlines, holes);
float minX = this.shapes.Min(x => x.Bounds.Left);
float maxX = this.shapes.Max(x => x.Bounds.Right);
float minY = this.shapes.Min(x => x.Bounds.Top);
float maxY = this.shapes.Max(x => x.Bounds.Bottom);
this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
}
/// <summary>
/// Gets the bounding box of this shape.
/// </summary>
/// <value>
/// The bounds.
/// </value>
public RectangleF Bounds { get; }
/// <summary>
/// Gets the maximum number intersections that a shape can have when testing a line.
/// </summary>
/// <value>
/// The maximum intersections.
/// </value>
public int MaxIntersections { get; }
/// <summary>
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
/// </summary>
/// <param name="point">The point.</param>
/// <returns>
/// Returns the distance from thr shape to the point
/// </returns>
/// <remarks>
/// Due to the clipping we did during construction we know that out shapes do not overlap at there edges
/// therefore for apoint to be in more that one we must be in a hole of another, theoretically this could
/// then flip again to be in a outlin inside a hole inside an outline :)
/// </remarks>
float IShape.Distance(Vector2 point)
{
float dist = float.MaxValue;
bool inside = false;
foreach (IShape shape in this.shapes)
{
float d = shape.Distance(point);
if (d <= 0)
{
// we are inside a poly
d = -d; // flip the sign
inside ^= true; // flip the inside flag
}
if (d < dist)
{
dist = d;
}
}
if (inside)
{
return -dist;
}
return dist;
}
/// <summary>
/// Based on a line described by <paramref name="start"/> and <paramref name="end"/>
/// populate a buffer for all points on all the polygons, that make up this complex shape,
/// that the line intersects.
/// </summary>
/// <param name="start">The start point of the line.</param>
/// <param name="end">The end point of the line.</param>
/// <param name="buffer">The buffer that will be populated with intersections.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>
/// The number of intersections populated into the buffer.
/// </returns>
public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset)
{
int totalAdded = 0;
for (int i = 0; i < this.shapes.Length; i++)
{
int added = this.shapes[i].FindIntersections(start, end, buffer, count, offset);
count -= added;
offset += added;
totalAdded += added;
}
return totalAdded;
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<IPath> GetEnumerator()
{
return this.paths.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
private void AddPoints(Clipper clipper, IShape shape, PolyType polyType)
{
// if the path is already the shape use it directly and skip the path loop.
if (shape is IPath)
{
clipper.AddPath(
(IPath)shape,
polyType);
}
else
{
foreach (IPath path in shape)
{
clipper.AddPath(
path,
polyType);
}
}
}
private void AddPoints(Clipper clipper, IEnumerable<IShape> shapes, PolyType polyType)
{
foreach (IShape shape in shapes)
{
this.AddPoints(clipper, shape, polyType);
}
}
private void ExtractOutlines(PolyNode tree, List<IShape> shapes, List<IPath> paths)
{
if (tree.Contour.Any())
{
// if the source path is set then we clipper retained the full path intact thus we can freely
// use it and get any shape optimisations that are availible.
if (tree.SourcePath != null)
{
shapes.Add((IShape)tree.SourcePath);
paths.Add(tree.SourcePath);
}
else
{
// convert the Clipper Contour from scaled ints back down to the origional size (this is going to be lossy but not significantly)
Polygon polygon = new Polygon(new Paths.LinearLineSegment(tree.Contour.ToArray()));
shapes.Add(polygon);
paths.Add(polygon);
}
}
foreach (PolyNode c in tree.Children)
{
this.ExtractOutlines(c, shapes, paths);
}
}
private int FixAndSetShapes(IEnumerable<IShape> outlines, IEnumerable<IShape> holes)
{
Clipper clipper = new Clipper();
// add the outlines and the holes to clipper, scaling up from the float source to the int based system clipper uses
this.AddPoints(clipper, outlines, PolyType.Subject);
this.AddPoints(clipper, holes, PolyType.Clip);
PolyTree tree = clipper.Execute();
List<IShape> shapes = new List<IShape>();
List<IPath> paths = new List<IPath>();
// convert the 'tree' back to paths
this.ExtractOutlines(tree, shapes, paths);
this.shapes = shapes.ToArray();
this.paths = paths.ToArray();
int intersections = 0;
foreach (IShape s in this.shapes)
{
intersections += s.MaxIntersections;
}
return intersections;
}
}
}

56
src/ImageSharp.Drawing/Shapes/IShape.cs

@ -1,56 +0,0 @@
// <copyright file="IShape.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes
{
using System.Collections.Generic;
using System.Numerics;
using Paths;
/// <summary>
/// Represents a closed set of paths making up a single shape.
/// </summary>
public interface IShape : IEnumerable<IPath>
{
/// <summary>
/// Gets the bounding box of this shape.
/// </summary>
/// <value>
/// The bounds.
/// </value>
RectangleF Bounds { get; }
/// <summary>
/// Gets the maximum number intersections that a shape can have when testing a line.
/// </summary>
/// <value>
/// The maximum intersections.
/// </value>
int MaxIntersections { get; }
/// <summary>
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
/// </summary>
/// <param name="point">The point.</param>
/// <returns>
/// Returns the distance from the shape to the point
/// </returns>
float Distance(Vector2 point);
/// <summary>
/// Based on a line described by <paramref name="start"/> and <paramref name="end"/>
/// populate a buffer for all points on the polygon that the line intersects.
/// </summary>
/// <param name="start">The start point of the line.</param>
/// <param name="end">The end point of the line.</param>
/// <param name="buffer">The buffer that will be populated with intersections.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>
/// The number of intersections populated into the buffer.
/// </returns>
int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset);
}
}

93
src/ImageSharp.Drawing/Shapes/LinearPolygon.cs

@ -1,93 +0,0 @@
// <copyright file="LinearPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes
{
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using Paths;
/// <summary>
/// Represents a polygon made up exclusivly of a single Linear path.
/// </summary>
public sealed class LinearPolygon : IShape
{
private Polygon innerPolygon;
/// <summary>
/// Initializes a new instance of the <see cref="LinearPolygon"/> class.
/// </summary>
/// <param name="points">The points.</param>
public LinearPolygon(params Vector2[] points)
{
this.innerPolygon = new Polygon(new LinearLineSegment(points));
}
/// <summary>
/// Gets the bounding box of this shape.
/// </summary>
/// <value>
/// The bounds.
/// </value>
public RectangleF Bounds => this.innerPolygon.Bounds;
/// <summary>
/// Gets the maximum number intersections that a shape can have when testing a line.
/// </summary>
/// <value>
/// The maximum intersections.
/// </value>
public int MaxIntersections
{
get
{
return this.innerPolygon.MaxIntersections;
}
}
/// <summary>
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
/// </summary>
/// <param name="point">The point.</param>
/// <returns>
/// Returns the distance from the shape to the point
/// </returns>
public float Distance(Vector2 point) => this.innerPolygon.Distance(point);
/// <summary>
/// Based on a line described by <paramref name="start"/> and <paramref name="end"/>
/// populate a buffer for all points on the polygon that the line intersects.
/// </summary>
/// <param name="start">The start point of the line.</param>
/// <param name="end">The end point of the line.</param>
/// <param name="buffer">The buffer that will be populated with intersections.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>
/// The number of intersections populated into the buffer.
/// </returns>
public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset)
{
return this.innerPolygon.FindIntersections(start, end, buffer, count, offset);
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<IPath> GetEnumerator() => this.innerPolygon.GetEnumerator();
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator() => this.innerPolygon.GetEnumerator();
}
}

156
src/ImageSharp.Drawing/Shapes/Polygon.cs

@ -1,156 +0,0 @@
// <copyright file="Polygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes
{
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
using Paths;
/// <summary>
/// A shape made up of a single path made up of one of more <see cref="ILineSegment"/>s
/// </summary>
public sealed class Polygon : IShape, IPath
{
private readonly InternalPath innerPath;
private readonly IEnumerable<IPath> pathCollection;
/// <summary>
/// Initializes a new instance of the <see cref="Polygon"/> class.
/// </summary>
/// <param name="segments">The segments.</param>
public Polygon(params ILineSegment[] segments)
{
this.innerPath = new InternalPath(segments, true);
this.pathCollection = new[] { this };
}
/// <summary>
/// Initializes a new instance of the <see cref="Polygon" /> class.
/// </summary>
/// <param name="segment">The segment.</param>
public Polygon(ILineSegment segment)
{
this.innerPath = new InternalPath(segment, true);
this.pathCollection = new[] { this };
}
/// <summary>
/// Gets the bounding box of this shape.
/// </summary>
/// <value>
/// The bounds.
/// </value>
public RectangleF Bounds => this.innerPath.Bounds;
/// <summary>
/// Gets the length of the path
/// </summary>
/// <value>
/// The length.
/// </value>
public float Length => this.innerPath.Length;
/// <summary>
/// Gets a value indicating whether this instance is closed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is closed; otherwise, <c>false</c>.
/// </value>
public bool IsClosed => true;
/// <summary>
/// Gets the maximum number intersections that a shape can have when testing a line.
/// </summary>
/// <value>
/// The maximum intersections.
/// </value>
public int MaxIntersections => this.innerPath.Points.Length;
/// <summary>
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
/// </summary>
/// <param name="point">The point.</param>
/// <returns>
/// The distance of the point away from the shape
/// </returns>
public float Distance(Vector2 point)
{
bool isInside = this.innerPath.PointInPolygon(point);
float distance = this.innerPath.DistanceFromPath(point).DistanceFromPath;
if (isInside)
{
return -distance;
}
return distance;
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<IPath> GetEnumerator()
{
return this.pathCollection.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.pathCollection.GetEnumerator();
}
/// <summary>
/// Calcualtes the distance along and away from the path for a specified point.
/// </summary>
/// <param name="point">The point along the path.</param>
/// <returns>
/// distance metadata about the point.
/// </returns>
PointInfo IPath.Distance(Vector2 point)
{
return this.innerPath.DistanceFromPath(point);
}
/// <summary>
/// Returns the current shape as a simple linear path.
/// </summary>
/// <returns>
/// Returns the current <see cref="ILineSegment" /> as simple linear path.
/// </returns>
public Vector2[] AsSimpleLinearPath()
{
return this.innerPath.Points;
}
/// <summary>
/// Based on a line described by <paramref name="start" /> and <paramref name="end" />
/// populate a buffer for all points on the polygon that the line intersects.
/// </summary>
/// <param name="start">The start point of the line.</param>
/// <param name="end">The end point of the line.</param>
/// <param name="buffer">The buffer that will be populated with intersections.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>
/// The number of intersections populated into the buffer.
/// </returns>
public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset)
{
return this.innerPath.FindIntersections(start, end, buffer, count, offset);
}
}
}

3860
src/ImageSharp.Drawing/Shapes/PolygonClipper/Clipper.cs

File diff suppressed because it is too large

31
src/ImageSharp.Drawing/Shapes/PolygonClipper/ClipperException.cs

@ -1,31 +0,0 @@
// <copyright file="ClipperException.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// Clipper Exception
/// </summary>
/// <seealso cref="System.Exception" />
internal class ClipperException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ClipperException"/> class.
/// </summary>
/// <param name="description">The description.</param>
public ClipperException(string description)
: base(description)
{
}
}
}

31
src/ImageSharp.Drawing/Shapes/PolygonClipper/Direction.cs

@ -1,31 +0,0 @@
// <copyright file="Direction.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ???
/// </summary>
internal enum Direction
{
/// <summary>
/// The right to left
/// </summary>
RightToLeft,
/// <summary>
/// The left to right
/// </summary>
LeftToRight
}
}

31
src/ImageSharp.Drawing/Shapes/PolygonClipper/EdgeSide.cs

@ -1,31 +0,0 @@
// <copyright file="EdgeSide.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ??
/// </summary>
internal enum EdgeSide
{
/// <summary>
/// The left
/// </summary>
Left,
/// <summary>
/// The right
/// </summary>
Right
}
}

38
src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNode.cs

@ -1,38 +0,0 @@
// <copyright file="IntersectNode.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ??
/// </summary>
internal class IntersectNode
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The edge1
/// </summary>
internal TEdge Edge1;
/// <summary>
/// The edge2
/// </summary>
internal TEdge Edge2;
/// <summary>
/// The pt
/// </summary>
internal System.Numerics.Vector2 Pt;
#pragma warning restore SA1401 // Field must be private
}
}

48
src/ImageSharp.Drawing/Shapes/PolygonClipper/IntersectNodeSort.cs

@ -1,48 +0,0 @@
// <copyright file="IntersectNodeSort.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// Compares <see cref="IntersectNode"/>s
/// </summary>
internal class IntersectNodeSort : IComparer<IntersectNode>
{
/// <summary>
/// Compares the specified node1.
/// </summary>
/// <param name="node1">The node1.</param>
/// <param name="node2">The node2.</param>
/// <returns>
/// 1 if node2 %gt; node1
/// -1 if node2 $lt; node1
/// 0 if same
/// </returns>
public int Compare(IntersectNode node1, IntersectNode node2)
{
float i = node2.Pt.Y - node1.Pt.Y;
if (i > 0)
{
return 1;
}
else if (i < 0)
{
return -1;
}
else
{
return 0;
}
}
}
}

38
src/ImageSharp.Drawing/Shapes/PolygonClipper/Join.cs

@ -1,38 +0,0 @@
// <copyright file="Join.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ??
/// </summary>
internal class Join
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The out PT1
/// </summary>
internal OutPt OutPt1;
/// <summary>
/// The out PT2
/// </summary>
internal OutPt OutPt2;
/// <summary>
/// The off pt
/// </summary>
internal System.Numerics.Vector2 OffPt;
#pragma warning restore SA1401 // Field must be private
}
}

44
src/ImageSharp.Drawing/Shapes/PolygonClipper/LocalMinima.cs

@ -1,44 +0,0 @@
// <copyright file="LocalMinima.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ??
/// </summary>
internal class LocalMinima
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The y
/// </summary>
internal float Y;
/// <summary>
/// The left bound
/// </summary>
internal TEdge LeftBound;
/// <summary>
/// The right bound
/// </summary>
internal TEdge RightBound;
/// <summary>
/// The next
/// </summary>
internal LocalMinima Next;
#pragma warning restore SA1401 // Field must be private
}
}

38
src/ImageSharp.Drawing/Shapes/PolygonClipper/Maxima.cs

@ -1,38 +0,0 @@
// <copyright file="Maxima.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ??
/// </summary>
internal class Maxima
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The x
/// </summary>
internal float X;
/// <summary>
/// The next
/// </summary>
internal Maxima Next;
/// <summary>
/// The previous
/// </summary>
internal Maxima Prev;
#pragma warning restore SA1401 // Field must be private
}
}

43
src/ImageSharp.Drawing/Shapes/PolygonClipper/OutPt.cs

@ -1,43 +0,0 @@
// <copyright file="OutPt.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// ??
/// </summary>
internal class OutPt
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The index
/// </summary>
internal int Idx;
/// <summary>
/// The pt
/// </summary>
internal System.Numerics.Vector2 Pt;
/// <summary>
/// The next
/// </summary>
internal OutPt Next;
/// <summary>
/// The previous
/// </summary>
internal OutPt Prev;
#pragma warning restore SA1401 // Field must be private
}
}

64
src/ImageSharp.Drawing/Shapes/PolygonClipper/OutRec.cs

@ -1,64 +0,0 @@
// <copyright file="OutRec.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// OutRec: contains a path in the clipping solution. Edges in the AEL will
/// carry a pointer to an OutRec when they are part of the clipping solution.
/// </summary>
internal class OutRec
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The source path
/// </summary>
internal IPath SourcePath;
/// <summary>
/// The index
/// </summary>
internal int Idx;
/// <summary>
/// The is hole
/// </summary>
internal bool IsHole;
/// <summary>
/// The is open
/// </summary>
internal bool IsOpen;
/// <summary>
/// The first left
/// </summary>
internal OutRec FirstLeft;
/// <summary>
/// The PTS
/// </summary>
internal OutPt Pts;
/// <summary>
/// The bottom pt
/// </summary>
internal OutPt BottomPt;
/// <summary>
/// The poly node
/// </summary>
internal PolyNode PolyNode;
#pragma warning restore SA1401 // Field must be private
}
}

179
src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyNode.cs

@ -1,179 +0,0 @@
// <copyright file="PolyNode.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// Poly Node
/// </summary>
internal class PolyNode
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The polygon
/// </summary>
internal List<Vector2> Polygon = new List<Vector2>();
/// <summary>
/// The index
/// </summary>
internal int Index;
/// <summary>
/// The childs
/// </summary>
protected List<PolyNode> children = new List<PolyNode>();
private PolyNode parent;
#pragma warning restore SA1401 // Field must be private
/// <summary>
/// Gets the child count.
/// </summary>
/// <value>
/// The child count.
/// </value>
public int ChildCount
{
get { return this.children.Count; }
}
/// <summary>
/// Gets the contour.
/// </summary>
/// <value>
/// The contour.
/// </value>
public List<Vector2> Contour
{
get { return this.Polygon; }
}
/// <summary>
/// Gets the childs.
/// </summary>
/// <value>
/// The childs.
/// </value>
public List<PolyNode> Children
{
get { return this.children; }
}
/// <summary>
/// Gets or sets the parent.
/// </summary>
/// <value>
/// The parent.
/// </value>
public PolyNode Parent
{
get { return this.parent; }
internal set { this.parent = value; }
}
/// <summary>
/// Gets a value indicating whether this instance is hole.
/// </summary>
/// <value>
/// <c>true</c> if this instance is hole; otherwise, <c>false</c>.
/// </value>
public bool IsHole
{
get { return this.IsHoleNode(); }
}
/// <summary>
/// Gets or sets a value indicating whether this instance is open.
/// </summary>
/// <value>
/// <c>true</c> if this instance is open; otherwise, <c>false</c>.
/// </value>
public bool IsOpen { get; set; }
/// <summary>
/// Gets or sets the source path.
/// </summary>
/// <value>
/// The source path.
/// </value>
public IPath SourcePath { get; internal set; }
/// <summary>
/// Gets the next.
/// </summary>
/// <returns>The next node</returns>
public PolyNode GetNext()
{
if (this.children.Count > 0)
{
return this.children[0];
}
else
{
return this.GetNextSiblingUp();
}
}
/// <summary>
/// Adds the child.
/// </summary>
/// <param name="child">The child.</param>
internal void AddChild(PolyNode child)
{
int cnt = this.children.Count;
this.children.Add(child);
child.parent = this;
child.Index = cnt;
}
/// <summary>
/// Gets the next sibling up.
/// </summary>
/// <returns>The next sibling up</returns>
internal PolyNode GetNextSiblingUp()
{
if (this.parent == null)
{
return null;
}
else if (this.Index == this.parent.children.Count - 1)
{
return this.parent.GetNextSiblingUp();
}
else
{
return this.parent.Children[this.Index + 1];
}
}
/// <summary>
/// Determines whether [is hole node].
/// </summary>
/// <returns>
/// <c>true</c> if [is hole node]; otherwise, <c>false</c>.
/// </returns>
private bool IsHoleNode()
{
bool result = true;
PolyNode node = this.parent;
while (node != null)
{
result = !result;
node = node.parent;
}
return result;
}
}
}

81
src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyTree.cs

@ -1,81 +0,0 @@
// <copyright file="PolyTree.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// Poly Tree
/// </summary>
/// <seealso cref="ImageSharp.Drawing.Shapes.PolygonClipper.PolyNode" />
internal class PolyTree : PolyNode
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// All polys
/// </summary>
internal List<PolyNode> AllPolys = new List<PolyNode>();
#pragma warning restore SA1401 // Field must be private
/// <summary>
/// Gets the total.
/// </summary>
/// <value>
/// The total.
/// </value>
public int Total
{
get
{
int result = this.AllPolys.Count;
// with negative offsets, ignore the hidden outer polygon ...
if (result > 0 && this.Children[0] != this.AllPolys[0])
{
result--;
}
return result;
}
}
/// <summary>
/// Clears this instance.
/// </summary>
public void Clear()
{
for (int i = 0; i < this.AllPolys.Count; i++)
{
this.AllPolys[i] = null;
}
this.AllPolys.Clear();
this.Children.Clear();
}
/// <summary>
/// Gets the first.
/// </summary>
/// <returns>the first node</returns>
public PolyNode GetFirst()
{
if (this.Children.Count > 0)
{
return this.Children[0];
}
else
{
return null;
}
}
}
}

31
src/ImageSharp.Drawing/Shapes/PolygonClipper/PolyType.cs

@ -1,31 +0,0 @@
// <copyright file="PolyType.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// Poly Type
/// </summary>
internal enum PolyType
{
/// <summary>
/// The subject
/// </summary>
Subject,
/// <summary>
/// The clip
/// </summary>
Clip
}
}

40
src/ImageSharp.Drawing/Shapes/PolygonClipper/README.md

@ -1,40 +0,0 @@
# Clipper
License details for code in this folder, this is code original written by **Angus Johnson**
The license header onthe original file which has now be split across multiple files in this folder.
```
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.4.0 *
* Date : 2 July 2015 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2015 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
```

33
src/ImageSharp.Drawing/Shapes/PolygonClipper/Scanbeam.cs

@ -1,33 +0,0 @@
// <copyright file="Scanbeam.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// Scanbeam
/// </summary>
internal class Scanbeam // would this work as a struct?
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The y
/// </summary>
internal float Y;
/// <summary>
/// The next
/// </summary>
internal Scanbeam Next;
#pragma warning restore SA1401 // Field must be private
}
}

118
src/ImageSharp.Drawing/Shapes/PolygonClipper/TEdge.cs

@ -1,118 +0,0 @@
// <copyright file="TEdge.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes.PolygonClipper
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.CompilerServices;
using Paths;
/// <summary>
/// TEdge
/// </summary>
internal class TEdge
{
#pragma warning disable SA1401 // Field must be private
/// <summary>
/// The source path, see if we can link this back later
/// </summary>
internal IPath SourcePath;
/// <summary>
/// The bot
/// </summary>
internal System.Numerics.Vector2 Bot;
/// <summary>
/// The current (updated for every new scanbeam)
/// </summary>
internal System.Numerics.Vector2 Curr;
/// <summary>
/// The top
/// </summary>
internal System.Numerics.Vector2 Top;
/// <summary>
/// The delta
/// </summary>
internal System.Numerics.Vector2 Delta;
/// <summary>
/// The dx
/// </summary>
internal double Dx;
/// <summary>
/// The poly type
/// </summary>
internal PolyType PolyTyp;
/// <summary>
/// Side only refers to current side of solution poly
/// </summary>
internal EdgeSide Side;
/// <summary>
/// 1 or -1 depending on winding direction
/// </summary>
internal int WindDelta;
/// <summary>
/// The winding count
/// </summary>
internal int WindCnt;
/// <summary>
/// The winding count of the opposite polytype
/// </summary>
internal int WindCnt2;
/// <summary>
/// The out index
/// </summary>
internal int OutIdx;
/// <summary>
/// The next
/// </summary>
internal TEdge Next;
/// <summary>
/// The previous
/// </summary>
internal TEdge Prev;
/// <summary>
/// The next in LML
/// </summary>
internal TEdge NextInLML;
/// <summary>
/// The next in ael
/// </summary>
internal TEdge NextInAEL;
/// <summary>
/// The previous in ael
/// </summary>
internal TEdge PrevInAEL;
/// <summary>
/// The next in sel
/// </summary>
internal TEdge NextInSEL;
/// <summary>
/// The previous in sel
/// </summary>
internal TEdge PrevInSEL;
#pragma warning restore SA1401 // Field must be
}
}

281
src/ImageSharp.Drawing/Shapes/RectangularPolygon.cs

@ -1,281 +0,0 @@
// <copyright file="RectangularPolygon.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Shapes
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Paths;
/// <summary>
/// A way of optermising drawing rectangles.
/// </summary>
/// <seealso cref="ImageSharp.Drawing.Shapes.IShape" />
public class RectangularPolygon : IShape, IPath
{
private readonly RectangleF rectangle;
private readonly Vector2 topLeft;
private readonly Vector2 bottomRight;
private readonly Vector2[] points;
private readonly IEnumerable<IPath> pathCollection;
private readonly float halfLength;
/// <summary>
/// Initializes a new instance of the <see cref="RectangularPolygon"/> class.
/// </summary>
/// <param name="rect">The rect.</param>
public RectangularPolygon(ImageSharp.Rectangle rect)
: this((RectangleF)rect)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RectangularPolygon"/> class.
/// </summary>
/// <param name="rect">The rect.</param>
public RectangularPolygon(ImageSharp.RectangleF rect)
{
this.rectangle = rect;
this.points = new Vector2[4]
{
this.topLeft = new Vector2(rect.Left, rect.Top),
new Vector2(rect.Right, rect.Top),
this.bottomRight = new Vector2(rect.Right, rect.Bottom),
new Vector2(rect.Left, rect.Bottom)
};
this.halfLength = this.rectangle.Width + this.rectangle.Height;
this.Length = this.halfLength * 2;
this.pathCollection = new[] { this };
}
/// <summary>
/// Gets the bounding box of this shape.
/// </summary>
/// <value>
/// The bounds.
/// </value>
public RectangleF Bounds => this.rectangle;
/// <summary>
/// Gets a value indicating whether this instance is closed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is closed; otherwise, <c>false</c>.
/// </value>
public bool IsClosed => true;
/// <summary>
/// Gets the length of the path
/// </summary>
/// <value>
/// The length.
/// </value>
public float Length { get; }
/// <summary>
/// Gets the maximum number intersections that a shape can have when testing a line.
/// </summary>
/// <value>
/// The maximum intersections.
/// </value>
public int MaxIntersections => 4;
/// <summary>
/// Calculates the distance along and away from the path for a specified point.
/// </summary>
/// <param name="point">The point along the path.</param>
/// <returns>
/// Returns details about the point and its distance away from the path.
/// </returns>
PointInfo IPath.Distance(Vector2 point)
{
bool inside; // dont care about inside/outside for paths just distance
return this.Distance(point, false, out inside);
}
/// <summary>
/// the distance of the point from the outline of the shape, if the value is negative it is inside the polygon bounds
/// </summary>
/// <param name="point">The point.</param>
/// <returns>
/// Returns the distance from the shape to the point
/// </returns>
public float Distance(Vector2 point)
{
bool insidePoly;
PointInfo result = this.Distance(point, true, out insidePoly);
// invert the distance from path when inside
return insidePoly ? -result.DistanceFromPath : result.DistanceFromPath;
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<IPath> GetEnumerator()
{
return this.pathCollection.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.pathCollection.GetEnumerator();
}
/// <summary>
/// Converts the <see cref="ILineSegment" /> into a simple linear path..
/// </summary>
/// <returns>
/// Returns the current <see cref="ILineSegment" /> as simple linear path.
/// </returns>
public Vector2[] AsSimpleLinearPath()
{
return this.points;
}
/// <summary>
/// Based on a line described by <paramref name="start"/> and <paramref name="end"/>
/// populate a buffer for all points on the edges of the <see cref="RectangularPolygon"/>
/// that the line intersects.
/// </summary>
/// <param name="start">The start point of the line.</param>
/// <param name="end">The end point of the line.</param>
/// <param name="buffer">The buffer that will be populated with intersections.</param>
/// <param name="count">The count.</param>
/// <param name="offset">The offset.</param>
/// <returns>
/// The number of intersections populated into the buffer.
/// </returns>
public int FindIntersections(Vector2 start, Vector2 end, Vector2[] buffer, int count, int offset)
{
int discovered = 0;
Vector2 startPoint = Vector2.Clamp(start, this.topLeft, this.bottomRight);
Vector2 endPoint = Vector2.Clamp(end, this.topLeft, this.bottomRight);
if (startPoint == Vector2.Clamp(startPoint, start, end))
{
// if start closest is within line then its a valid point
discovered++;
buffer[offset++] = startPoint;
}
if (endPoint == Vector2.Clamp(endPoint, start, end))
{
// if start closest is within line then its a valid point
discovered++;
buffer[offset++] = endPoint;
}
return discovered;
}
private PointInfo Distance(Vector2 point, bool getDistanceAwayOnly, out bool isInside)
{
// point in rectangle
// if after its clamped by the extreams its still the same then it must be inside :)
Vector2 clamped = Vector2.Clamp(point, this.topLeft, this.bottomRight);
isInside = clamped == point;
float distanceFromEdge = float.MaxValue;
float distanceAlongEdge = 0f;
if (isInside)
{
// get the absolute distances from the extreams
Vector2 topLeftDist = Vector2.Abs(point - this.topLeft);
Vector2 bottomRightDist = Vector2.Abs(point - this.bottomRight);
// get the min components
Vector2 minDists = Vector2.Min(topLeftDist, bottomRightDist);
// and then the single smallest (dont have to worry about direction)
distanceFromEdge = Math.Min(minDists.X, minDists.Y);
if (!getDistanceAwayOnly)
{
// we need to make clamped the closest point
if (this.topLeft.X + distanceFromEdge == point.X)
{
// closer to lhf
clamped.X = this.topLeft.X; // y is already the same
// distance along edge is length minus the amout down we are from the top of the rect
distanceAlongEdge = this.Length - (clamped.Y - this.topLeft.Y);
}
else if (this.topLeft.Y + distanceFromEdge == point.Y)
{
// closer to top
clamped.Y = this.topLeft.Y; // x is already the same
distanceAlongEdge = clamped.X - this.topLeft.X;
}
else if (this.bottomRight.Y - distanceFromEdge == point.Y)
{
// closer to bottom
clamped.Y = this.bottomRight.Y; // x is already the same
distanceAlongEdge = (this.bottomRight.X - clamped.X) + this.halfLength;
}
else if (this.bottomRight.X - distanceFromEdge == point.X)
{
// closer to rhs
clamped.X = this.bottomRight.X; // x is already the same
distanceAlongEdge = (this.bottomRight.Y - clamped.Y) + this.rectangle.Width;
}
}
}
else
{
// clamped is the point on the path thats closest no matter what
distanceFromEdge = (clamped - point).Length();
if (!getDistanceAwayOnly)
{
// we need to figure out whats the cloests edge now and thus what distance/poitn is closest
if (this.topLeft.X == clamped.X)
{
// distance along edge is length minus the amout down we are from the top of the rect
distanceAlongEdge = this.Length - (clamped.Y - this.topLeft.Y);
}
else if (this.topLeft.Y == clamped.Y)
{
distanceAlongEdge = clamped.X - this.topLeft.X;
}
else if (this.bottomRight.Y == clamped.Y)
{
distanceAlongEdge = (this.bottomRight.X - clamped.X) + this.halfLength;
}
else if (this.bottomRight.X == clamped.X)
{
distanceAlongEdge = (this.bottomRight.Y - clamped.Y) + this.rectangle.Width;
}
}
}
return new PointInfo
{
SearchPoint = point,
DistanceFromPath = distanceFromEdge,
ClosestPointOnPath = clamped,
DistanceAlongPath = distanceAlongEdge
};
}
}
}

6
src/ImageSharp.Formats.Bmp/BmpDecoder.cs

@ -26,9 +26,9 @@ namespace ImageSharp.Formats
public class BmpDecoder : IImageDecoder
{
/// <inheritdoc/>
public void Decode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
public void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
Guard.NotNull(image, "image");
Guard.NotNull(stream, "stream");

10
src/ImageSharp.Formats.Bmp/BmpDecoderCore.cs

@ -58,7 +58,7 @@ namespace ImageSharp.Formats
/// <para><paramref name="stream"/> is null.</para>
/// </exception>
public void Decode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
this.currentStream = stream;
@ -212,7 +212,7 @@ namespace ImageSharp.Formats
/// <param name="bits">The number of bits per pixel.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgbPalette<TColor>(PixelAccessor<TColor> pixels, byte[] colors, int width, int height, int bits, bool inverted)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
// Pixels per byte (bits per pixel)
int ppb = 8 / bits;
@ -267,7 +267,7 @@ namespace ImageSharp.Formats
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb16<TColor>(PixelAccessor<TColor> pixels, int width, int height, bool inverted)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
// We divide here as we will store the colors in our floating point format.
const int ScaleR = 8; // 256/32
@ -309,7 +309,7 @@ namespace ImageSharp.Formats
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb24<TColor>(PixelAccessor<TColor> pixels, int width, int height, bool inverted)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
int padding = CalculatePadding(width, 3);
using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.Zyx, padding))
@ -333,7 +333,7 @@ namespace ImageSharp.Formats
/// <param name="height">The height of the bitmap.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param>
private void ReadRgb32<TColor>(PixelAccessor<TColor> pixels, int width, int height, bool inverted)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
int padding = CalculatePadding(width, 4);
using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.Zyxw, padding))

28
src/ImageSharp.Formats.Bmp/BmpEncoder.cs

@ -14,17 +14,27 @@ namespace ImageSharp.Formats
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
public class BmpEncoder : IImageEncoder
{
/// <inheritdoc/>
public void Encode<TColor>(Image<TColor> image, Stream stream, IEncoderOptions options)
where TColor : struct, IPixel<TColor>
{
IBmpEncoderOptions bmpOptions = BmpEncoderOptions.Create(options);
this.Encode(image, stream, bmpOptions);
}
/// <summary>
/// Gets or sets the number of bits per pixel.
/// Encodes the image to the specified stream from the <see cref="Image{TColor}"/>.
/// </summary>
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24;
/// <inheritdoc/>
public void Encode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
BmpEncoderCore encoder = new BmpEncoderCore();
encoder.Encode(image, stream, this.BitsPerPixel);
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TColor}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
/// <param name="options">The options for the encoder.</param>
public void Encode<TColor>(Image<TColor> image, Stream stream, IBmpEncoderOptions options)
where TColor : struct, IPixel<TColor>
{
BmpEncoderCore encoder = new BmpEncoderCore(options);
encoder.Encode(image, stream);
}
}
}

50
src/ImageSharp.Formats.Bmp/BmpEncoderCore.cs

@ -16,34 +16,40 @@ namespace ImageSharp.Formats
internal sealed class BmpEncoderCore
{
/// <summary>
/// The number of bits per pixel.
/// The options for the encoder.
/// </summary>
private BmpBitsPerPixel bmpBitsPerPixel;
private readonly IBmpEncoderOptions options;
/// <summary>
/// The amount to pad each row by.
/// </summary>
private int padding;
/// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderCore"/> class.
/// </summary>
/// <param name="options">The options for the encoder.</param>
public BmpEncoderCore(IBmpEncoderOptions options)
{
this.options = options ?? new BmpEncoderOptions();
}
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageBase{TColor}"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
/// <param name="bitsPerPixel">The <see cref="BmpBitsPerPixel"/></param>
public void Encode<TColor>(ImageBase<TColor> image, Stream stream, BmpBitsPerPixel bitsPerPixel)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
public void Encode<TColor>(ImageBase<TColor> image, Stream stream)
where TColor : struct, IPixel<TColor>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.bmpBitsPerPixel = bitsPerPixel;
// Cast to int will get the bytes per pixel
short bpp = (short)(8 * (int)bitsPerPixel);
short bpp = (short)(8 * (int)this.options.BitsPerPixel);
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32);
this.padding = bytesPerLine - (image.Width * (int)bitsPerPixel);
this.padding = bytesPerLine - (image.Width * (int)this.options.BitsPerPixel);
// Do not use IDisposable pattern here as we want to preserve the stream.
EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
@ -119,23 +125,23 @@ namespace ImageSharp.Formats
/// Writes the pixel data to the binary stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="image">
/// The <see cref="ImageBase{TColor}"/> containing pixel data.
/// </param>
private void WriteImage<TColor>(EndianBinaryWriter writer, ImageBase<TColor> image)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
where TColor : struct, IPixel<TColor>
{
using (PixelAccessor<TColor> pixels = image.Lock())
{
switch (this.bmpBitsPerPixel)
switch (this.options.BitsPerPixel)
{
case BmpBitsPerPixel.Pixel32:
this.Write32Bit<TColor>(writer, pixels);
this.Write32Bit(writer, pixels);
break;
case BmpBitsPerPixel.Pixel24:
this.Write24Bit<TColor>(writer, pixels);
this.Write24Bit(writer, pixels);
break;
}
}
@ -145,11 +151,11 @@ namespace ImageSharp.Formats
/// Writes the 32bit color palette to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="pixels">The <see cref="PixelAccessor{TColor}"/> containing pixel data.</param>
private void Write32Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
where TColor : struct, IPixel<TColor>
{
using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.Zyxw, this.padding))
{
for (int y = pixels.Height - 1; y >= 0; y--)
@ -164,11 +170,11 @@ namespace ImageSharp.Formats
/// Writes the 24bit color palette to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="pixels">The <see cref="PixelAccessor{TColor}"/> containing pixel data.</param>
private void Write24Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
where TColor : struct, IPixel<TColor>
{
using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.Zyx, this.padding))
{
for (int y = pixels.Height - 1; y >= 0; y--)

45
src/ImageSharp.Formats.Bmp/BmpEncoderOptions.cs

@ -0,0 +1,45 @@
// <copyright file="BmpEncoderOptions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
/// <summary>
/// Encapsulates the options for the <see cref="BmpEncoder"/>.
/// </summary>
public sealed class BmpEncoderOptions : EncoderOptions, IBmpEncoderOptions
{
/// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderOptions"/> class.
/// </summary>
public BmpEncoderOptions()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BmpEncoderOptions"/> class.
/// </summary>
/// <param name="options">The options for the encoder.</param>
private BmpEncoderOptions(IEncoderOptions options)
: base(options)
{
}
/// <summary>
/// Gets or sets the number of bits per pixel.
/// </summary>
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24;
/// <summary>
/// Converts the options to a <see cref="IBmpEncoderOptions"/> instance with a cast
/// or by creating a new instance with the specfied options.
/// </summary>
/// <param name="options">The options for the encoder.</param>
/// <returns>The options for the <see cref="BmpEncoder"/>.</returns>
internal static IBmpEncoderOptions Create(IEncoderOptions options)
{
return options as IBmpEncoderOptions ?? new BmpEncoderOptions(options);
}
}
}

18
src/ImageSharp.Formats.Bmp/IBmpEncoderOptions.cs

@ -0,0 +1,18 @@
// <copyright file="IBmpEncoderOptions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
/// <summary>
/// Encapsulates the options for the <see cref="BmpEncoder"/>.
/// </summary>
public interface IBmpEncoderOptions : IEncoderOptions
{
/// <summary>
/// Gets the number of bits per pixel.
/// </summary>
BmpBitsPerPixel BitsPerPixel { get; }
}
}

2
src/ImageSharp.Formats.Bmp/ImageExtensions.cs

@ -26,7 +26,7 @@ namespace ImageSharp
/// The <see cref="Image{TColoR}"/>.
/// </returns>
public static Image<TColor> SaveAsBmp<TColor>(this Image<TColor> source, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
=> source.Save(stream, new BmpEncoder());
}
}

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

@ -5,10 +5,12 @@
namespace ImageSharp.Formats
{
using System.Text;
/// <summary>
/// Constants that define specific points within a gif.
/// </summary>
internal sealed class GifConstants
internal static class GifConstants
{
/// <summary>
/// The file type.
@ -50,6 +52,11 @@ namespace ImageSharp.Formats
/// </summary>
public const byte CommentLabel = 0xFE;
/// <summary>
/// The name of the property inside the image properties for the comments.
/// </summary>
public const string Comments = "Comments";
/// <summary>
/// The maximum comment length.
/// </summary>
@ -79,5 +86,10 @@ namespace ImageSharp.Formats
/// The end introducer trailer <value>;</value>.
/// </summary>
public const byte EndIntroducer = 0x3B;
/// <summary>
/// Gets the default encoding to use when reading comments.
/// </summary>
public static Encoding DefaultEncoding { get; } = Encoding.GetEncoding("ASCII");
}
}

23
src/ImageSharp.Formats.Gif/GifDecoder.cs

@ -14,10 +14,25 @@ namespace ImageSharp.Formats
public class GifDecoder : IImageDecoder
{
/// <inheritdoc/>
public void Decode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
new GifDecoderCore<TColor>().Decode(image, stream);
public void Decode<TColor>(Image<TColor> image, Stream stream, IDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
IGifDecoderOptions gifOptions = GifDecoderOptions.Create(options);
this.Decode(image, stream, gifOptions);
}
/// <summary>
/// Decodes the image from the specified stream to the <see cref="ImageBase{TColor}"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to decode to.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <param name="options">The options for the decoder.</param>
public void Decode<TColor>(Image<TColor> image, Stream stream, IGifDecoderOptions options)
where TColor : struct, IPixel<TColor>
{
new GifDecoderCore<TColor>(options).Decode(image, stream);
}
}
}

69
src/ImageSharp.Formats.Gif/GifDecoderCore.cs

@ -8,19 +8,25 @@ namespace ImageSharp.Formats
using System;
using System.Buffers;
using System.IO;
using System.Text;
/// <summary>
/// Performs the gif decoding operation.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
internal class GifDecoderCore<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The temp buffer used to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[16];
/// <summary>
/// The decoder options.
/// </summary>
private readonly IGifDecoderOptions options;
/// <summary>
/// The image to decode the information to.
/// </summary>
@ -61,6 +67,15 @@ namespace ImageSharp.Formats
/// </summary>
private GifGraphicsControlExtension graphicsControlExtension;
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderCore{TColor}"/> class.
/// </summary>
/// <param name="options">The decoder options.</param>
public GifDecoderCore(IGifDecoderOptions options)
{
this.options = options ?? new GifDecoderOptions();
}
/// <summary>
/// Decodes the stream to the image.
/// </summary>
@ -225,25 +240,32 @@ namespace ImageSharp.Formats
/// </summary>
private void ReadComments()
{
int flag;
int length;
while ((flag = this.currentStream.ReadByte()) != 0)
while ((length = this.currentStream.ReadByte()) != 0)
{
if (flag > GifConstants.MaxCommentLength)
if (length > GifConstants.MaxCommentLength)
{
throw new ImageFormatException($"Gif comment length '{length}' exceeds max '{GifConstants.MaxCommentLength}'");
}
if (this.options.IgnoreMetadata)
{
throw new ImageFormatException($"Gif comment length '{flag}' exceeds max '{GifConstants.MaxCommentLength}'");
this.currentStream.Seek(length, SeekOrigin.Current);
continue;
}
byte[] flagBuffer = ArrayPool<byte>.Shared.Rent(flag);
byte[] commentsBuffer = ArrayPool<byte>.Shared.Rent(length);
try
{
this.currentStream.Read(flagBuffer, 0, flag);
this.decodedImage.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(flagBuffer, 0, flag)));
this.currentStream.Read(commentsBuffer, 0, length);
string comments = this.options.TextEncoding.GetString(commentsBuffer, 0, length);
this.decodedImage.MetaData.Properties.Add(new ImageProperty(GifConstants.Comments, comments));
}
finally
{
ArrayPool<byte>.Shared.Return(flagBuffer);
ArrayPool<byte>.Shared.Return(commentsBuffer);
}
}
}
@ -321,12 +343,14 @@ namespace ImageSharp.Formats
if (this.previousFrame == null)
{
image = this.decodedImage;
image.Quality = colorTableLength / 3;
this.decodedImage.MetaData.Quality = colorTableLength / 3;
// This initializes the image to become fully transparent because the alpha channel is zero.
image.InitPixels(imageWidth, imageHeight);
this.decodedImage.InitPixels(imageWidth, imageHeight);
this.SetFrameDelay(this.decodedImage.MetaData);
image = this.decodedImage;
}
else
{
@ -338,6 +362,8 @@ namespace ImageSharp.Formats
currentFrame = this.previousFrame.Clone();
this.SetFrameDelay(currentFrame.MetaData);
image = currentFrame;
this.RestoreToBackground(image);
@ -345,11 +371,6 @@ namespace ImageSharp.Formats
this.decodedImage.Frames.Add(currentFrame);
}
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{
image.FrameDelay = this.graphicsControlExtension.DelayTime;
}
int i = 0;
int interlacePass = 0; // The interlace pass
int interlaceIncrement = 8; // The interlacing line increment
@ -465,5 +486,17 @@ namespace ImageSharp.Formats
this.restoreArea = null;
}
/// <summary>
/// Sets the frame delay in the metadata.
/// </summary>
/// <param name="metaData">The meta data.</param>
private void SetFrameDelay(IMetaData metaData)
{
if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0)
{
metaData.FrameDelay = this.graphicsControlExtension.DelayTime;
}
}
}
}

47
src/ImageSharp.Formats.Gif/GifDecoderOptions.cs

@ -0,0 +1,47 @@
// <copyright file="GifDecoderOptions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System.Text;
/// <summary>
/// Encapsulates the options for the <see cref="GifDecoder"/>.
/// </summary>
public sealed class GifDecoderOptions : DecoderOptions, IGifDecoderOptions
{
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderOptions"/> class.
/// </summary>
public GifDecoderOptions()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GifDecoderOptions"/> class.
/// </summary>
/// <param name="options">The options for the decoder.</param>
private GifDecoderOptions(IDecoderOptions options)
: base(options)
{
}
/// <summary>
/// Gets or sets the encoding that should be used when reading comments.
/// </summary>
public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding;
/// <summary>
/// Converts the options to a <see cref="IGifDecoderOptions"/> instance with a cast
/// or by creating a new instance with the specfied options.
/// </summary>
/// <param name="options">The options for the decoder.</param>
/// <returns>The options for the <see cref="GifDecoder"/>.</returns>
internal static IGifDecoderOptions Create(IDecoderOptions options)
{
return options as IGifDecoderOptions ?? new GifDecoderOptions(options);
}
}
}

41
src/ImageSharp.Formats.Gif/GifEncoder.cs

@ -8,40 +8,31 @@ namespace ImageSharp.Formats
using System;
using System.IO;
using ImageSharp.Quantizers;
/// <summary>
/// Image encoder for writing image data to a stream in gif format.
/// </summary>
public class GifEncoder : IImageEncoder
{
/// <summary>
/// Gets or sets the quality of output for images.
/// </summary>
/// <remarks>For gifs the value ranges from 1 to 256.</remarks>
public int Quality { get; set; }
/// <inheritdoc/>
public void Encode<TColor>(Image<TColor> image, Stream stream, IEncoderOptions options)
where TColor : struct, IPixel<TColor>
{
IGifEncoderOptions gifOptions = GifEncoderOptions.Create(options);
/// <summary>
/// Gets or sets the transparency threshold.
/// </summary>
public byte Threshold { get; set; } = 128;
this.Encode(image, stream, gifOptions);
}
/// <summary>
/// Gets or sets the quantizer for reducing the color count.
/// Encodes the image to the specified stream from the <see cref="Image{TColor}"/>.
/// </summary>
public IQuantizer Quantizer { get; set; }
/// <inheritdoc/>
public void Encode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
{
GifEncoderCore encoder = new GifEncoderCore
{
Quality = this.Quality,
Quantizer = this.Quantizer,
Threshold = this.Threshold
};
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TColor}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
/// <param name="options">The options for the encoder.</param>
public void Encode<TColor>(Image<TColor> image, Stream stream, IGifEncoderOptions options)
where TColor : struct, IPixel<TColor>
{
GifEncoderCore encoder = new GifEncoderCore(options);
encoder.Encode(image, stream);
}
}

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

@ -24,20 +24,23 @@ namespace ImageSharp.Formats
private readonly byte[] buffer = new byte[16];
/// <summary>
/// The number of bits requires to store the image palette.
/// The options for the encoder.
/// </summary>
private int bitDepth;
private readonly IGifEncoderOptions options;
/// <summary>
/// Gets or sets the quality of output for images.
/// The number of bits requires to store the image palette.
/// </summary>
/// <remarks>For gifs the value ranges from 1 to 256.</remarks>
public int Quality { get; set; }
private int bitDepth;
/// <summary>
/// Gets or sets the transparency threshold.
/// Initializes a new instance of the <see cref="GifEncoderCore"/> class.
/// </summary>
public byte Threshold { get; set; } = 128;
/// <param name="options">The options for the encoder.</param>
public GifEncoderCore(IGifEncoderOptions options)
{
this.options = options ?? new GifEncoderOptions();
}
/// <summary>
/// Gets or sets the quantizer for reducing the color count.
@ -51,28 +54,25 @@ namespace ImageSharp.Formats
/// <param name="image">The <see cref="Image{TColor}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
if (this.Quantizer == null)
{
this.Quantizer = new OctreeQuantizer<TColor>();
}
this.Quantizer = this.options.Quantizer ?? new OctreeQuantizer<TColor>();
// Do not use IDisposable pattern here as we want to preserve the stream.
EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Ensure that quality can be set but has a fallback.
int quality = this.Quality > 0 ? this.Quality : image.Quality;
this.Quality = quality > 0 ? quality.Clamp(1, 256) : 256;
int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality;
quality = quality > 0 ? quality.Clamp(1, 256) : 256;
// Get the number of bits.
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(this.Quality);
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quality);
// Quantize the image returning a palette.
QuantizedImage<TColor> quantized = ((IQuantizer<TColor>)this.Quantizer).Quantize(image, this.Quality);
QuantizedImage<TColor> quantized = ((IQuantizer<TColor>)this.Quantizer).Quantize(image, quality);
int index = this.GetTransparentIndex(quantized);
@ -84,6 +84,7 @@ namespace ImageSharp.Formats
// Write the first frame.
this.WriteGraphicalControlExtension(image, writer, index);
this.WriteComments(image, writer);
this.WriteImageDescriptor(image, writer);
this.WriteColorTable(quantized, writer);
this.WriteImageData(quantized, writer);
@ -91,13 +92,13 @@ namespace ImageSharp.Formats
// Write additional frames.
if (image.Frames.Any())
{
this.WriteApplicationExtension(writer, image.RepeatCount, image.Frames.Count);
this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count);
// ReSharper disable once ForCanBeConvertedToForeach
for (int i = 0; i < image.Frames.Count; i++)
{
ImageFrame<TColor> frame = image.Frames[i];
QuantizedImage<TColor> quantizedFrame = ((IQuantizer<TColor>)this.Quantizer).Quantize(frame, this.Quality);
QuantizedImage<TColor> quantizedFrame = ((IQuantizer<TColor>)this.Quantizer).Quantize(frame, quality);
this.WriteGraphicalControlExtension(frame, writer, this.GetTransparentIndex(quantizedFrame));
this.WriteImageDescriptor(frame, writer);
@ -106,7 +107,7 @@ namespace ImageSharp.Formats
}
}
// TODO: Write Comments extension etc
// TODO: Write extension etc
writer.Write(GifConstants.EndIntroducer);
}
@ -121,7 +122,7 @@ namespace ImageSharp.Formats
/// The <see cref="int"/>.
/// </returns>
private int GetTransparentIndex<TColor>(QuantizedImage<TColor> quantized)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
// Find the lowest alpha value and make it the transparent index.
int index = 255;
@ -171,7 +172,7 @@ namespace ImageSharp.Formats
/// <param name="writer">The writer to write to the stream with.</param>
/// <param name="tranparencyIndex">The transparency index to set the default background index to.</param>
private void WriteLogicalScreenDescriptor<TColor>(Image<TColor> image, EndianBinaryWriter writer, int tranparencyIndex)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
GifLogicalScreenDescriptor descriptor = new GifLogicalScreenDescriptor
{
@ -229,15 +230,75 @@ namespace ImageSharp.Formats
}
}
/// <summary>
/// Writes the image comments to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to be encoded.</param>
/// <param name="writer">The stream to write to.</param>
private void WriteComments<TColor>(Image<TColor> image, EndianBinaryWriter writer)
where TColor : struct, IPixel<TColor>
{
if (this.options.IgnoreMetadata == true)
{
return;
}
ImageProperty property = image.MetaData.Properties.FirstOrDefault(p => p.Name == GifConstants.Comments);
if (property == null || string.IsNullOrEmpty(property.Value))
{
return;
}
byte[] comments = this.options.TextEncoding.GetBytes(property.Value);
int count = Math.Min(comments.Length, 255);
this.buffer[0] = GifConstants.ExtensionIntroducer;
this.buffer[1] = GifConstants.CommentLabel;
this.buffer[2] = (byte)count;
writer.Write(this.buffer, 0, 3);
writer.Write(comments, 0, count);
writer.Write(GifConstants.Terminator);
}
/// <summary>
/// Writes the graphics control extension to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TColor}"/> to encode.</param>
/// <param name="writer">The stream to write to.</param>
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
private void WriteGraphicalControlExtension<TColor>(Image<TColor> image, EndianBinaryWriter writer, int transparencyIndex)
where TColor : struct, IPixel<TColor>
{
this.WriteGraphicalControlExtension(image, image.MetaData, writer, transparencyIndex);
}
/// <summary>
/// Writes the graphics control extension to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="imageFrame">The <see cref="ImageFrame{TColor}"/> to encode.</param>
/// <param name="writer">The stream to write to.</param>
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
private void WriteGraphicalControlExtension<TColor>(ImageFrame<TColor> imageFrame, EndianBinaryWriter writer, int transparencyIndex)
where TColor : struct, IPixel<TColor>
{
this.WriteGraphicalControlExtension(imageFrame, imageFrame.MetaData, writer, transparencyIndex);
}
/// <summary>
/// Writes the graphics control extension to the stream.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to encode.</param>
/// <param name="metaData">The metadata of the image or frame.</param>
/// <param name="writer">The stream to write to.</param>
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
private void WriteGraphicalControlExtension<TColor>(ImageBase<TColor> image, EndianBinaryWriter writer, int transparencyIndex)
where TColor : struct, IPackedPixel, IEquatable<TColor>
private void WriteGraphicalControlExtension<TColor>(ImageBase<TColor> image, IMetaData metaData, EndianBinaryWriter writer, int transparencyIndex)
where TColor : struct, IPixel<TColor>
{
// TODO: Check transparency logic.
bool hasTransparent = transparencyIndex < 255;
@ -250,7 +311,7 @@ namespace ImageSharp.Formats
DisposalMethod = disposalMethod,
TransparencyFlag = hasTransparent,
TransparencyIndex = transparencyIndex,
DelayTime = image.FrameDelay
DelayTime = metaData.FrameDelay
};
// Write the intro.
@ -279,7 +340,7 @@ namespace ImageSharp.Formats
/// <param name="image">The <see cref="ImageBase{TColor}"/> to be encoded.</param>
/// <param name="writer">The stream to write to.</param>
private void WriteImageDescriptor<TColor>(ImageBase<TColor> image, EndianBinaryWriter writer)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
writer.Write(GifConstants.ImageDescriptorLabel); // 2c
@ -305,7 +366,7 @@ namespace ImageSharp.Formats
/// <param name="image">The <see cref="ImageBase{TColor}"/> to encode.</param>
/// <param name="writer">The writer to write to the stream with.</param>
private void WriteColorTable<TColor>(QuantizedImage<TColor> image, EndianBinaryWriter writer)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
// Grab the palette and write it to the stream.
int pixelCount = image.Palette.Length;
@ -340,7 +401,7 @@ namespace ImageSharp.Formats
/// <param name="image">The <see cref="QuantizedImage{TColor}"/> containing indexed pixels.</param>
/// <param name="writer">The stream to write to.</param>
private void WriteImageData<TColor>(QuantizedImage<TColor> image, EndianBinaryWriter writer)
where TColor : struct, IPackedPixel, IEquatable<TColor>
where TColor : struct, IPixel<TColor>
{
using (LzwEncoder encoder = new LzwEncoder(image.Pixels, (byte)this.bitDepth))
{

65
src/ImageSharp.Formats.Gif/GifEncoderOptions.cs

@ -0,0 +1,65 @@
// <copyright file="GifEncoderOptions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats
{
using System.Text;
using Quantizers;
/// <summary>
/// Encapsulates the options for the <see cref="GifEncoder"/>.
/// </summary>
public sealed class GifEncoderOptions : EncoderOptions, IGifEncoderOptions
{
/// <summary>
/// Initializes a new instance of the <see cref="GifEncoderOptions"/> class.
/// </summary>
public GifEncoderOptions()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="GifEncoderOptions"/> class.
/// </summary>
/// <param name="options">The options for the encoder.</param>
private GifEncoderOptions(IEncoderOptions options)
: base(options)
{
}
/// <summary>
/// Gets or sets the encoding that should be used when writing comments.
/// </summary>
public Encoding TextEncoding { get; set; } = GifConstants.DefaultEncoding;
/// <summary>
/// Gets or sets the quality of output for images.
/// </summary>
/// <remarks>For gifs the value ranges from 1 to 256.</remarks>
public int Quality { get; set; }
/// <summary>
/// Gets or sets the transparency threshold.
/// </summary>
public byte Threshold { get; set; } = 128;
/// <summary>
/// Gets or sets the quantizer for reducing the color count.
/// </summary>
public IQuantizer Quantizer { get; set; }
/// <summary>
/// Converts the options to a <see cref="IGifEncoderOptions"/> instance with a
/// cast or by creating a new instance with the specfied options.
/// </summary>
/// <param name="options">The options for the encoder.</param>
/// <returns>The options for the <see cref="GifEncoder"/>.</returns>
internal static IGifEncoderOptions Create(IEncoderOptions options)
{
return options as IGifEncoderOptions ?? new GifEncoderOptions(options);
}
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save