Browse Source

Merge remote-tracking branch 'refs/remotes/origin/master' into feature/icc

af/merge-core
James Jackson-South 9 years ago
parent
commit
cf4d594287
  1. 2
      .editorconfig
  2. 2
      ImageSharp.ruleset
  3. 4
      ImageSharp.sln
  4. 25
      README.md
  5. 249
      Rebracer.xml
  6. 56
      Settings.StyleCop
  7. 252
      src/ImageSharp.Drawing/Brushes/Brushes.cs
  8. 168
      src/ImageSharp.Drawing/Brushes/Brushes{TPixel}.cs
  9. 24
      src/ImageSharp.Drawing/Brushes/ImageBrush.cs
  10. 9
      src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs
  11. 35
      src/ImageSharp.Drawing/Brushes/PatternBrush.cs
  12. 6
      src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
  13. 6
      src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
  14. 26
      src/ImageSharp.Drawing/Brushes/RecolorBrush.cs
  15. 7
      src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs
  16. 24
      src/ImageSharp.Drawing/Brushes/SolidBrush.cs
  17. 7
      src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs
  18. 6
      src/ImageSharp.Drawing/DrawImage.cs
  19. 2
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  20. 55
      src/ImageSharp.Drawing/Pens/Pen.cs
  21. 57
      src/ImageSharp.Drawing/Pens/Pens.cs
  22. 112
      src/ImageSharp.Drawing/Pens/Pens{TPixel}.cs
  23. 6
      src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
  24. 4
      src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
  25. 2
      src/ImageSharp.Drawing/Processors/FillProcessor.cs
  26. 2
      src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
  27. 2
      src/ImageSharp.Drawing/Text/DrawText.cs
  28. 40
      src/ImageSharp/Common/Helpers/DebugGuard.cs
  29. 19
      src/ImageSharp/Common/Helpers/Guard.cs
  30. 2
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  31. 205
      src/ImageSharp/Common/Memory/BufferSpan{T}.cs
  32. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs
  33. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs
  34. 1
      src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs
  35. 2
      src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs
  36. 2
      src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs
  37. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs
  38. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs
  39. 2
      src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs
  40. 2
      src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs
  41. 2
      src/ImageSharp/Dithering/Ordered/Bayer.cs
  42. 2
      src/ImageSharp/Dithering/Ordered/Ordered.cs
  43. 1
      src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs
  44. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  45. 2
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  46. 55
      src/ImageSharp/Formats/Jpeg/Components/Decoder/DecodedBlockArray.cs
  47. 10
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs
  48. 64
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs
  49. 8
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs
  50. 20
      src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs
  51. 55
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  52. 65
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  53. 19
      src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
  54. 68
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  55. 49
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  56. 48
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  57. 83
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  58. 6
      src/ImageSharp/Formats/Png/PngEncoder.cs
  59. 151
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  60. 62
      src/ImageSharp/Image.Create.cs
  61. 69
      src/ImageSharp/Image.cs
  62. 17
      src/ImageSharp/Image/Image.Decode.cs
  63. 146
      src/ImageSharp/Image/Image.FromBytes.cs
  64. 109
      src/ImageSharp/Image/Image.FromFile.cs
  65. 131
      src/ImageSharp/Image/Image.FromStream.cs
  66. 8
      src/ImageSharp/Image/ImageBase{TPixel}.cs
  67. 2
      src/ImageSharp/Image/ImageFrame{TPixel}.cs
  68. 22
      src/ImageSharp/Image/Image{TPixel}.cs
  69. 38
      src/ImageSharp/Image/PixelAccessor{TPixel}.cs
  70. 8
      src/ImageSharp/Image/PixelArea{TPixel}.cs
  71. 5
      src/ImageSharp/ImageSharp.csproj
  72. 31
      src/ImageSharp/Memory/Buffer.cs
  73. 3
      src/ImageSharp/Memory/Buffer2D.cs
  74. 14
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  75. 6
      src/ImageSharp/Memory/Fast2DArray{T}.cs
  76. 8
      src/ImageSharp/Memory/IBuffer2D.cs
  77. 3
      src/ImageSharp/Memory/PixelDataPool{T}.cs
  78. 36
      src/ImageSharp/Memory/SpanHelper.cs
  79. 22
      src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
  80. 6
      src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
  81. 4
      src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs
  82. 8
      src/ImageSharp/PixelFormats/Alpha8.cs
  83. 9
      src/ImageSharp/PixelFormats/Argb32.cs
  84. 8
      src/ImageSharp/PixelFormats/Bgr565.cs
  85. 8
      src/ImageSharp/PixelFormats/Bgra4444.cs
  86. 8
      src/ImageSharp/PixelFormats/Bgra5551.cs
  87. 8
      src/ImageSharp/PixelFormats/Byte4.cs
  88. 9
      src/ImageSharp/PixelFormats/HalfSingle.cs
  89. 9
      src/ImageSharp/PixelFormats/HalfVector2.cs
  90. 9
      src/ImageSharp/PixelFormats/HalfVector4.cs
  91. 8
      src/ImageSharp/PixelFormats/IPixel.cs
  92. 8
      src/ImageSharp/PixelFormats/NormalizedByte2.cs
  93. 8
      src/ImageSharp/PixelFormats/NormalizedByte4.cs
  94. 9
      src/ImageSharp/PixelFormats/NormalizedShort2.cs
  95. 9
      src/ImageSharp/PixelFormats/NormalizedShort4.cs
  96. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs
  97. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs
  98. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs
  99. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs
  100. 10
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs

2
.editorconfig

@ -6,7 +6,7 @@ indent_style = space
indent_size = 4
csharp_style_var_for_built_in_types = false:warning
csharp_style_var_elsewhere = false:warning
csharp_style_var_when_type_is_apparent = false:warning
csharp_style_var_when_type_is_apparent = true:warning
end_of_line = crlf
dotnet_sort_system_directives_first = true
dotnet_style_predefined_type_for_locals_parameters_members = true:warning

2
ImageSharp.ruleset

@ -4,7 +4,7 @@
<Rule Id="AD0001" Action="None" />
<Rule Id="SA1405" Action="None" />
<Rule Id="SA1413" Action="None" />
<!-- temp remove the header requiremnet as stylecop is currently failing to read the stylecop.json file from 'dotnet build' -->
<!-- temp remove the header requirement as stylecop is currently failing to read the stylecop.json file from 'dotnet build' -->
<Rule Id="SA1636" Action="None" />
<Rule Id="SA1633" Action="None" />
</Rules>

4
ImageSharp.sln

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.3
VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
@ -16,8 +16,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings
NuGet.config = NuGet.config
README.md = README.md
Rebracer.xml = Rebracer.xml
Settings.StyleCop = Settings.StyleCop
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"

25
README.md

@ -1,5 +1,5 @@
# <img src="https://github.com/JimBobSquarePants/ImageSharp/blob/master/build/icons/imagesharp-logo-256.png" alt="ImageSharp" width="52"/> ImageSharp
# <img src="https://raw.githubusercontent.com/JimBobSquarePants/ImageSharp/master/build/icons/imagesharp-logo-256.png" alt="ImageSharp" width="52"/> ImageSharp
**ImageSharp** is a new, fully featured, fully managed, cross-platform, 2D graphics API designed to allow the processing of images without the use of `System.Drawing`.
@ -39,8 +39,8 @@ The **ImageSharp** library is made up of multiple packages.
Packages include:
- **ImageSharp**
- Contains the Image classes, PixelFormats, Primitives, Configuration, and other core functionality.
- The IImageFormat interface, Jpeg, Png, Bmp, and Gif formats.
- Contains the generic `Image<TPixel>` class, PixelFormats, Primitives, Configuration, and other core functionality.
- The `IImageFormat` interface, Jpeg, Png, Bmp, and Gif formats.
- Transform methods like Resize, Crop, Skew, Rotate - Anything that alters the dimensions of the image.
- Non-transform methods like Gaussian Blur, Pixelate, Edge Detection - Anything that maintains the original image dimensions.
@ -77,13 +77,16 @@ Without the constraints of `System.Drawing` We have been able to develop somethi
Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments.
Many `Image` methods are also fluent.
Many `Image<TPixel>` 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.
`Rgba32` is our default PixelFormat, equivalent to `System.Drawing Color`.
On platforms supporting netstandard 1.3+
```csharp
using (Image image = Image.Load("foo.jpg"))
// Image.Load(string path) is a shortcut for our default type. Other pixel formats use Image.Load<TPixel>(string path))
using (Image<Rgba32> image = Image.Load("foo.jpg"))
{
image.Resize(image.Width / 2, image.Height / 2)
.Grayscale()
@ -92,9 +95,10 @@ using (Image image = Image.Load("foo.jpg"))
```
on netstandard 1.1 - 1.2
```csharp
// Image.Load(Stream stream) is a shortcut for our default type. Other pixel formats use Image.Load<TPixel>(Stream stream))
using (FileStream stream = File.OpenRead("foo.jpg"))
using (FileStream output = File.OpenWrite("bar.jpg"))
using (Image image = Image.Load(stream))
using (Image<Rgba32> image = Image.Load<Rgba32>(stream))
{
image.Resize(image.Width / 2, image.Height / 2)
.Grayscale()
@ -105,15 +109,14 @@ using (Image image = Image.Load(stream))
Setting individual pixel values is perfomed as follows:
```csharp
using (image = new Image(400, 400)
using (var pixels = image.Lock())
using (Image<Rgba32> image = new Image<Rgba32>(400, 400)
using (PixelAccessor<Rgba32> pixels = image.Lock())
{
// Rgba32 is our default PixelFormat, equivalent to System.Drawing Color
pixels[200, 200] = Rgba32.White;
}
```
For advanced usage the `Image<TPixel>` and `PixelAccessor<TPixel>` classes are available allowing developers to implement their own color models in the same manner as Microsoft XNA Game Studio and MonoGame.
For advanced usage there are multiple [PixelFormat implementations](https://github.com/JimBobSquarePants/ImageSharp/tree/master/src/ImageSharp/PixelFormats) available allowing developers to implement their own color models in the same manner as Microsoft XNA Game Studio and MonoGame.
All in all this should allow image processing to be much more accessible to developers which has always been my goal from the start.
@ -121,7 +124,7 @@ All in all this should allow image processing to be much more accessible to deve
Please... Spread the word, contribute algorithms, submit performance improvements, unit tests.
Performance is a biggie, if you know anything about the new vector types and can apply some fancy new stuff with that it would be awesome.
Performance is a biggie, if you know anything about the `System.Numerics.Vectors` types and can apply some fancy new stuff with that it would be awesome.
There's a lot of developers out there who could write this stuff a lot better and faster than I and I would love to see what we collectively can come up with so please, if you can help in any way it would be most welcome and benificial for all.

249
Rebracer.xml

@ -1,249 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--Rebracer Solution Settings File-->
<!--This file contains Visual Studio settings for ImageProcessorCore.sln.-->
<!--Rebracer uses this file to apply settings for this solution-->
<!--when the solution is opened.-->
<!--Install Rebracer from http://visualstudiogallery.msdn.microsoft.com/410e9b9f-65f3-4495-b68e-15567e543c58 -->
<!--See https://github.com/SLaks/Rebracer for more information-->
<UserSettings>
<ToolsOptions>
<ToolsOptionsCategory name="Environment">
<ToolsOptionsSubCategory name="TaskList">
<PropertyValue name="CommentTokens" ArrayType="VT_VARIANT" ArrayElementCount="4">
<PropertyValue name="0">HACK:2</PropertyValue>
<PropertyValue name="1">TODO:2</PropertyValue>
<PropertyValue name="2">UNDONE:2</PropertyValue>
<PropertyValue name="3">UnresolvedMergeConflict:3</PropertyValue>
</PropertyValue>
<PropertyValue name="ConfirmTaskDeletion">false</PropertyValue>
<PropertyValue name="DontShowFilePaths">false</PropertyValue>
<PropertyValue name="WarnOnAddingHiddenItem">false</PropertyValue>
</ToolsOptionsSubCategory>
</ToolsOptionsCategory>
<ToolsOptionsCategory name="TextEditor">
<ToolsOptionsSubCategory name="CSharp-Specific">
<PropertyValue name="AddImport_SuggestForTypesInNuGetPackages">0</PropertyValue>
<PropertyValue name="AddImport_SuggestForTypesInReferenceAssemblies">0</PropertyValue>
<PropertyValue name="AutoComment">1</PropertyValue>
<PropertyValue name="AutoInsertAsteriskForNewLinesOfBlockComments">1</PropertyValue>
<PropertyValue name="CSharpClosedFileDiagnostics">-1</PropertyValue>
<PropertyValue name="ClosedFileDiagnostics">-1</PropertyValue>
<PropertyValue name="DisplayLineSeparators">0</PropertyValue>
<PropertyValue name="EnableHighlightRelatedKeywords">1</PropertyValue>
<PropertyValue name="ExtractMethod_AllowMovingDeclaration">0</PropertyValue>
<PropertyValue name="ExtractMethod_DoNotPutOutOrRefOnStruct">1</PropertyValue>
<PropertyValue name="Formatting_TriggerOnBlockCompletion">1</PropertyValue>
<PropertyValue name="Formatting_TriggerOnPaste">1</PropertyValue>
<PropertyValue name="Formatting_TriggerOnStatementCompletion">1</PropertyValue>
<PropertyValue name="Indent_BlockContents">1</PropertyValue>
<PropertyValue name="Indent_Braces">0</PropertyValue>
<PropertyValue name="Indent_CaseContents">1</PropertyValue>
<PropertyValue name="Indent_CaseLabels">1</PropertyValue>
<PropertyValue name="Indent_FlushLabelsLeft">0</PropertyValue>
<PropertyValue name="Indent_UnindentLabels">2</PropertyValue>
<PropertyValue name="NewLines_AnonymousTypeInitializer_EachMember">1</PropertyValue>
<PropertyValue name="NewLines_Braces_Accessor">1</PropertyValue>
<PropertyValue name="NewLines_Braces_AnonymousMethod">1</PropertyValue>
<PropertyValue name="NewLines_Braces_AnonymousTypeInitializer">1</PropertyValue>
<PropertyValue name="NewLines_Braces_ControlFlow">1</PropertyValue>
<PropertyValue name="NewLines_Braces_LambdaExpressionBody">1</PropertyValue>
<PropertyValue name="NewLines_Braces_Method">1</PropertyValue>
<PropertyValue name="NewLines_Braces_ObjectInitializer">1</PropertyValue>
<PropertyValue name="NewLines_Braces_Property">1</PropertyValue>
<PropertyValue name="NewLines_Braces_Type">1</PropertyValue>
<PropertyValue name="NewLines_Keywords_Catch">1</PropertyValue>
<PropertyValue name="NewLines_Keywords_Else">1</PropertyValue>
<PropertyValue name="NewLines_Keywords_Finally">1</PropertyValue>
<PropertyValue name="NewLines_ObjectInitializer_EachMember">1</PropertyValue>
<PropertyValue name="NewLines_QueryExpression_EachClause">1</PropertyValue>
<PropertyValue name="RenameTrackingPreview">1</PropertyValue>
<PropertyValue name="SortUsings_PlaceSystemFirst">0</PropertyValue>
<PropertyValue name="Space_AfterBasesColon">1</PropertyValue>
<PropertyValue name="Space_AfterCast">0</PropertyValue>
<PropertyValue name="Space_AfterComma">1</PropertyValue>
<PropertyValue name="Space_AfterDot">0</PropertyValue>
<PropertyValue name="Space_AfterMethodCallName">0</PropertyValue>
<PropertyValue name="Space_AfterMethodDeclarationName">0</PropertyValue>
<PropertyValue name="Space_AfterSemicolonsInForStatement">1</PropertyValue>
<PropertyValue name="Space_AroundBinaryOperator">1</PropertyValue>
<PropertyValue name="Space_BeforeBasesColon">1</PropertyValue>
<PropertyValue name="Space_BeforeComma">0</PropertyValue>
<PropertyValue name="Space_BeforeDot">0</PropertyValue>
<PropertyValue name="Space_BeforeOpenSquare">0</PropertyValue>
<PropertyValue name="Space_BeforeSemicolonsInForStatement">0</PropertyValue>
<PropertyValue name="Space_BetweenEmptyMethodCallParentheses">0</PropertyValue>
<PropertyValue name="Space_BetweenEmptyMethodDeclarationParentheses">0</PropertyValue>
<PropertyValue name="Space_BetweenEmptySquares">0</PropertyValue>
<PropertyValue name="Space_InControlFlowConstruct">1</PropertyValue>
<PropertyValue name="Space_WithinCastParentheses">0</PropertyValue>
<PropertyValue name="Space_WithinExpressionParentheses">0</PropertyValue>
<PropertyValue name="Space_WithinMethodCallParentheses">0</PropertyValue>
<PropertyValue name="Space_WithinMethodDeclarationParentheses">0</PropertyValue>
<PropertyValue name="Space_WithinOtherParentheses">0</PropertyValue>
<PropertyValue name="Space_WithinSquares">0</PropertyValue>
<PropertyValue name="Style_PreferIntrinsicPredefinedTypeKeywordInDeclaration">1</PropertyValue>
<PropertyValue name="Style_PreferIntrinsicPredefinedTypeKeywordInMemberAccess">1</PropertyValue>
<PropertyValue name="Style_QualifyMemberAccessWithThisOrMe">0</PropertyValue>
<PropertyValue name="Style_UseVarWhenDeclaringLocals">1</PropertyValue>
<PropertyValue name="WarnOnBuildErrors">0</PropertyValue>
<PropertyValue name="Wrapping_IgnoreSpacesAroundBinaryOperators">0</PropertyValue>
<PropertyValue name="Wrapping_IgnoreSpacesAroundVariableDeclaration">0</PropertyValue>
<PropertyValue name="Wrapping_KeepStatementsOnSingleLine">1</PropertyValue>
<PropertyValue name="Wrapping_PreserveSingleLine">1</PropertyValue>
</ToolsOptionsSubCategory>
<ToolsOptionsSubCategory name="JavaScript Specific">
<PropertyValue name="DownloadRemoteReferences">false</PropertyValue>
<PropertyValue name="FormatCompletedBlockOnRightCurlyBrace">true</PropertyValue>
<PropertyValue name="FormatCompletedLineOnEnter">true</PropertyValue>
<PropertyValue name="FormatCompletedStatementOnSemicolon">true</PropertyValue>
<PropertyValue name="FormatOnPaste">true</PropertyValue>
<PropertyValue name="ImplicitReferencesString">Implicit (Windows)|$(VSInstallDir)\JavaScript\References\libhelp.js|$(VSInstallDir)\JavaScript\References\domWindows.js|$(VSInstallDir)\JavaScript\References\underscorefilter.js|$(VSInstallDir)\JavaScript\References\showPlainComments.js;Implicit (Windows 8.1)|$(VSInstallDir)\JavaScript\References\libhelp.js|$(VSInstallDir)\JavaScript\References\sitetypesWindows.js|$(VSInstallDir)\JavaScript\References\domWindows_8.1.js|$(VSInstallDir)\JavaScript\References\underscorefilter.js|$(VSInstallDir)\JavaScript\References\showPlainComments.js;Implicit (Windows Phone 8.1)|$(VSInstallDir)\JavaScript\References\libhelp.js|$(VSInstallDir)\JavaScript\References\sitetypesWindows.js|$(VSInstallDir)\JavaScript\References\domWindowsPhone_8.1.js|$(VSInstallDir)\JavaScript\References\underscorefilter.js|$(VSInstallDir)\JavaScript\References\showPlainComments.js;Implicit (Web)|$(VSInstallDir)\JavaScript\References\libhelp.js|$(VSInstallDir)\JavaScript\References\sitetypesWeb.js|$(VSInstallDir)\JavaScript\References\domWeb.js|$(VSInstallDir)\JavaScript\References\underscorefilter.js|$(VSInstallDir)\JavaScript\References\showPlainComments.js|C:\Users\james.south\AppData\Local\Web Essentials 2015\Modern.Intellisense.js;Dedicated Worker|$(VSInstallDir)\JavaScript\References\libhelp.js|$(VSInstallDir)\JavaScript\References\dedicatedworker.js|$(VSInstallDir)\JavaScript\References\underscorefilter.js|$(VSInstallDir)\JavaScript\References\showPlainComments.js;Generic|$(VSInstallDir)\JavaScript\References\libhelp.js|$(VSInstallDir)\JavaScript\References\underscorefilter.js|$(VSInstallDir)\JavaScript\References\showPlainComments.js;</PropertyValue>
<PropertyValue name="InsertSpaceAfterCommaDelimiter">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterFunctionKeywordForAnonymousFunctions">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterKeywordsInControlFlowStatements">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis">false</PropertyValue>
<PropertyValue name="InsertSpaceAfterSemicolonInForStatements">true</PropertyValue>
<PropertyValue name="InsertSpaceBeforeAndAfterBinaryOperators">true</PropertyValue>
<PropertyValue name="PlaceOpenBraceOnNewLineForControlBlocks">false</PropertyValue>
<PropertyValue name="PlaceOpenBraceOnNewLineForFunctionsAndClasses">false</PropertyValue>
<PropertyValue name="ShowErrorsAsWarnings">true</PropertyValue>
<PropertyValue name="ShowSyntaxErrors">true</PropertyValue>
</ToolsOptionsSubCategory>
<ToolsOptionsSubCategory name="C/C++ Specific">
<PropertyValue name="AddSemicolonForClassTypes">true</PropertyValue>
<PropertyValue name="AlignParameters">false</PropertyValue>
<PropertyValue name="AlwaysUseFallbackLocation">false</PropertyValue>
<PropertyValue name="AutoFormatOnBraceCompletion">true</PropertyValue>
<PropertyValue name="AutoFormatOnClosingBrace">true</PropertyValue>
<PropertyValue name="AutoFormatOnPaste">true</PropertyValue>
<PropertyValue name="AutoFormatOnPaste2">1</PropertyValue>
<PropertyValue name="AutoFormatOnSemicolon">true</PropertyValue>
<PropertyValue name="AutoIndentOnTab">false</PropertyValue>
<PropertyValue name="ColorizeInactiveBlocksDifferently">true</PropertyValue>
<PropertyValue name="DisableBrowsingUpToDateCheck">true</PropertyValue>
<PropertyValue name="DisableCreateDeclDefnScan">false</PropertyValue>
<PropertyValue name="DisableErrorReporting">false</PropertyValue>
<PropertyValue name="DisableIntelliSenseErrorsInErrorList">false</PropertyValue>
<PropertyValue name="EnableChangeSignature">false</PropertyValue>
<PropertyValue name="EnableExpandPrecedence">false</PropertyValue>
<PropertyValue name="EnableExpandScopes">false</PropertyValue>
<PropertyValue name="EnableExtractFunction">false</PropertyValue>
<PropertyValue name="EnableSQLiteStoreEngine">true</PropertyValue>
<PropertyValue name="EnableSingleFileISense">true</PropertyValue>
<PropertyValue name="EnableSingleFileISenseSquiggles">false</PropertyValue>
<PropertyValue name="EnumerateCommentTasks">true</PropertyValue>
<PropertyValue name="GroupBrackets">true</PropertyValue>
<PropertyValue name="HideExperimentalAd">true</PropertyValue>
<PropertyValue name="HighlightMatchingTokens">true</PropertyValue>
<PropertyValue name="IndentAccessSpecifiers">false</PropertyValue>
<PropertyValue name="IndentBlockContents">true</PropertyValue>
<PropertyValue name="IndentBraces">false</PropertyValue>
<PropertyValue name="IndentCaseBraces">false</PropertyValue>
<PropertyValue name="IndentCaseContents">true</PropertyValue>
<PropertyValue name="IndentCaseLabels">false</PropertyValue>
<PropertyValue name="IndentGotoLabels">1</PropertyValue>
<PropertyValue name="IndentNamespaceContents">true</PropertyValue>
<PropertyValue name="IndentPreprocessor">2</PropertyValue>
<PropertyValue name="IndentationReference">2</PropertyValue>
<PropertyValue name="MemberListDotToArrow">false</PropertyValue>
<PropertyValue name="MemberListFilterHeuristic">false</PropertyValue>
<PropertyValue name="NewlineControlBlockBrace">0</PropertyValue>
<PropertyValue name="NewlineEmptyFunctionCloseBrace">true</PropertyValue>
<PropertyValue name="NewlineEmptyTypeCloseBrace">true</PropertyValue>
<PropertyValue name="NewlineFunctionBrace">0</PropertyValue>
<PropertyValue name="NewlineInitListBrace">0</PropertyValue>
<PropertyValue name="NewlineKeywordCatch">true</PropertyValue>
<PropertyValue name="NewlineKeywordElse">true</PropertyValue>
<PropertyValue name="NewlineKeywordWhile">false</PropertyValue>
<PropertyValue name="NewlineLambdaBrace">0</PropertyValue>
<PropertyValue name="NewlineNamespaceBrace">0</PropertyValue>
<PropertyValue name="NewlineScopeBrace">false</PropertyValue>
<PropertyValue name="NewlineTypeBrace">0</PropertyValue>
<PropertyValue name="PreserveBlock">1</PropertyValue>
<PropertyValue name="PreserveCommentIndentation">false</PropertyValue>
<PropertyValue name="PreserveInitListSpace">true</PropertyValue>
<PropertyValue name="PreserveParameterIndentation">false</PropertyValue>
<PropertyValue name="RefactorScope">2</PropertyValue>
<PropertyValue name="RemoveSpaceBeforeSemicolon">true</PropertyValue>
<PropertyValue name="RenameRenameComments">false</PropertyValue>
<PropertyValue name="RenameRenameInactive">false</PropertyValue>
<PropertyValue name="RenameRenameStrings">false</PropertyValue>
<PropertyValue name="RenameRenameUnconfirmed">false</PropertyValue>
<PropertyValue name="RenameSearchComments">true</PropertyValue>
<PropertyValue name="RenameSearchStrings">true</PropertyValue>
<PropertyValue name="RenameShowPreview">false</PropertyValue>
<PropertyValue name="RenameSkipPreviewIfConfirmed">false</PropertyValue>
<PropertyValue name="ShowSingleFileISenseErrorsInTaskList">false</PropertyValue>
<PropertyValue name="SpaceAfterCastParenthesis">false</PropertyValue>
<PropertyValue name="SpaceAfterComma">true</PropertyValue>
<PropertyValue name="SpaceAfterSemicolon">true</PropertyValue>
<PropertyValue name="SpaceAroundAssignmentOperator">2</PropertyValue>
<PropertyValue name="SpaceAroundBinaryOperator">2</PropertyValue>
<PropertyValue name="SpaceAroundConditionalOperator">2</PropertyValue>
<PropertyValue name="SpaceBeforeBlockBrace">true</PropertyValue>
<PropertyValue name="SpaceBeforeBracket">false</PropertyValue>
<PropertyValue name="SpaceBeforeComma">false</PropertyValue>
<PropertyValue name="SpaceBeforeConstructorColon">true</PropertyValue>
<PropertyValue name="SpaceBeforeControlBlockParenthesis">true</PropertyValue>
<PropertyValue name="SpaceBeforeEmptyBracket">false</PropertyValue>
<PropertyValue name="SpaceBeforeFunctionParenthesis">false</PropertyValue>
<PropertyValue name="SpaceBeforeFunctionParenthesis2">1</PropertyValue>
<PropertyValue name="SpaceBeforeInheritanceColon">true</PropertyValue>
<PropertyValue name="SpaceBeforeInitListBrace">false</PropertyValue>
<PropertyValue name="SpaceBeforeLambdaParenthesis">false</PropertyValue>
<PropertyValue name="SpaceBetweenEmptyBraces">false</PropertyValue>
<PropertyValue name="SpaceBetweenEmptyBrackets">false</PropertyValue>
<PropertyValue name="SpaceBetweenEmptyFunctionParentheses">false</PropertyValue>
<PropertyValue name="SpaceBetweenEmptyLambdaBrackets">false</PropertyValue>
<PropertyValue name="SpaceWithinBrackets">false</PropertyValue>
<PropertyValue name="SpaceWithinCastParentheses">false</PropertyValue>
<PropertyValue name="SpaceWithinControlBlockParentheses">false</PropertyValue>
<PropertyValue name="SpaceWithinExpressionParentheses">false</PropertyValue>
<PropertyValue name="SpaceWithinFunctionParentheses">false</PropertyValue>
<PropertyValue name="SpaceWithinInitListBraces">true</PropertyValue>
<PropertyValue name="SpaceWithinLambdaBrackets">false</PropertyValue>
<PropertyValue name="SuspendNewSingleFileISenseDuringDebugging">false</PropertyValue>
<PropertyValue name="TrimSpaceAroundScope">true</PropertyValue>
<PropertyValue name="TrimSpaceUnaryOperator">true</PropertyValue>
</ToolsOptionsSubCategory>
<ToolsOptionsSubCategory name="TypeScript Specific">
<PropertyValue name="AutomaticallyCompileTypeScriptFilesWhenSavedWhenNoSolution">false</PropertyValue>
<PropertyValue name="ES3ForFilesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="ES5ForFilesThatAreNotPartOfAProject">true</PropertyValue>
<PropertyValue name="ES6ForFilesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="FormatCompletedBlockOnRightCurlyBrace">true</PropertyValue>
<PropertyValue name="FormatCompletedLineOnEnter">true</PropertyValue>
<PropertyValue name="FormatCompletedStatementOnSemicolon">true</PropertyValue>
<PropertyValue name="FormatOnPaste">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterCommaDelimiter">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterFunctionKeywordForAnonymousFunctions">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterKeywordsInControlFlowStatements">true</PropertyValue>
<PropertyValue name="InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis">false</PropertyValue>
<PropertyValue name="InsertSpaceAfterSemicolonInForStatements">true</PropertyValue>
<PropertyValue name="InsertSpaceBeforeAndAfterBinaryOperators">true</PropertyValue>
<PropertyValue name="PlaceOpenBraceOnNewLineForControlBlocks">false</PropertyValue>
<PropertyValue name="PlaceOpenBraceOnNewLineForFunctions">false</PropertyValue>
<PropertyValue name="ShowGruntGulpDialogForAspNet">true</PropertyValue>
<PropertyValue name="ShowVirtualProjectsInSolutionExplorerWhenNoSolution">true</PropertyValue>
<PropertyValue name="ShowVirtualProjectsInSolutionExplorerWhenSolutionOpen">false</PropertyValue>
<PropertyValue name="UseAMDCodeGenerationForModulesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="UseCommonJSCodeGenerationForModulesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="UseES2015CodeGenerationForModulesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="UseJsxPreserveForFilesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="UseJsxReactForFilesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="UseSystemCodeGenerationForModulesThatAreNotPartOfAProject">false</PropertyValue>
<PropertyValue name="UseUMDCodeGenerationForModulesThatAreNotPartOfAProject">false</PropertyValue>
</ToolsOptionsSubCategory>
<ToolsOptionsSubCategory name="HTMLX Specific">
<PropertyValue name="EnableTagNavigator">false</PropertyValue>
<PropertyValue name="EnableValidation">true</PropertyValue>
<PropertyValue name="ErrorsAsWarnings">true</PropertyValue>
<PropertyValue name="FormatOnPaste">true</PropertyValue>
<PropertyValue name="IdentifyHelpfulExtensions">false</PropertyValue>
<PropertyValue name="InsertAttributeValueQuotes">true</PropertyValue>
<PropertyValue name="InsertClosingTag">true</PropertyValue>
<PropertyValue name="XHtmlCodingStyle">true</PropertyValue>
</ToolsOptionsSubCategory>
</ToolsOptionsCategory>
</ToolsOptions>
</UserSettings>

56
Settings.StyleCop

@ -1,56 +0,0 @@
<StyleCopSettings Version="105">
<GlobalSettings>
<CollectionProperty Name="RecognizedWords">
<Value>enum</Value>
<Value>exif</Value>
<Value>uint</Value>
<Value>lossy</Value>
<Value>octree</Value>
<Value>png</Value>
<Value>quantizer</Value>
<Value>unzig</Value>
<Value>cb</Value>
<Value>cr</Value>
<Value>Laplacian</Value>
<Value>Sobel</Value>
<Value>Scharr</Value>
<Value>rgb</Value>
<Value>rgba</Value>
<Value>rrggbb</Value>
<Value>rrggbbaa</Value>
<Value>scanline</Value>
<Value>scanlines</Value>
<Value>png's</Value>
<Value>codeword</Value>
<Value>unscaled</Value>
<Value>zig-zag</Value>
<Value>crc</Value>
<Value>zlib</Value>
<Value>xff</Value>
<Value>xda</Value>
<Value>ss</Value>
<Value>Vol</Value>
<Value>pp</Value>
<Value>cmyk</Value>
<Value>Paeth</Value>
<Value>th</Value>
<Value>bool</Value>
<Value>bools</Value>
<Value>desensitivity</Value>
<Value>premultiplied</Value>
<Value>endianness</Value>
<Value>thresholding</Value>
</CollectionProperty>
</GlobalSettings>
<Analyzers>
<Analyzer AnalyzerId="StyleCop.CSharp.DocumentationRules">
<AnalyzerSettings>
<StringProperty Name="CompanyName">James Jackson-South</StringProperty>
<StringProperty Name="Copyright">
Copyright © James Jackson-South and contributors.
Licensed under the Apache License, Version 2.0.
</StringProperty>
</AnalyzerSettings>
</Analyzer>
</Analyzers>
</StyleCopSettings>

252
src/ImageSharp.Drawing/Brushes/Brushes.cs

@ -8,149 +8,251 @@ namespace ImageSharp.Drawing.Brushes
using ImageSharp.PixelFormats;
/// <summary>
/// A collection of methods for creating brushes. Brushes use <see cref="Rgba32"/> for painting.
/// A collection of methods for creating generic brushes.
/// </summary>
public class Brushes
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static class Brushes
{
/// <summary>
/// Percent10 Hatch Pattern
/// </summary>
/// ---> x axis
/// ^
/// | y - axis
/// |
/// see PatternBrush for details about how to make new patterns work
private static readonly bool[,] Percent10Pattern =
{
{ true, false, false, false },
{ false, false, false, false },
{ false, false, true, false },
{ false, false, false, false }
};
/// <summary>
/// Percent20 pattern.
/// </summary>
private static readonly bool[,] Percent20Pattern =
{
{ true, false, false, false },
{ false, false, true, false },
{ true, false, false, false },
{ false, false, true, false }
};
/// <summary>
/// Horizontal Hatch Pattern
/// </summary>
private static readonly bool[,] HorizontalPattern =
{
{ false },
{ true },
{ false },
{ false }
};
/// <summary>
/// Min Pattern
/// </summary>
private static readonly bool[,] MinPattern =
{
{ false },
{ false },
{ false },
{ true }
};
/// <summary>
/// Vertical Pattern
/// </summary>
private static readonly bool[,] VerticalPattern =
{
{ false, true, false, false },
};
/// <summary>
/// Forward Diagonal Pattern
/// </summary>
private static readonly bool[,] ForwardDiagonalPattern =
{
{ false, false, false, true },
{ false, false, true, false },
{ false, true, false, false },
{ true, false, false, false }
};
/// <summary>
/// Backward Diagonal Pattern
/// </summary>
private static readonly bool[,] BackwardDiagonalPattern =
{
{ true, false, false, false },
{ false, true, false, false },
{ false, false, true, false },
{ false, false, false, true }
};
/// <summary>
/// Create as brush that will paint a solid color
/// </summary>
/// <param name="color">The color.</param>
/// <returns>A Brush</returns>
public static SolidBrush Solid(Rgba32 color)
=> new SolidBrush(color);
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static SolidBrush<TPixel> Solid<TPixel>(TPixel color)
where TPixel : struct, IPixel<TPixel>
=> new SolidBrush<TPixel>(color);
/// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush Percent10(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.Percent10(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Percent10<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, Percent10Pattern);
/// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Percent10 Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush Percent10(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.Percent10(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Percent10<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, Percent10Pattern);
/// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Percent20 Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush Percent20(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.Percent20(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Percent20<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, Percent20Pattern);
/// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Percent20 Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush Percent20(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.Percent20(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Percent20<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, Percent20Pattern);
/// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Horizontal Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush Horizontal(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.Horizontal(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Horizontal<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, HorizontalPattern);
/// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Horizontal Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush Horizontal(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.Horizontal(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Horizontal<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, HorizontalPattern);
/// <summary>
/// Create as brush that will paint a Min Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Min Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush Min(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.Min(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Min<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, MinPattern);
/// <summary>
/// Create as brush that will paint a Min Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Min Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush Min(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.Min(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Min<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, MinPattern);
/// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Vertical Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush Vertical(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.Vertical(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Vertical<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, VerticalPattern);
/// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Vertical Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush Vertical(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.Vertical(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> Vertical<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, VerticalPattern);
/// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush ForwardDiagonal(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.ForwardDiagonal(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> ForwardDiagonal<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, ForwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Forward Diagonal Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush ForwardDiagonal(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.ForwardDiagonal(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> ForwardDiagonal<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, ForwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with
/// in the specified foreground color and a transparent background
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified foreground color and a
/// transparent background.
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <returns>A Brush</returns>
public static PatternBrush BackwardDiagonal(Rgba32 foreColor)
=> new PatternBrush(Brushes<Rgba32>.BackwardDiagonal(foreColor, Rgba32.Transparent));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> BackwardDiagonal<TPixel>(TPixel foreColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, NamedColors<TPixel>.Transparent, BackwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with
/// in the specified foreground and background colors
/// Create as brush that will paint a Backward Diagonal Hatch Pattern with the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush BackwardDiagonal(Rgba32 foreColor, Rgba32 backColor)
=> new PatternBrush(Brushes<Rgba32>.BackwardDiagonal(foreColor, backColor));
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A New <see cref="PatternBrush{TPixel}"/></returns>
public static PatternBrush<TPixel> BackwardDiagonal<TPixel>(TPixel foreColor, TPixel backColor)
where TPixel : struct, IPixel<TPixel>
=> new PatternBrush<TPixel>(foreColor, backColor, BackwardDiagonalPattern);
}
}

168
src/ImageSharp.Drawing/Brushes/Brushes{TPixel}.cs

@ -1,168 +0,0 @@
// <copyright file="Brushes{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Brushes
{
using ImageSharp.PixelFormats;
/// <summary>
/// A collection of methods for creating generic brushes.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A Brush</returns>
public class Brushes<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Percent10 Hatch Pattern
/// </summary>
/// ---> x axis
/// ^
/// | y - axis
/// |
/// see PatternBrush for details about how to make new patterns work
private static readonly bool[,] Percent10Pattern =
{
{ true, false, false, false },
{ false, false, false, false },
{ false, false, true, false },
{ false, false, false, false }
};
/// <summary>
/// Percent20 pattern.
/// </summary>
private static readonly bool[,] Percent20Pattern =
{
{ true, false, false, false },
{ false, false, true, false },
{ true, false, false, false },
{ false, false, true, false }
};
/// <summary>
/// Horizontal Hatch Pattern
/// </summary>
private static readonly bool[,] HorizontalPattern =
{
{ false },
{ true },
{ false },
{ false }
};
/// <summary>
/// Min Pattern
/// </summary>
private static readonly bool[,] MinPattern =
{
{ false },
{ false },
{ false },
{ true }
};
/// <summary>
/// Vertical Pattern
/// </summary>
private static readonly bool[,] VerticalPattern =
{
{ false, true, false, false },
};
/// <summary>
/// Forward Diagonal Pattern
/// </summary>
private static readonly bool[,] ForwardDiagonalPattern =
{
{ false, false, false, true },
{ false, false, true, false },
{ false, true, false, false },
{ true, false, false, false }
};
/// <summary>
/// Backward Diagonal Pattern
/// </summary>
private static readonly bool[,] BackwardDiagonalPattern =
{
{ true, false, false, false },
{ false, true, false, false },
{ false, false, true, false },
{ false, false, false, true }
};
/// <summary>
/// Create as brush that will paint a solid color
/// </summary>
/// <param name="color">The color.</param>
/// <returns>A Brush</returns>
public static SolidBrush<TPixel> Solid(TPixel color)
=> new SolidBrush<TPixel>(color);
/// <summary>
/// Create as brush that will paint a Percent10 Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> Percent10(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, Percent10Pattern);
/// <summary>
/// Create as brush that will paint a Percent20 Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> Percent20(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, Percent20Pattern);
/// <summary>
/// Create as brush that will paint a Horizontal Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> Horizontal(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, HorizontalPattern);
/// <summary>
/// Create as brush that will paint a Min Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> Min(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, MinPattern);
/// <summary>
/// Create as brush that will paint a Vertical Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> Vertical(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, VerticalPattern);
/// <summary>
/// Create as brush that will paint a Forward Diagonal Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> ForwardDiagonal(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, ForwardDiagonalPattern);
/// <summary>
/// Create as brush that will paint a Backward Diagonal Hatch Pattern within the specified colors
/// </summary>
/// <param name="foreColor">Color of the foreground.</param>
/// <param name="backColor">Color of the background.</param>
/// <returns>A Brush</returns>
public static PatternBrush<TPixel> BackwardDiagonal(TPixel foreColor, TPixel backColor)
=> new PatternBrush<TPixel>(foreColor, backColor, BackwardDiagonalPattern);
}
}

24
src/ImageSharp.Drawing/Brushes/ImageBrush.cs

@ -1,24 +0,0 @@
// <copyright file="ImageBrush.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Brushes
{
using ImageSharp.PixelFormats;
/// <summary>
/// Provides an implementation of a solid brush for painting with repeating images. The brush uses <see cref="Rgba32"/> for painting.
/// </summary>
public class ImageBrush : ImageBrush<Rgba32>
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageBrush" /> class.
/// </summary>
/// <param name="image">The image to paint.</param>
public ImageBrush(IImageBase<Rgba32> image)
: base(image)
{
}
}
}

9
src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs

@ -5,7 +5,10 @@
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -114,7 +117,7 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
// create a span for colors
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
@ -122,7 +125,7 @@ namespace ImageSharp.Drawing.Brushes
{
int sourceY = (y - this.offsetY) % this.yLength;
int offsetX = x - this.offsetX;
BufferSpan<TPixel> sourceRow = this.source.GetRowSpan(sourceY);
Span<TPixel> sourceRow = this.source.GetRowSpan(sourceY);
for (int i = 0; i < scanline.Length; i++)
{
@ -133,7 +136,7 @@ namespace ImageSharp.Drawing.Brushes
overlay[i] = pixel;
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

35
src/ImageSharp.Drawing/Brushes/PatternBrush.cs

@ -1,35 +0,0 @@
// <copyright file="PatternBrush.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Brushes
{
using ImageSharp.PixelFormats;
/// <summary>
/// Provides an implementation of a pattern brush for painting patterns. The brush use <see cref="Rgba32"/> for painting.
/// </summary>
public class PatternBrush : PatternBrush<Rgba32>
{
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrush"/> class.
/// </summary>
/// <param name="foreColor">Color of the fore.</param>
/// <param name="backColor">Color of the back.</param>
/// <param name="pattern">The pattern.</param>
public PatternBrush(Rgba32 foreColor, Rgba32 backColor, bool[,] pattern)
: base(foreColor, backColor, pattern)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="PatternBrush"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
internal PatternBrush(PatternBrush<Rgba32> brush)
: base(brush)
{
}
}
}

6
src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -147,7 +149,7 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
int patternY = y % this.pattern.Height;
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
@ -161,7 +163,7 @@ namespace ImageSharp.Drawing.Brushes
overlay[i] = this.pattern[patternY, patternX];
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

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

@ -7,6 +7,8 @@ namespace ImageSharp.Drawing.Processors
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -64,7 +66,7 @@ namespace ImageSharp.Drawing.Processors
/// <param name="x">The x position in the target pixel space that the start of the scanline data corresponds to.</param>
/// <param name="y">The y position in the target pixel space that whole scanline corresponds to.</param>
/// <remarks>scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs.</remarks>
internal virtual void Apply(BufferSpan<float> scanline, int x, int y)
internal virtual void Apply(Span<float> scanline, int x, int y)
{
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
using (Buffer<TPixel> overlay = new Buffer<TPixel>(scanline.Length))
@ -79,7 +81,7 @@ namespace ImageSharp.Drawing.Processors
overlay[i] = this[x + i, y];
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

26
src/ImageSharp.Drawing/Brushes/RecolorBrush.cs

@ -1,26 +0,0 @@
// <copyright file="RecolorBrush.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Brushes
{
using ImageSharp.PixelFormats;
/// <summary>
/// Provides an implementation of a recolor brush for painting color changes.
/// </summary>
public class RecolorBrush : RecolorBrush<Rgba32>
{
/// <summary>
/// Initializes a new instance of the <see cref="RecolorBrush" /> class.
/// </summary>
/// <param name="sourceColor">Color of the source.</param>
/// <param name="targeTPixel">Color of the target.</param>
/// <param name="threshold">The threshold.</param>
public RecolorBrush(Rgba32 sourceColor, Rgba32 targeTPixel, float threshold)
: base(sourceColor, targeTPixel, threshold)
{
}
}
}

7
src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs

@ -5,7 +5,10 @@
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -139,7 +142,7 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
using (Buffer<TPixel> overlay = new Buffer<TPixel>(scanline.Length))
@ -155,7 +158,7 @@ namespace ImageSharp.Drawing.Brushes
overlay[i] = this[offsetX, y];
}
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
this.Blender.Blend(destinationRow, destinationRow, overlay, amountBuffer);
}
}

24
src/ImageSharp.Drawing/Brushes/SolidBrush.cs

@ -1,24 +0,0 @@
// <copyright file="SolidBrush.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Brushes
{
using ImageSharp.PixelFormats;
/// <summary>
/// Provides an implementation of a solid brush for painting solid color areas. The brush uses <see cref="Rgba32"/> for painting.
/// </summary>
public class SolidBrush : SolidBrush<Rgba32>
{
/// <summary>
/// Initializes a new instance of the <see cref="SolidBrush" /> class.
/// </summary>
/// <param name="color">The color.</param>
public SolidBrush(Rgba32 color)
: base(color)
{
}
}
}

7
src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs

@ -5,7 +5,10 @@
namespace ImageSharp.Drawing.Brushes
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processors;
@ -87,9 +90,9 @@ namespace ImageSharp.Drawing.Brushes
}
/// <inheritdoc />
internal override void Apply(BufferSpan<float> scanline, int x, int y)
internal override void Apply(Span<float> scanline, int x, int y)
{
BufferSpan<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
Span<TPixel> destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length);
using (Buffer<float> amountBuffer = new Buffer<float>(scanline.Length))
{

6
src/ImageSharp.Drawing/DrawImage.cs

@ -1,17 +1,15 @@
// <copyright file="DrawImage.cs" company="James Jackson-South">
// <copyright file="DrawImage.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.Processors;
using ImageSharp.Drawing;
using ImageSharp.PixelFormats;
/// <summary>
/// Extension methods for the <see cref="Image"/> type.
/// Extension methods for the <see cref="Image{TPixel}"/> type.
/// </summary>
public static partial class ImageExtensions
{

2
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<AssemblyTitle>ImageSharp.Drawing</AssemblyTitle>
<VersionPrefix>1.0.0-alpha8</VersionPrefix>
<VersionPrefix>1.0.0-alpha9</VersionPrefix>
<Authors>James Jackson-South and contributors</Authors>
<TargetFramework>netstandard1.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

55
src/ImageSharp.Drawing/Pens/Pen.cs

@ -1,55 +0,0 @@
// <copyright file="Pen.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Pens
{
using ImageSharp.PixelFormats;
/// <summary>
/// Represents a <see cref="Pen{TPixel}"/> in the <see cref="Rgba32"/> color space.
/// </summary>
public class Pen : Pen<Rgba32>
{
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
public Pen(Rgba32 color, float width)
: base(color, width)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
public Pen(IBrush<Rgba32> brush, float width)
: base(brush, width)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <param name="pattern">The pattern.</param>
public Pen(IBrush<Rgba32> brush, float width, float[] pattern)
: base(brush, width, pattern)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Pen"/> class.
/// </summary>
/// <param name="pen">The pen.</param>
internal Pen(Pen<Rgba32> pen)
: base(pen)
{
}
}
}

57
src/ImageSharp.Drawing/Pens/Pens.cs

@ -10,86 +10,121 @@ namespace ImageSharp.Drawing.Pens
/// <summary>
/// Common Pen styles
/// </summary>
public class Pens
public static class Pens
{
private static readonly float[] DashDotPattern = new[] { 3f, 1f, 1f, 1f };
private static readonly float[] DashDotDotPattern = new[] { 3f, 1f, 1f, 1f, 1f, 1f };
private static readonly float[] DottedPattern = new[] { 1f, 1f };
private static readonly float[] DashedPattern = new[] { 3f, 1f };
/// <summary>
/// Create a solid pen with out any drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen Solid(Rgba32 color, float width) => new Pen(color, width);
public static Pen<TPixel> Solid<TPixel>(TPixel color, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width);
/// <summary>
/// Create a solid pen with out any drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen Solid(IBrush<Rgba32> brush, float width) => new Pen(brush, width);
public static Pen<TPixel> Solid<TPixel>(IBrush<TPixel> brush, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width);
/// <summary>
/// Create a pen with a 'Dash' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen Dash(Rgba32 color, float width) => new Pen(Pens<Rgba32>.Dash(color, width));
public static Pen<TPixel> Dash<TPixel>(TPixel color, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DashedPattern);
/// <summary>
/// Create a pen with a 'Dash' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen Dash(IBrush<Rgba32> brush, float width) => new Pen(Pens<Rgba32>.Dash(brush, width));
public static Pen<TPixel> Dash<TPixel>(IBrush<TPixel> brush, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DashedPattern);
/// <summary>
/// Create a pen with a 'Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen Dot(Rgba32 color, float width) => new Pen(Pens<Rgba32>.Dot(color, width));
public static Pen<TPixel> Dot<TPixel>(TPixel color, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DottedPattern);
/// <summary>
/// Create a pen with a 'Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen Dot(IBrush<Rgba32> brush, float width) => new Pen(Pens<Rgba32>.Dot(brush, width));
public static Pen<TPixel> Dot<TPixel>(IBrush<TPixel> brush, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DottedPattern);
/// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen DashDot(Rgba32 color, float width) => new Pen(Pens<Rgba32>.DashDot(color, width));
public static Pen<TPixel> DashDot<TPixel>(TPixel color, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DashDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen DashDot(IBrush<Rgba32> brush, float width) => new Pen(Pens<Rgba32>.DashDot(brush, width));
public static Pen<TPixel> DashDot<TPixel>(IBrush<TPixel> brush, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DashDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen DashDotDot(Rgba32 color, float width) => new Pen(Pens<Rgba32>.DashDotDot(color, width));
public static Pen<TPixel> DashDotDot<TPixel>(TPixel color, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(color, width, DashDotDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <typeparam name="TPixel">The type of the color.</typeparam>
/// <returns>The Pen</returns>
public static Pen DashDotDot(IBrush<Rgba32> brush, float width) => new Pen(Pens<Rgba32>.DashDotDot(brush, width));
public static Pen<TPixel> DashDotDot<TPixel>(IBrush<TPixel> brush, float width)
where TPixel : struct, IPixel<TPixel>
=> new Pen<TPixel>(brush, width, DashDotDotPattern);
}
}

112
src/ImageSharp.Drawing/Pens/Pens{TPixel}.cs

@ -1,112 +0,0 @@
// <copyright file="Pens{TPixel}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Drawing.Pens
{
using ImageSharp.PixelFormats;
/// <summary>
/// Common Pen styles
/// </summary>
/// <typeparam name="TPixel">The type of the color.</typeparam>
public class Pens<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private static readonly float[] DashDotPattern = new[] { 3f, 1f, 1f, 1f };
private static readonly float[] DashDotDotPattern = new[] { 3f, 1f, 1f, 1f, 1f, 1f };
private static readonly float[] DottedPattern = new[] { 1f, 1f };
private static readonly float[] DashedPattern = new[] { 3f, 1f };
/// <summary>
/// Create a solid pen with out any drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> Solid(TPixel color, float width)
=> new Pen<TPixel>(color, width);
/// <summary>
/// Create a solid pen with out any drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> Solid(IBrush<TPixel> brush, float width)
=> new Pen<TPixel>(brush, width);
/// <summary>
/// Create a pen with a 'Dash' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> Dash(TPixel color, float width)
=> new Pen<TPixel>(color, width, DashedPattern);
/// <summary>
/// Create a pen with a 'Dash' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> Dash(IBrush<TPixel> brush, float width)
=> new Pen<TPixel>(brush, width, DashedPattern);
/// <summary>
/// Create a pen with a 'Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> Dot(TPixel color, float width)
=> new Pen<TPixel>(color, width, DottedPattern);
/// <summary>
/// Create a pen with a 'Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> Dot(IBrush<TPixel> brush, float width)
=> new Pen<TPixel>(brush, width, DottedPattern);
/// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> DashDot(TPixel color, float width)
=> new Pen<TPixel>(color, width, DashDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> DashDot(IBrush<TPixel> brush, float width)
=> new Pen<TPixel>(brush, width, DashDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> DashDotDot(TPixel color, float width)
=> new Pen<TPixel>(color, width, DashDotDotPattern);
/// <summary>
/// Create a pen with a 'Dash Dot Dot' drawing patterns
/// </summary>
/// <param name="brush">The brush.</param>
/// <param name="width">The width.</param>
/// <returns>The Pen</returns>
public static Pen<TPixel> DashDotDot(IBrush<TPixel> brush, float width)
=> new Pen<TPixel>(brush, width, DashDotDotPattern);
}
}

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

@ -8,6 +8,8 @@ namespace ImageSharp.Drawing.Processors
using System;
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
@ -97,8 +99,8 @@ namespace ImageSharp.Drawing.Processors
this.ParallelOptions,
y =>
{
BufferSpan<TPixel> background = sourcePixels.GetRowSpan(y).Slice(minX, width);
BufferSpan<TPixel> foreground = toBlendPixels.GetRowSpan(y - this.Location.Y).Slice(0, width);
Span<TPixel> background = sourcePixels.GetRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = toBlendPixels.GetRowSpan(y - this.Location.Y).Slice(0, width);
this.blender.Blend(background, background, foreground, amount);
});
}

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

@ -8,6 +8,8 @@ namespace ImageSharp.Drawing.Processors
using System;
using System.Numerics;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;
using Pens;
@ -110,7 +112,7 @@ namespace ImageSharp.Drawing.Processors
colors[i] = color.Color;
}
BufferSpan<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
Span<TPixel> destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width);
blender.Blend(destination, destination, colors, amount);
}
});

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

@ -10,6 +10,8 @@ namespace ImageSharp.Drawing.Processors
using System.Threading.Tasks;
using Drawing;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;

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

@ -8,6 +8,8 @@ namespace ImageSharp.Drawing.Processors
using System;
using System.Buffers;
using Drawing;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using ImageSharp.Processing;

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

@ -54,7 +54,7 @@ namespace ImageSharp
public static Image<TPixel> DrawText<TPixel>(this Image<TPixel> source, string text, Font font, TPixel color, Vector2 location, TextGraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
{
return source.DrawText(text, font, Brushes<TPixel>.Solid(color), null, location, options);
return source.DrawText(text, font, Brushes.Solid(color), null, location, options);
}
/// <summary>

40
src/ImageSharp/Common/Helpers/DebugGuard.cs

@ -159,5 +159,45 @@ namespace ImageSharp
throw new ArgumentException(message, parameterName);
}
}
/// <summary>
/// Verifies, that the target span is of same size than the 'other' span.
/// </summary>
/// <typeparam name="T">The element type of the spans</typeparam>
/// <param name="target">The target span.</param>
/// <param name="other">The 'other' span to compare 'target' to.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="target"/> is true
/// </exception>
[Conditional("DEBUG")]
public static void MustBeSameSized<T>(Span<T> target, Span<T> other, string parameterName)
where T : struct
{
if (target.Length != other.Length)
{
throw new ArgumentException("Span-s must be the same size!", parameterName);
}
}
/// <summary>
/// Verifies, that the `target` span has the length of 'minSpan', or longer.
/// </summary>
/// <typeparam name="T">The element type of the spans</typeparam>
/// <param name="target">The target span.</param>
/// <param name="minSpan">The 'minSpan' span to compare 'target' to.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="target"/> is true
/// </exception>
[Conditional("DEBUG")]
public static void MustBeSizedAtLeast<T>(Span<T> target, Span<T> minSpan, string parameterName)
where T : struct
{
if (target.Length < minSpan.Length)
{
throw new ArgumentException($"Span-s must be at least of length {minSpan.Length}!", parameterName);
}
}
}
}

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

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

2
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -146,7 +146,7 @@ namespace ImageSharp
/// than the given one.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="bitmap">The <see cref="Image"/> to search within.</param>
/// <param name="bitmap">The <see cref="Image{TPixel}"/> to search within.</param>
/// <param name="componentValue">The color component value to remove.</param>
/// <param name="channel">The <see cref="RgbaComponent"/> channel to test against.</param>
/// <returns>

205
src/ImageSharp/Common/Memory/BufferSpan{T}.cs

@ -1,205 +0,0 @@
// <copyright file="BufferSpan{T}.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.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Represents a contiguous region of a pinned managed array.
/// The array is usually owned by a <see cref="Buffer{T}"/> instance.
/// </summary>
/// <remarks>
/// <see cref="BufferSpan{T}"/> is very similar to corefx System.Span&lt;T&gt;, and we try to maintain a compatible API.
/// There are several differences though:
/// - It's not possible to use it with stack objects or pointers to unmanaged memory, only with managed arrays.
/// - It's possible to retrieve a reference to the array (<see cref="Array"/>) so we can pass it to API-s like <see cref="Marshal.Copy(byte[], int, IntPtr, int)"/>
/// - It's possible to retrieve the pinned pointer. This enables optimized (unchecked) unsafe operations.
/// - There is no bounds checking for performance reasons, only in debug mode. This makes <see cref="BufferSpan{T}"/> an unsafe type!
/// </remarks>
/// <typeparam name="T">The type of elements of the array</typeparam>
internal unsafe struct BufferSpan<T>
where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="start">The index at which to begin the span.</param>
/// <param name="length">The length</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, int start, int length)
{
GuardArray(array);
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length));
this.Array = array;
this.Length = length;
this.Start = start;
}
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="start">The index at which to begin the span.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, int start)
{
GuardArray(array);
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
this.Array = array;
this.Length = array.Length - start;
this.Start = start;
}
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array.
/// </summary>
/// <param name="array">The pinned array</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array)
{
GuardArray(array);
this.Array = array;
this.Start = 0;
this.Length = array.Length;
}
/// <summary>
/// Gets the backing array.
/// </summary>
public T[] Array { get; private set; }
/// <summary>
/// Gets the length of the <see cref="BufferSpan{T}"/>
/// </summary>
public int Length { get; private set; }
/// <summary>
/// Gets the start inside <see cref="Array"/>
/// </summary>
public int Start { get; private set; }
/// <summary>
/// Gets the start inside <see cref="Array"/> in bytes.
/// </summary>
public int ByteOffset => this.Start * Unsafe.SizeOf<T>();
/// <summary>
/// Returns a reference to specified element of the span.
/// </summary>
/// <param name="index">The index</param>
/// <returns>The reference to the specified element</returns>
public ref T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
ref T startRef = ref this.DangerousGetPinnableReference();
return ref Unsafe.Add(ref startRef, index);
}
}
/// <summary>
/// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes
/// setting it's <see cref="Start"/> and <see cref="Length"/> to correct values.
/// </summary>
/// <returns>The span of bytes</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<byte> AsBytes()
{
BufferSpan<byte> result = default(BufferSpan<byte>);
result.Array = Unsafe.As<byte[]>(this.Array);
result.Start = this.Start * Unsafe.SizeOf<T>();
result.Length = this.Length * Unsafe.SizeOf<T>();
return result;
}
/// <summary>
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
/// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
/// </summary>
/// <returns>The reference to the 0th element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T DangerousGetPinnableReference()
{
ref T origin = ref this.Array[0];
return ref Unsafe.Add(ref origin, this.Start);
}
/// <summary>
/// Forms a slice out of the given BufferSpan, beginning at 'start'.
/// </summary>
/// <param name="start">TThe index at which to begin this slice.</param>
/// <returns>The offseted (sliced) BufferSpan</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start)
{
DebugGuard.MustBeLessThan(start, this.Length, nameof(start));
BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array;
result.Start = this.Start + start;
result.Length = this.Length - start;
return result;
}
/// <summary>
/// Forms a slice out of the given BufferSpan, beginning at 'start'.
/// </summary>
/// <param name="start">The index at which to begin this slice.</param>
/// <param name="length">The desired length for the slice (exclusive).</param>
/// <returns>The sliced BufferSpan</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start, int length)
{
DebugGuard.MustBeLessThanOrEqualTo(start, this.Length, nameof(start));
DebugGuard.MustBeLessThanOrEqualTo(length, this.Length - start, nameof(length));
BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array;
result.Start = this.Start + start;
result.Length = length;
return result;
}
/// <summary>
/// Clears `count` elements from the beginning of the span.
/// </summary>
/// <param name="count">The number of elements to clear</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear(int count)
{
DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count));
// TODO: Use Unsafe.InitBlock(ref T) for small arrays, when it get's official
System.Array.Clear(this.Array, this.Start, count);
}
/// <summary>
/// Clears the the span
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
this.Clear(this.Length);
}
[Conditional("DEBUG")]
private static void GuardArray(T[] array)
{
DebugGuard.NotNull(array, nameof(array));
}
}
}

2
src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Atkinson image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Burks image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

1
src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs

@ -8,6 +8,7 @@ namespace ImageSharp.Dithering
using System.Numerics;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

2
src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Floyd–Steinberg image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the JarvisJudiceNinke image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Sierra2 image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Sierra3 image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the SierraLite image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the Stucki image dithering algorithm.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/Ordered/Bayer.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering.Ordered
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the 4x4 Bayer dithering matrix.
/// <see href="http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT"/>

2
src/ImageSharp/Dithering/Ordered/Ordered.cs

@ -5,6 +5,8 @@
namespace ImageSharp.Dithering.Ordered
{
using ImageSharp.Memory;
/// <summary>
/// Applies error diffusion based dithering using the 4x4 ordered dithering matrix.
/// <see href="https://en.wikipedia.org/wiki/Ordered_dithering"/>

1
src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Dithering.Ordered
{
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>

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

@ -127,7 +127,7 @@ namespace ImageSharp.Formats
+ $"bigger then the max allowed size '{Image<TPixel>.MaxWidth}x{Image<TPixel>.MaxHeight}'");
}
Image<TPixel> image = Image.Create<TPixel>(this.infoHeader.Width, this.infoHeader.Height, this.configuration);
Image<TPixel> image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height);
using (PixelAccessor<TPixel> pixels = image.Lock())
{
switch (this.infoHeader.Compression)

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

@ -366,7 +366,7 @@ namespace ImageSharp.Formats
this.metaData.Quality = colorTableLength / 3;
// This initializes the image to become fully transparent because the alpha channel is zero.
this.image = Image.Create<TPixel>(imageWidth, imageHeight, this.metaData, this.configuration);
this.image = new Image<TPixel>(this.configuration, imageWidth, imageHeight, this.metaData);
this.SetFrameMetaData(this.metaData);

55
src/ImageSharp/Formats/Jpeg/Components/Decoder/DecodedBlockArray.cs

@ -1,55 +0,0 @@
// <copyright file="DecodedBlockArray.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats.Jpg
{
using System;
using System.Buffers;
/// <summary>
/// Because <see cref="System.Array.Length"/> has no information for rented arrays,
/// we need to store the count and the buffer separately when storing pooled <see cref="DecodedBlock"/> arrays.
/// </summary>
internal struct DecodedBlockArray : IDisposable
{
/// <summary>
/// The <see cref="ArrayPool{T}"/> used to pool data in <see cref="JpegDecoderCore.DecodedBlocks"/>.
/// Should always clean arrays when returning!
/// </summary>
private static readonly ArrayPool<DecodedBlock> ArrayPool = ArrayPool<DecodedBlock>.Create();
/// <summary>
/// Initializes a new instance of the <see cref="DecodedBlockArray"/> struct. Rents a buffer.
/// </summary>
/// <param name="count">The number of valid <see cref="DecodedBlock"/>-s</param>
public DecodedBlockArray(int count)
{
this.Count = count;
this.Buffer = ArrayPool.Rent(count);
}
/// <summary>
/// Gets the number of actual <see cref="DecodedBlock"/>-s inside <see cref="Buffer"/>
/// </summary>
public int Count { get; }
/// <summary>
/// Gets the rented buffer.
/// </summary>
public DecodedBlock[] Buffer { get; private set; }
/// <summary>
/// Returns the rented buffer to the pool.
/// </summary>
public void Dispose()
{
if (this.Buffer != null)
{
ArrayPool.Return(this.Buffer, true);
this.Buffer = null;
}
}
}
}

10
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockProcessor.cs

@ -8,8 +8,10 @@ namespace ImageSharp.Formats.Jpg
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ImageSharp.Memory;
/// <summary>
/// Encapsulates the implementation of processing "raw" <see cref="DecodedBlockArray"/>-s into Jpeg image channels.
/// Encapsulates the implementation of processing "raw" <see cref="Buffer{T}"/>-s into Jpeg image channels.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct JpegBlockProcessor
@ -47,10 +49,10 @@ namespace ImageSharp.Formats.Jpg
/// <param name="decoder">The <see cref="JpegDecoderCore"/> instance</param>
public void ProcessAllBlocks(JpegDecoderCore decoder)
{
DecodedBlockArray blockArray = decoder.DecodedBlocks[this.componentIndex];
for (int i = 0; i < blockArray.Count; i++)
Buffer<DecodedBlock> blockArray = decoder.DecodedBlocks[this.componentIndex];
for (int i = 0; i < blockArray.Length; i++)
{
this.ProcessBlockColors(decoder, ref blockArray.Buffer[i]);
this.ProcessBlockColors(decoder, ref blockArray[i]);
}
}

64
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegPixelArea.cs

@ -4,9 +4,10 @@
// </copyright>
namespace ImageSharp.Formats.Jpg
{
using System.Buffers;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary>
/// Represents an area of a Jpeg subimage (channel)
/// </summary>
@ -15,20 +16,30 @@ namespace ImageSharp.Formats.Jpg
/// <summary>
/// Initializes a new instance of the <see cref="JpegPixelArea" /> struct from existing data.
/// </summary>
/// <param name="pixels">The pixel array</param>
/// <param name="striede">The stride</param>
/// <param name="pixels">The pixel buffer</param>
/// <param name="stride">The stride</param>
/// <param name="offset">The offset</param>
public JpegPixelArea(byte[] pixels, int striede, int offset)
public JpegPixelArea(Buffer2D<byte> pixels, int stride, int offset)
{
this.Stride = striede;
this.Stride = stride;
this.Pixels = pixels;
this.Offset = offset;
}
/// <summary>
/// Gets the pixels.
/// Initializes a new instance of the <see cref="JpegPixelArea" /> struct from existing buffer.
/// <see cref="Stride"/> will be set to <see cref="Buffer2D{T}.Width"/> of <paramref name="pixels"/> and <see cref="Offset"/> will be set to 0.
/// </summary>
/// <param name="pixels">The pixel buffer</param>
public JpegPixelArea(Buffer2D<byte> pixels)
: this(pixels, pixels.Width, 0)
{
}
/// <summary>
/// Gets the pixels buffer.
/// </summary>
public byte[] Pixels { get; private set; }
public Buffer2D<byte> Pixels { get; private set; }
/// <summary>
/// Gets a value indicating whether the instance has been initalized. (Is not default(JpegPixelArea))
@ -36,21 +47,19 @@ namespace ImageSharp.Formats.Jpg
public bool IsInitialized => this.Pixels != null;
/// <summary>
/// Gets or the stride.
/// Gets the stride.
/// </summary>
public int Stride { get; }
/// <summary>
/// Gets or the offset.
/// Gets the offset.
/// </summary>
public int Offset { get; }
/// <summary>
/// Gets a <see cref="MutableSpan{T}" /> of bytes to the pixel area
/// </summary>
public MutableSpan<byte> Span => new MutableSpan<byte>(this.Pixels, this.Offset);
private static ArrayPool<byte> BytePool => ArrayPool<byte>.Shared;
public MutableSpan<byte> Span => new MutableSpan<byte>(this.Pixels.Array, this.Offset);
/// <summary>
/// Returns the pixel at (x, y)
@ -67,35 +76,6 @@ namespace ImageSharp.Formats.Jpg
}
}
/// <summary>
/// Creates a new instance of the <see cref="JpegPixelArea" /> struct.
/// Pixel array will be taken from a pool, this instance will be the owner of it's pixel data, therefore
/// <see cref="ReturnPooled" /> should be called when the instance is no longer needed.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <returns>A <see cref="JpegPixelArea" /> with pooled data</returns>
public static JpegPixelArea CreatePooled(int width, int height)
{
int size = width * height;
byte[] pixels = BytePool.Rent(size);
return new JpegPixelArea(pixels, width, 0);
}
/// <summary>
/// Returns <see cref="Pixels" /> to the pool
/// </summary>
public void ReturnPooled()
{
if (this.Pixels == null)
{
return;
}
BytePool.Return(this.Pixels);
this.Pixels = null;
}
/// <summary>
/// Gets the subarea that belongs to the Block8x8 defined by block indices
/// </summary>
@ -129,7 +109,7 @@ namespace ImageSharp.Formats.Jpg
public unsafe void LoadColorsFrom(Block8x8F* block, Block8x8F* temp)
{
// Level shift by +128, clip to [0, 255], and write to dst.
block->CopyColorsTo(new MutableSpan<byte>(this.Pixels, this.Offset), this.Stride, temp);
block->CopyColorsTo(new MutableSpan<byte>(this.Pixels.Array, this.Offset), this.Stride, temp);
}
}
}

8
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegScanDecoder.cs

@ -9,6 +9,8 @@ namespace ImageSharp.Formats.Jpg
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using ImageSharp.Memory;
/// <summary>
/// Encapsulates the impementation of Jpeg SOS Huffman decoding. See JpegScanDecoder.md!
///
@ -171,7 +173,7 @@ namespace ImageSharp.Formats.Jpg
// Take an existing block (required when progressive):
int blockIndex = this.GetBlockIndex(decoder);
this.data.Block = decoder.DecodedBlocks[this.ComponentIndex].Buffer[blockIndex].Block;
this.data.Block = decoder.DecodedBlocks[this.ComponentIndex][blockIndex].Block;
if (!decoder.InputProcessor.UnexpectedEndOfStreamReached)
{
@ -179,8 +181,8 @@ namespace ImageSharp.Formats.Jpg
}
// Store the decoded block
DecodedBlockArray blocks = decoder.DecodedBlocks[this.ComponentIndex];
blocks.Buffer[blockIndex].SaveBlock(this.bx, this.by, ref this.data.Block);
Buffer<DecodedBlock> blocks = decoder.DecodedBlocks[this.ComponentIndex];
blocks[blockIndex].SaveBlock(this.bx, this.by, ref this.data.Block);
}
// for j

20
src/ImageSharp/Formats/Jpeg/Components/Decoder/YCbCrImage.cs

@ -7,6 +7,8 @@ namespace ImageSharp.Formats.Jpg
using System;
using System.Buffers;
using ImageSharp.Memory;
/// <summary>
/// Represents an image made up of three color components (luminance, blue chroma, red chroma)
/// </summary>
@ -17,17 +19,17 @@ namespace ImageSharp.Formats.Jpg
/// <summary>
/// Gets the luminance components channel as <see cref="JpegPixelArea" />.
/// </summary>
public JpegPixelArea YChannel;
public Buffer2D<byte> YChannel;
/// <summary>
/// Gets the blue chroma components channel as <see cref="JpegPixelArea" />.
/// </summary>
public JpegPixelArea CbChannel;
public Buffer2D<byte> CbChannel;
/// <summary>
/// Gets an offseted <see cref="JpegPixelArea" /> to the Cr channel
/// </summary>
public JpegPixelArea CrChannel;
public Buffer2D<byte> CrChannel;
#pragma warning restore SA1401
/// <summary>
@ -44,9 +46,9 @@ namespace ImageSharp.Formats.Jpg
this.YStride = width;
this.CStride = cSize.Width;
this.YChannel = JpegPixelArea.CreatePooled(width, height);
this.CbChannel = JpegPixelArea.CreatePooled(cSize.Width, cSize.Height);
this.CrChannel = JpegPixelArea.CreatePooled(cSize.Width, cSize.Height);
this.YChannel = Buffer2D<byte>.CreateClean(width, height);
this.CbChannel = Buffer2D<byte>.CreateClean(cSize.Width, cSize.Height);
this.CrChannel = Buffer2D<byte>.CreateClean(cSize.Width, cSize.Height);
}
/// <summary>
@ -106,9 +108,9 @@ namespace ImageSharp.Formats.Jpg
/// </summary>
public void Dispose()
{
this.YChannel.ReturnPooled();
this.CbChannel.ReturnPooled();
this.CrChannel.ReturnPooled();
this.YChannel.Dispose();
this.CbChannel.Dispose();
this.CrChannel.Dispose();
}
/// <summary>

55
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -12,6 +12,7 @@ namespace ImageSharp.Formats
using System.Threading.Tasks;
using ImageSharp.Formats.Jpg;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -112,7 +113,7 @@ namespace ImageSharp.Formats
this.QuantizationTables = new Block8x8F[MaxTq + 1];
this.Temp = new byte[2 * Block8x8F.ScalarCount];
this.ComponentArray = new Component[MaxComponents];
this.DecodedBlocks = new DecodedBlockArray[MaxComponents];
this.DecodedBlocks = new Buffer<DecodedBlock>[MaxComponents];
}
/// <summary>
@ -126,12 +127,12 @@ namespace ImageSharp.Formats
public HuffmanTree[] HuffmanTrees { get; }
/// <summary>
/// Gets the array of <see cref="DecodedBlockArray"/>-s storing the "raw" frequency-domain decoded blocks.
/// Gets the array of <see cref="Buffer{T}"/>-s storing the "raw" frequency-domain decoded blocks.
/// We need to apply IDCT, dequantiazition and unzigging to transform them into color-space blocks.
/// This is done by <see cref="ProcessBlocksIntoJpegImageChannels{TPixel}"/>.
/// When <see cref="IsProgressive"/>==true, we are touching these blocks multiple times - each time we process a Scan.
/// </summary>
public DecodedBlockArray[] DecodedBlocks { get; }
public Buffer<DecodedBlock>[] DecodedBlocks { get; }
/// <summary>
/// Gets the quantization tables, in zigzag order.
@ -217,15 +218,15 @@ namespace ImageSharp.Formats
this.HuffmanTrees[i].Dispose();
}
foreach (DecodedBlockArray blockArray in this.DecodedBlocks)
foreach (Buffer<DecodedBlock> blockArray in this.DecodedBlocks)
{
blockArray.Dispose();
blockArray?.Dispose();
}
this.ycbcrImage?.Dispose();
this.InputProcessor.Dispose();
this.grayImage.ReturnPooled();
this.blackImage.ReturnPooled();
this.grayImage.Pixels?.Dispose();
this.blackImage.Pixels?.Dispose();
}
/// <summary>
@ -244,11 +245,11 @@ namespace ImageSharp.Formats
switch (compIndex)
{
case 0:
return this.ycbcrImage.YChannel;
return new JpegPixelArea(this.ycbcrImage.YChannel);
case 1:
return this.ycbcrImage.CbChannel;
return new JpegPixelArea(this.ycbcrImage.CbChannel);
case 2:
return this.ycbcrImage.CrChannel;
return new JpegPixelArea(this.ycbcrImage.CrChannel);
case 3:
return this.blackImage;
default:
@ -486,7 +487,7 @@ namespace ImageSharp.Formats
private Image<TPixel> ConvertJpegPixelsToImagePixels<TPixel>(ImageMetaData metadata)
where TPixel : struct, IPixel<TPixel>
{
Image<TPixel> image = Image.Create<TPixel>(this.ImageWidth, this.ImageHeight, metadata, this.configuration);
Image<TPixel> image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, metadata);
if (this.grayImage.IsInitialized)
{
@ -590,9 +591,9 @@ namespace ImageSharp.Formats
for (int x = 0; x < image.Width; x++)
{
byte cyan = this.ycbcrImage.YChannel.Pixels[yo + x];
byte magenta = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
byte yellow = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
byte cyan = this.ycbcrImage.YChannel[yo + x];
byte magenta = this.ycbcrImage.CbChannel[co + (x / scale)];
byte yellow = this.ycbcrImage.CrChannel[co + (x / scale)];
TPixel packed = default(TPixel);
this.PackCmyk(ref packed, cyan, magenta, yellow, x, y);
@ -659,9 +660,9 @@ namespace ImageSharp.Formats
for (int x = 0; x < image.Width; x++)
{
byte red = this.ycbcrImage.YChannel.Pixels[yo + x];
byte green = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
byte blue = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
byte red = this.ycbcrImage.YChannel[yo + x];
byte green = this.ycbcrImage.CbChannel[co + (x / scale)];
byte blue = this.ycbcrImage.CrChannel[co + (x / scale)];
TPixel packed = default(TPixel);
packed.PackFromBytes(red, green, blue, 255);
@ -691,9 +692,9 @@ namespace ImageSharp.Formats
y =>
{
// TODO. This Parallel loop doesn't give us the boost it should.
ref byte ycRef = ref this.ycbcrImage.YChannel.Pixels[0];
ref byte cbRef = ref this.ycbcrImage.CbChannel.Pixels[0];
ref byte crRef = ref this.ycbcrImage.CrChannel.Pixels[0];
ref byte ycRef = ref this.ycbcrImage.YChannel[0];
ref byte cbRef = ref this.ycbcrImage.CbChannel[0];
ref byte crRef = ref this.ycbcrImage.CrChannel[0];
fixed (YCbCrToRgbTables* tables = &yCbCrToRgbTables)
{
// TODO: Simplify + optimize + share duplicate code across converter methods
@ -741,9 +742,9 @@ namespace ImageSharp.Formats
for (int x = 0; x < image.Width; x++)
{
byte yy = this.ycbcrImage.YChannel.Pixels[yo + x];
byte cb = this.ycbcrImage.CbChannel.Pixels[co + (x / scale)];
byte cr = this.ycbcrImage.CrChannel.Pixels[co + (x / scale)];
byte yy = this.ycbcrImage.YChannel[yo + x];
byte cb = this.ycbcrImage.CbChannel[co + (x / scale)];
byte cr = this.ycbcrImage.CrChannel[co + (x / scale)];
TPixel packed = default(TPixel);
this.PackYcck(ref packed, yy, cb, cr, x, y);
@ -791,7 +792,8 @@ namespace ImageSharp.Formats
if (this.ComponentCount == 1)
{
this.grayImage = JpegPixelArea.CreatePooled(8 * this.MCUCountX, 8 * this.MCUCountY);
Buffer2D<byte> buffer = Buffer2D<byte>.CreateClean(8 * this.MCUCountX, 8 * this.MCUCountY);
this.grayImage = new JpegPixelArea(buffer);
}
else
{
@ -830,7 +832,8 @@ namespace ImageSharp.Formats
int h3 = this.ComponentArray[3].HorizontalFactor;
int v3 = this.ComponentArray[3].VerticalFactor;
this.blackImage = JpegPixelArea.CreatePooled(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
Buffer2D<byte> buffer = Buffer2D<byte>.CreateClean(8 * h3 * this.MCUCountX, 8 * v3 * this.MCUCountY);
this.blackImage = new JpegPixelArea(buffer);
}
}
}
@ -1358,7 +1361,7 @@ namespace ImageSharp.Formats
{
int count = this.TotalMCUCount * this.ComponentArray[i].HorizontalFactor
* this.ComponentArray[i].VerticalFactor;
this.DecodedBlocks[i] = new DecodedBlockArray(count);
this.DecodedBlocks[i] = Buffer<DecodedBlock>.CreateClean(count);
}
}
}

65
src/ImageSharp/Formats/Png/Filters/AverageFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -12,28 +13,37 @@ namespace ImageSharp.Formats
/// the value of a pixel.
/// <see href="https://www.w3.org/TR/PNG-Filters.html"/>
/// </summary>
internal static unsafe class AverageFilter
internal static class AverageFilter
{
/// <summary>
/// Decodes the scanline
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel)
public static void Decode(Span<byte> scanline, Span<byte> previousScanline, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference();
// Average(x) + floor((Raw(x-bpp)+Prior(x))/2)
fixed (byte* scan = scanline)
fixed (byte* prev = previousScanline)
for (int x = 1; x < scanline.Length; x++)
{
for (int x = 1; x < bytesPerScanline; x++)
if (x - bytesPerPixel < 1)
{
byte left = (x - bytesPerPixel < 1) ? (byte)0 : scan[x - bytesPerPixel];
byte above = prev[x];
scan[x] = (byte)((scan[x] + Average(left, above)) % 256);
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)((scan + (above >> 1)) % 256);
}
else
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)((scan + Average(left, above)) % 256);
}
}
}
@ -46,21 +56,34 @@ namespace ImageSharp.Formats
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerPixel)
public static void Encode(Span<byte> scanline, Span<byte> previousScanline, Span<byte> result, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference();
ref byte resultBaseRef = ref result.DangerousGetPinnableReference();
// Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2)
fixed (byte* scan = scanline)
fixed (byte* prev = previousScanline)
fixed (byte* res = result)
{
res[0] = 3;
resultBaseRef = 3;
for (int x = 0; x < scanline.Length; x++)
for (int x = 0; x < scanline.Length; x++)
{
if (x - bytesPerPixel < 0)
{
byte left = (x - bytesPerPixel < 0) ? (byte)0 : scan[x - bytesPerPixel];
byte above = prev[x];
res[x + 1] = (byte)((scan[x] - Average(left, above)) % 256);
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)((scan - (above >> 1)) % 256);
}
else
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
byte above = Unsafe.Add(ref prevBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)((scan - Average(left, above)) % 256);
}
}
}

19
src/ImageSharp/Formats/Png/Filters/NoneFilter.cs

@ -8,6 +8,8 @@ namespace ImageSharp.Formats
using System;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
/// <summary>
/// The None filter, the scanline is transmitted unmodified; it is only necessary to
/// insert a filter type byte before the data.
@ -15,29 +17,18 @@ namespace ImageSharp.Formats
/// </summary>
internal static class NoneFilter
{
/// <summary>
/// Decodes the scanline
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <returns>The <see cref="T:byte[]"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte[] Decode(byte[] scanline)
{
// No change required.
return scanline;
}
/// <summary>
/// Encodes the scanline
/// </summary>
/// <param name="scanline">The scanline to encode</param>
/// <param name="result">The filtered scanline result.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(byte[] scanline, byte[] result)
public static void Encode(Span<byte> scanline, Span<byte> result)
{
// Insert a byte before the data.
result[0] = 0;
Buffer.BlockCopy(scanline, 0, result, 1, scanline.Length);
result = result.Slice(1);
SpanHelper.Copy(scanline, result);
}
}
}

68
src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

@ -21,22 +21,31 @@ namespace ImageSharp.Formats
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel)
public static void Decode(Span<byte> scanline, Span<byte> previousScanline, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference();
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
fixed (byte* scan = scanline)
fixed (byte* prev = previousScanline)
for (int x = 1; x < scanline.Length; x++)
{
for (int x = 1; x < bytesPerScanline; x++)
if (x - bytesPerPixel < 1)
{
byte left = (x - bytesPerPixel < 1) ? (byte)0 : scan[x - bytesPerPixel];
byte above = prev[x];
byte upperLeft = (x - bytesPerPixel < 1) ? (byte)0 : prev[x - bytesPerPixel];
scan[x] = (byte)((scan[x] + PaethPredicator(left, above, upperLeft)) % 256);
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)((scan + PaethPredicator(0, above, 0)) % 256);
}
else
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
byte above = Unsafe.Add(ref prevBaseRef, x);
byte upperLeft = Unsafe.Add(ref prevBaseRef, x - bytesPerPixel);
scan = (byte)((scan + PaethPredicator(left, above, upperLeft)) % 256);
}
}
}
@ -49,22 +58,35 @@ namespace ImageSharp.Formats
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerPixel)
public static void Encode(Span<byte> scanline, Span<byte> previousScanline, Span<byte> result, int bytesPerPixel)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference();
ref byte resultBaseRef = ref result.DangerousGetPinnableReference();
// Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp))
fixed (byte* scan = scanline)
fixed (byte* prev = previousScanline)
fixed (byte* res = result)
{
res[0] = 4;
resultBaseRef = 4;
for (int x = 0; x < scanline.Length; x++)
for (int x = 0; x < scanline.Length; x++)
{
if (x - bytesPerPixel < 0)
{
byte left = (x - bytesPerPixel < 0) ? (byte)0 : scan[x - bytesPerPixel];
byte above = prev[x];
byte upperLeft = (x - bytesPerPixel < 0) ? (byte)0 : prev[x - bytesPerPixel];
res[x + 1] = (byte)((scan[x] - PaethPredicator(left, above, upperLeft)) % 256);
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)((scan - PaethPredicator(0, above, 0)) % 256);
}
else
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
byte above = Unsafe.Add(ref prevBaseRef, x);
byte upperLeft = Unsafe.Add(ref prevBaseRef, x - bytesPerPixel);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)((scan - PaethPredicator(left, above, upperLeft)) % 256);
}
}
}
@ -100,4 +122,4 @@ namespace ImageSharp.Formats
return upperLeft;
}
}
}
}

49
src/ImageSharp/Formats/Png/Filters/SubFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -18,18 +19,25 @@ namespace ImageSharp.Formats
/// Decodes the scanline
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, int bytesPerScanline, int bytesPerPixel)
public static void Decode(Span<byte> scanline, int bytesPerPixel)
{
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
// Sub(x) + Raw(x-bpp)
fixed (byte* scan = scanline)
for (int x = 1; x < scanline.Length; x++)
{
for (int x = 1; x < bytesPerScanline; x++)
if (x - bytesPerPixel < 1)
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
scan = (byte)(scan % 256);
}
else
{
byte priorRawByte = (x - bytesPerPixel < 1) ? (byte)0 : scan[x - bytesPerPixel];
scan[x] = (byte)((scan[x] + priorRawByte) % 256);
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
scan = (byte)((scan + prev) % 256);
}
}
}
@ -41,19 +49,30 @@ namespace ImageSharp.Formats
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(byte[] scanline, byte[] result, int bytesPerPixel)
public static void Encode(Span<byte> scanline, Span<byte> result, int bytesPerPixel)
{
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte resultBaseRef = ref result.DangerousGetPinnableReference();
// Sub(x) = Raw(x) - Raw(x-bpp)
fixed (byte* scan = scanline)
fixed (byte* res = result)
{
res[0] = 1;
resultBaseRef = 1;
for (int x = 0; x < scanline.Length; x++)
for (int x = 0; x < scanline.Length; x++)
{
if (x - bytesPerPixel < 0)
{
byte priorRawByte = (x - bytesPerPixel < 0) ? (byte)0 : scan[x - bytesPerPixel];
res[x + 1] = (byte)((scan[x] - priorRawByte) % 256);
byte scan = Unsafe.Add(ref scanBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)(scan % 256);
}
else
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)((scan - prev) % 256);
}
}
}

48
src/ImageSharp/Formats/Png/Filters/UpFilter.cs

@ -5,6 +5,7 @@
namespace ImageSharp.Formats
{
using System;
using System.Runtime.CompilerServices;
/// <summary>
@ -19,20 +20,20 @@ namespace ImageSharp.Formats
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline)
public static void Decode(Span<byte> scanline, Span<byte> previousScanline)
{
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference();
// Up(x) + Prior(x)
fixed (byte* scan = scanline)
fixed (byte* prev = previousScanline)
for (int x = 1; x < scanline.Length; x++)
{
for (int x = 1; x < bytesPerScanline; x++)
{
byte above = prev[x];
scan[x] = (byte)((scan[x] + above) % 256);
}
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
scan = (byte)((scan + above) % 256);
}
}
@ -43,21 +44,24 @@ namespace ImageSharp.Formats
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="result">The filtered scanline result.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(byte[] scanline, byte[] previousScanline, byte[] result)
public static void Encode(Span<byte> scanline, Span<byte> previousScanline, Span<byte> result)
{
// Up(x) = Raw(x) - Prior(x)
fixed (byte* scan = scanline)
fixed (byte* prev = previousScanline)
fixed (byte* res = result)
{
res[0] = 2;
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference();
ref byte resultBaseRef = ref result.DangerousGetPinnableReference();
for (int x = 0; x < scanline.Length; x++)
{
byte above = prev[x];
// Up(x) = Raw(x) - Prior(x)
resultBaseRef = 2;
res[x + 1] = (byte)((scan[x] - above) % 256);
}
for (int x = 0; x < scanline.Length; x++)
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
ref byte res = ref Unsafe.Add(ref resultBaseRef, x + 1);
res = (byte)((scan - above) % 256);
}
}
}

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

@ -12,6 +12,7 @@ namespace ImageSharp.Formats
using System.Linq;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using static ComparableExtensions;
@ -131,12 +132,12 @@ namespace ImageSharp.Formats
/// <summary>
/// Previous scanline processed
/// </summary>
private byte[] previousScanline;
private Buffer<byte> previousScanline;
/// <summary>
/// The current scanline that is being processed
/// </summary>
private byte[] scanline;
private Buffer<byte> scanline;
/// <summary>
/// The index of the current scanline being processed
@ -184,14 +185,14 @@ namespace ImageSharp.Formats
public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : struct, IPixel<TPixel>
{
ImageMetaData metadata = new ImageMetaData();
var metadata = new ImageMetaData();
this.currentStream = stream;
this.currentStream.Skip(8);
Image<TPixel> image = null;
PixelAccessor<TPixel> pixels = null;
try
{
using (ZlibInflateStream deframeStream = new ZlibInflateStream(this.currentStream))
using (var deframeStream = new ZlibInflateStream(this.currentStream))
{
PngChunk currentChunk;
while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
@ -252,11 +253,8 @@ namespace ImageSharp.Formats
finally
{
pixels?.Dispose();
if (this.previousScanline != null)
{
ArrayPool<byte>.Shared.Return(this.previousScanline);
ArrayPool<byte>.Shared.Return(this.scanline);
}
this.scanline?.Dispose();
this.previousScanline?.Dispose();
}
}
@ -335,7 +333,7 @@ namespace ImageSharp.Formats
throw new ArgumentOutOfRangeException($"The input png '{this.header.Width}x{this.header.Height}' is bigger than the max allowed size '{Image<TPixel>.MaxWidth}x{Image<TPixel>.MaxHeight}'");
}
image = Image.Create<TPixel>(this.header.Width, this.header.Height, metadata, this.configuration);
image = new Image<TPixel>(this.configuration, this.header.Width, this.header.Height, metadata);
pixels = image.Lock();
this.bytesPerPixel = this.CalculateBytesPerPixel();
this.bytesPerScanline = this.CalculateScanlineLength(this.header.Width) + 1;
@ -345,12 +343,8 @@ namespace ImageSharp.Formats
this.bytesPerSample = this.header.BitDepth / 8;
}
this.previousScanline = ArrayPool<byte>.Shared.Rent(this.bytesPerScanline);
this.scanline = ArrayPool<byte>.Shared.Rent(this.bytesPerScanline);
// Zero out the scanlines, because the bytes that are rented from the arraypool may not be zero.
Array.Clear(this.scanline, 0, this.bytesPerScanline);
Array.Clear(this.previousScanline, 0, this.bytesPerScanline);
this.previousScanline = Buffer<byte>.CreateClean(this.bytesPerScanline);
this.scanline = Buffer<byte>.CreateClean(this.bytesPerScanline);
}
/// <summary>
@ -429,7 +423,7 @@ namespace ImageSharp.Formats
{
while (this.currentRow < this.header.Height)
{
int bytesRead = compressedStream.Read(this.scanline, this.currentRowBytesRead, this.bytesPerScanline - this.currentRowBytesRead);
int bytesRead = compressedStream.Read(this.scanline.Array, this.currentRowBytesRead, this.bytesPerScanline - this.currentRowBytesRead);
this.currentRowBytesRead += bytesRead;
if (this.currentRowBytesRead < this.bytesPerScanline)
{
@ -437,45 +431,38 @@ namespace ImageSharp.Formats
}
this.currentRowBytesRead = 0;
FilterType filterType = (FilterType)this.scanline[0];
var filterType = (FilterType)this.scanline[0];
switch (filterType)
{
case FilterType.None:
NoneFilter.Decode(this.scanline);
break;
case FilterType.Sub:
SubFilter.Decode(this.scanline, this.bytesPerScanline, this.bytesPerPixel);
SubFilter.Decode(this.scanline, this.bytesPerPixel);
break;
case FilterType.Up:
UpFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline);
UpFilter.Decode(this.scanline, this.previousScanline);
break;
case FilterType.Average:
AverageFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline, this.bytesPerPixel);
AverageFilter.Decode(this.scanline, this.previousScanline, this.bytesPerPixel);
break;
case FilterType.Paeth:
PaethFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline, this.bytesPerPixel);
PaethFilter.Decode(this.scanline, this.previousScanline, this.bytesPerPixel);
break;
default:
throw new ImageFormatException("Unknown filter type.");
}
this.ProcessDefilteredScanline(this.scanline, pixels);
this.ProcessDefilteredScanline(this.scanline.Array, pixels);
Swap(ref this.scanline, ref this.previousScanline);
this.currentRow++;
@ -508,7 +495,7 @@ namespace ImageSharp.Formats
while (this.currentRow < this.header.Height)
{
int bytesRead = compressedStream.Read(this.scanline, this.currentRowBytesRead, bytesPerInterlaceScanline - this.currentRowBytesRead);
int bytesRead = compressedStream.Read(this.scanline.Array, this.currentRowBytesRead, bytesPerInterlaceScanline - this.currentRowBytesRead);
this.currentRowBytesRead += bytesRead;
if (this.currentRowBytesRead < bytesPerInterlaceScanline)
{
@ -517,45 +504,40 @@ namespace ImageSharp.Formats
this.currentRowBytesRead = 0;
FilterType filterType = (FilterType)this.scanline[0];
Span<byte> scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline);
Span<byte> prevSpan = this.previousScanline.Span.Slice(0, bytesPerInterlaceScanline);
var filterType = (FilterType)scanSpan[0];
switch (filterType)
{
case FilterType.None:
NoneFilter.Decode(this.scanline);
break;
case FilterType.Sub:
SubFilter.Decode(this.scanline, bytesPerInterlaceScanline, this.bytesPerPixel);
SubFilter.Decode(scanSpan, this.bytesPerPixel);
break;
case FilterType.Up:
UpFilter.Decode(this.scanline, this.previousScanline, bytesPerInterlaceScanline);
UpFilter.Decode(scanSpan, prevSpan);
break;
case FilterType.Average:
AverageFilter.Decode(this.scanline, this.previousScanline, bytesPerInterlaceScanline, this.bytesPerPixel);
AverageFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel);
break;
case FilterType.Paeth:
PaethFilter.Decode(this.scanline, this.previousScanline, bytesPerInterlaceScanline, this.bytesPerPixel);
PaethFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel);
break;
default:
throw new ImageFormatException("Unknown filter type.");
}
this.ProcessInterlacedDefilteredScanline(this.scanline, this.currentRow, pixels, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
this.ProcessInterlacedDefilteredScanline(this.scanline.Array, this.currentRow, pixels, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]);
Swap(ref this.scanline, ref this.previousScanline);
@ -583,9 +565,10 @@ namespace ImageSharp.Formats
private void ProcessDefilteredScanline<TPixel>(byte[] defilteredScanline, PixelAccessor<TPixel> pixels)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default(TPixel);
BufferSpan<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow);
BufferSpan<byte> scanlineBuffer = new BufferSpan<byte>(defilteredScanline, 1);
var color = default(TPixel);
Span<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow);
var scanlineBuffer = new Span<byte>(defilteredScanline, 1);
switch (this.PngColorType)
{
case PngColorType.Grayscale:
@ -646,7 +629,7 @@ namespace ImageSharp.Formats
{
byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
byte[] palette = this.palette;
TPixel color = default(TPixel);
var color = default(TPixel);
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
{
@ -703,7 +686,7 @@ namespace ImageSharp.Formats
private void ProcessInterlacedDefilteredScanline<TPixel>(byte[] defilteredScanline, int row, PixelAccessor<TPixel> pixels, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default(TPixel);
var color = default(TPixel);
switch (this.PngColorType)
{
@ -901,7 +884,7 @@ namespace ImageSharp.Formats
/// </returns>
private PngChunk ReadChunk()
{
PngChunk chunk = new PngChunk();
var chunk = new PngChunk();
this.ReadChunkLength(chunk);
if (chunk.Length < 0)
{

6
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -33,8 +33,10 @@ namespace ImageSharp.Formats
public void Encode<TPixel>(Image<TPixel> image, Stream stream, IPngEncoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
PngEncoderCore encode = new PngEncoderCore(options);
encode.Encode(image, stream);
using (var encode = new PngEncoderCore(options))
{
encode.Encode(image, stream);
}
}
}
}

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

@ -9,7 +9,9 @@ namespace ImageSharp.Formats
using System.Buffers;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Quantizers;
@ -19,7 +21,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Performs the png encoding operation.
/// </summary>
internal sealed class PngEncoderCore
internal sealed class PngEncoderCore : IDisposable
{
/// <summary>
/// The maximum block size, defaults at 64k for uncompressed blocks.
@ -71,25 +73,45 @@ namespace ImageSharp.Formats
/// </summary>
private int bytesPerPixel;
/// <summary>
/// The number of bytes per scanline.
/// </summary>
private int bytesPerScanline;
/// <summary>
/// The previous scanline.
/// </summary>
private Buffer<byte> previousScanline;
/// <summary>
/// The raw scanline.
/// </summary>
private Buffer<byte> rawScanline;
/// <summary>
/// The filtered scanline result.
/// </summary>
private Buffer<byte> result;
/// <summary>
/// The buffer for the sub filter
/// </summary>
private byte[] sub;
private Buffer<byte> sub;
/// <summary>
/// The buffer for the up filter
/// </summary>
private byte[] up;
private Buffer<byte> up;
/// <summary>
/// The buffer for the average filter
/// </summary>
private byte[] average;
private Buffer<byte> average;
/// <summary>
/// The buffer for the paeth filter
/// </summary>
private byte[] paeth;
private Buffer<byte> paeth;
/// <summary>
/// The quality of output for images.
@ -177,7 +199,7 @@ namespace ImageSharp.Formats
this.bytesPerPixel = this.CalculateBytesPerPixel();
PngHeader header = new PngHeader
var header = new PngHeader
{
Width = image.Width,
Height = image.Height,
@ -207,6 +229,20 @@ namespace ImageSharp.Formats
stream.Flush();
}
/// <summary>
/// Disposes PngEncoderCore instance, disposing it's internal buffers.
/// </summary>
public void Dispose()
{
this.previousScanline?.Dispose();
this.rawScanline?.Dispose();
this.result?.Dispose();
this.sub?.Dispose();
this.up?.Dispose();
this.average?.Dispose();
this.paeth?.Dispose();
}
/// <summary>
/// Writes an integer to the byte array.
/// </summary>
@ -268,10 +304,11 @@ namespace ImageSharp.Formats
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The image pixels accessor.</param>
/// <param name="row">The row index.</param>
/// <param name="rawScanline">The raw scanline.</param>
private void CollectGrayscaleBytes<TPixel>(PixelAccessor<TPixel> pixels, int row, byte[] rawScanline)
private void CollectGrayscaleBytes<TPixel>(PixelAccessor<TPixel> pixels, int row)
where TPixel : struct, IPixel<TPixel>
{
byte[] rawScanlineArray = this.rawScanline.Array;
// Copy the pixels across from the image.
// Reuse the chunk type buffer.
for (int x = 0; x < this.width; x++)
@ -286,11 +323,11 @@ namespace ImageSharp.Formats
{
if (i == 0)
{
rawScanline[offset] = luminance;
rawScanlineArray[offset] = luminance;
}
else
{
rawScanline[offset + i] = this.chunkTypeBuffer[3];
rawScanlineArray[offset + i] = this.chunkTypeBuffer[3];
}
}
}
@ -302,14 +339,18 @@ namespace ImageSharp.Formats
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The image pixel accessor.</param>
/// <param name="row">The row index.</param>
/// <param name="rawScanline">The raw scanline.</param>
private void CollecTPixelBytes<TPixel>(PixelAccessor<TPixel> pixels, int row, byte[] rawScanline)
private void CollecTPixelBytes<TPixel>(PixelAccessor<TPixel> pixels, int row)
where TPixel : struct, IPixel<TPixel>
{
// We can use the optimized PixelAccessor here and copy the bytes in unmanaged memory.
using (PixelArea<TPixel> pixelRow = new PixelArea<TPixel>(this.width, rawScanline, this.bytesPerPixel == 4 ? ComponentOrder.Xyzw : ComponentOrder.Xyz))
Span<TPixel> rowSpan = pixels.GetRowSpan(row);
if (this.bytesPerPixel == 4)
{
PixelOperations<TPixel>.Instance.ToXyzwBytes(rowSpan, this.rawScanline, this.width);
}
else
{
pixels.CopyTo(pixelRow, row);
PixelOperations<TPixel>.Instance.ToXyzBytes(rowSpan, this.rawScanline, this.width);
}
}
@ -320,81 +361,79 @@ namespace ImageSharp.Formats
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="pixels">The image pixel accessor.</param>
/// <param name="row">The row.</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="rawScanline">The raw scanline.</param>
/// <param name="result">The filtered scanline result.</param>
/// <returns>The <see cref="T:byte[]"/></returns>
private byte[] EncodePixelRow<TPixel>(PixelAccessor<TPixel> pixels, int row, byte[] previousScanline, byte[] rawScanline, byte[] result)
private Buffer<byte> EncodePixelRow<TPixel>(PixelAccessor<TPixel> pixels, int row)
where TPixel : struct, IPixel<TPixel>
{
switch (this.pngColorType)
{
case PngColorType.Palette:
Buffer.BlockCopy(this.palettePixelData, row * rawScanline.Length, rawScanline, 0, rawScanline.Length);
Buffer.BlockCopy(this.palettePixelData, row * this.rawScanline.Length, this.rawScanline.Array, 0, this.rawScanline.Length);
break;
case PngColorType.Grayscale:
case PngColorType.GrayscaleWithAlpha:
this.CollectGrayscaleBytes(pixels, row, rawScanline);
this.CollectGrayscaleBytes(pixels, row);
break;
default:
this.CollecTPixelBytes(pixels, row, rawScanline);
this.CollecTPixelBytes(pixels, row);
break;
}
return this.GetOptimalFilteredScanline(rawScanline, previousScanline, result);
return this.GetOptimalFilteredScanline();
}
/// <summary>
/// Applies all PNG filters to the given scanline and returns the filtered scanline that is deemed
/// to be most compressible, using lowest total variation as proxy for compressibility.
/// </summary>
/// <param name="rawScanline">The raw scanline</param>
/// <param name="previousScanline">The previous scanline</param>
/// <param name="result">The filtered scanline result.</param>
/// <returns>The <see cref="T:byte[]"/></returns>
private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, byte[] result)
private Buffer<byte> GetOptimalFilteredScanline()
{
Span<byte> scanSpan = this.rawScanline.Span;
Span<byte> prevSpan = this.previousScanline.Span;
// Palette images don't compress well with adaptive filtering.
if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8)
{
NoneFilter.Encode(rawScanline, result);
return result;
NoneFilter.Encode(this.rawScanline, this.result);
return this.result;
}
// This order, while different to the enumerated order is more likely to produce a smaller sum
// early on which shaves a couple of milliseconds off the processing time.
UpFilter.Encode(rawScanline, previousScanline, this.up);
UpFilter.Encode(scanSpan, prevSpan, this.up);
int currentSum = this.CalculateTotalVariation(this.up, int.MaxValue);
int lowestSum = currentSum;
result = this.up;
Buffer<byte> actualResult = this.up;
PaethFilter.Encode(rawScanline, previousScanline, this.paeth, this.bytesPerPixel);
PaethFilter.Encode(scanSpan, prevSpan, this.paeth, this.bytesPerPixel);
currentSum = this.CalculateTotalVariation(this.paeth, currentSum);
if (currentSum < lowestSum)
{
lowestSum = currentSum;
result = this.paeth;
actualResult = this.paeth;
}
SubFilter.Encode(rawScanline, this.sub, this.bytesPerPixel);
SubFilter.Encode(scanSpan, this.sub, this.bytesPerPixel);
currentSum = this.CalculateTotalVariation(this.sub, int.MaxValue);
if (currentSum < lowestSum)
{
lowestSum = currentSum;
result = this.sub;
actualResult = this.sub;
}
AverageFilter.Encode(rawScanline, previousScanline, this.average, this.bytesPerPixel);
AverageFilter.Encode(scanSpan, prevSpan, this.average, this.bytesPerPixel);
currentSum = this.CalculateTotalVariation(this.average, currentSum);
if (currentSum < lowestSum)
{
result = this.average;
actualResult = this.average;
}
return result;
return actualResult;
}
/// <summary>
@ -404,17 +443,19 @@ namespace ImageSharp.Formats
/// <param name="scanline">The scanline bytes</param>
/// <param name="lastSum">The last variation sum</param>
/// <returns>The <see cref="int"/></returns>
private int CalculateTotalVariation(byte[] scanline, int lastSum)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int CalculateTotalVariation(Span<byte> scanline, int lastSum)
{
ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference();
int sum = 0;
for (int i = 1; i < scanline.Length; i++)
for (int i = 1; i < this.bytesPerScanline; i++)
{
byte v = scanline[i];
byte v = Unsafe.Add(ref scanBaseRef, i);
sum += v < 128 ? v : 256 - v;
// No point continuing if we are larger.
if (sum > lastSum)
if (sum >= lastSum)
{
break;
}
@ -601,18 +642,19 @@ namespace ImageSharp.Formats
private void WriteDataChunks<TPixel>(PixelAccessor<TPixel> pixels, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
int bytesPerScanline = this.width * this.bytesPerPixel;
byte[] previousScanline = new byte[bytesPerScanline];
byte[] rawScanline = new byte[bytesPerScanline];
int resultLength = bytesPerScanline + 1;
byte[] result = new byte[resultLength];
this.bytesPerScanline = this.width * this.bytesPerPixel;
int resultLength = this.bytesPerScanline + 1;
this.previousScanline = new Buffer<byte>(this.bytesPerScanline);
this.rawScanline = new Buffer<byte>(this.bytesPerScanline);
this.result = new Buffer<byte>(resultLength);
if (this.pngColorType != PngColorType.Palette)
{
this.sub = new byte[resultLength];
this.up = new byte[resultLength];
this.average = new byte[resultLength];
this.paeth = new byte[resultLength];
this.sub = Buffer<byte>.CreateClean(resultLength);
this.up = Buffer<byte>.CreateClean(resultLength);
this.average = Buffer<byte>.CreateClean(resultLength);
this.paeth = Buffer<byte>.CreateClean(resultLength);
}
byte[] buffer;
@ -621,13 +663,14 @@ namespace ImageSharp.Formats
try
{
memoryStream = new MemoryStream();
using (ZlibDeflateStream deflateStream = new ZlibDeflateStream(memoryStream, this.options.CompressionLevel))
using (var deflateStream = new ZlibDeflateStream(memoryStream, this.options.CompressionLevel))
{
for (int y = 0; y < this.height; y++)
{
deflateStream.Write(this.EncodePixelRow(pixels, y, previousScanline, rawScanline, result), 0, resultLength);
Buffer<byte> r = this.EncodePixelRow(pixels, y);
deflateStream.Write(r.Array, 0, resultLength);
Swap(ref rawScanline, ref previousScanline);
Swap(ref this.rawScanline, ref this.previousScanline);
}
}

62
src/ImageSharp/Image.Create.cs

@ -1,62 +0,0 @@
// <copyright file="Image.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
{
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images matadata to preload.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <returns>
/// A new <see cref="Image{TPixel}"/> unless <typeparamref name="TPixel"/> is <see cref="Rgba32"/> in which case it returns <see cref="Image" />
/// </returns>
internal static Image<TPixel> Create<TPixel>(int width, int height, ImageMetaData metadata, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
if (typeof(TPixel) == typeof(Rgba32))
{
return new Image(width, height, metadata, configuration) as Image<TPixel>;
}
else
{
return new Image<TPixel>(width, height, metadata, configuration);
}
}
/// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <returns>
/// A new <see cref="Image{TPixel}"/> unless <typeparamref name="TPixel"/> is <see cref="Rgba32"/> in which case it returns <see cref="Image" />
/// </returns>
internal static Image<TPixel> Create<TPixel>(int width, int height, Configuration configuration)
where TPixel : struct, IPixel<TPixel>
{
return Image.Create<TPixel>(width, height, null, configuration);
}
}
}

69
src/ImageSharp/Image.cs

@ -1,69 +0,0 @@
// <copyright file="Image.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.Diagnostics;
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
[DebuggerDisplay("Image: {Width}x{Height}")]
public sealed partial class Image : Image<Rgba32>
{
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
public Image(int width, int height, Configuration configuration)
: base(width, height, configuration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public Image(int width, int height)
: this(width, height, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
/// by making a copy from another image.
/// </summary>
/// <param name="other">The other image, where the clone should be made from.</param>
/// <exception cref="System.ArgumentNullException"><paramref name="other"/> is null.</exception>
public Image(Image<Rgba32> other)
: base(other)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The metadata.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
internal Image(int width, int height, ImageMetaData metadata, Configuration configuration)
: base(width, height, metadata, configuration)
{
}
}
}

17
src/ImageSharp/Image.Decode.cs → src/ImageSharp/Image/Image.Decode.cs

@ -12,11 +12,10 @@ namespace ImageSharp
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
/// <content>
/// Adds static methods allowing the decoding of new images.
/// </content>
public static partial class Image
{
/// <summary>
/// By reading the header on the provided stream this calculates the images format.
@ -53,15 +52,15 @@ namespace ImageSharp
/// <summary>
/// Decodes the image stream to the current image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream.</param>
/// <param name="options">The options for the decoder.</param>
/// <param name="config">the configuration.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>
/// The decoded image
/// A new <see cref="Image{TPixel}"/>.
/// </returns>
private static Image<TPixel> Decode<TPixel>(Stream stream, IDecoderOptions options, Configuration config)
where TPixel : struct, IPixel<TPixel>
where TPixel : struct, IPixel<TPixel>
{
IImageFormat format = DiscoverFormat(stream, config);
if (format == null)
@ -74,4 +73,4 @@ namespace ImageSharp
return img;
}
}
}
}

146
src/ImageSharp/Image.FromBytes.cs → src/ImageSharp/Image/Image.FromBytes.cs

@ -1,122 +1,75 @@
// <copyright file="Image.FromStream.cs" company="James Jackson-South">
// <copyright file="Image.FromBytes.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.IO;
using Formats;
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
/// <content>
/// Adds static methods allowing the creation of new image from a byte array.
/// </content>
public static partial class Image
{
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] data)
{
return Load(null, data, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data) => Load<Rgba32>(null, data, null);
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] data, IDecoderOptions options)
{
return Load(null, data, options);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, IDecoderOptions options) => Load<Rgba32>(null, data, options);
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Configuration config, byte[] data)
{
return Load(config, data, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data) => Load<Rgba32>(config, data, null);
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] data, IImageDecoder decoder)
{
return Load(data, decoder, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, IImageDecoder decoder) => Load<Rgba32>(data, decoder, null);
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Configuration config, byte[] data, IDecoderOptions options)
{
using (MemoryStream ms = new MemoryStream(data))
{
return Load(config, ms, options);
}
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, byte[] data, IDecoderOptions options) => Load<Rgba32>(config, data, options);
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(byte[] data, IImageDecoder decoder, IDecoderOptions options)
{
using (MemoryStream ms = new MemoryStream(data))
{
return Load(ms, decoder, options);
}
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(byte[] data, IImageDecoder decoder, IDecoderOptions options) => Load<Rgba32>(data, decoder, options);
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="data">The byte array containing image data.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data)
where TPixel : struct, IPixel<TPixel>
{
@ -124,15 +77,12 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="data">The byte array containing image data.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -140,15 +90,12 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data)
where TPixel : struct, IPixel<TPixel>
{
@ -156,15 +103,12 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data, IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
{
@ -172,16 +116,13 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -192,16 +133,13 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given byte array.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given byte array.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(byte[] data, IImageDecoder decoder, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -211,4 +149,4 @@ namespace ImageSharp
}
}
}
}
}

109
src/ImageSharp/Image.FromFile.cs → src/ImageSharp/Image/Image.FromFile.cs

@ -11,110 +11,87 @@ namespace ImageSharp
using Formats;
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
/// <content>
/// Adds static methods allowing the creation of new image from a given file.
/// </content>
public static partial class Image
{
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string path)
{
return Load(null, path, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path) => Load<Rgba32>(path);
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string path, IDecoderOptions options)
{
return Load(null, path, options);
}
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<Rgba32> Load(string path, IDecoderOptions options) => Load<Rgba32>(path, options);
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Configuration config, string path)
{
return Load(config, path, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path) => Load<Rgba32>(config, path);
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string path, IImageDecoder decoder)
{
return Load(path, decoder, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, IImageDecoder decoder) => Load<Rgba32>(path, decoder);
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(string path, IImageDecoder decoder, IDecoderOptions options)
{
return new Image(Load<Rgba32>(path, decoder, options));
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(Configuration config, string path, IDecoderOptions options) => Load<Rgba32>(config, path, options);
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Configuration config, string path, IDecoderOptions options)
{
config = config ?? Configuration.Default;
using (Stream s = config.FileSystem.OpenRead(path))
{
return Load(config, s, options);
}
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
public static Image<Rgba32> Load(string path, IImageDecoder decoder, IDecoderOptions options) => Load<Rgba32>(path, decoder, options);
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path)
where TPixel : struct, IPixel<TPixel>
{
@ -122,15 +99,15 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -138,15 +115,15 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="config">The config for the decoder.</param>
/// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, string path)
where TPixel : struct, IPixel<TPixel>
{
@ -154,15 +131,15 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
{
@ -170,16 +147,16 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="config">The configuration options.</param>
/// <param name="path">The file path to the image.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, string path, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -191,16 +168,16 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given file.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(string path, IImageDecoder decoder, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -212,4 +189,4 @@ namespace ImageSharp
}
}
#endif
}
}

131
src/ImageSharp/Image.FromStream.cs → src/ImageSharp/Image/Image.FromStream.cs

@ -7,92 +7,61 @@ namespace ImageSharp
{
using System;
using System.IO;
using System.Numerics;
using System.Text;
using Formats;
using ImageSharp.PixelFormats;
/// <summary>
/// Represents an image. Each pixel is a made up four 8-bit components red, green, blue, and alpha
/// packed into a single unsigned integer value.
/// </summary>
public sealed partial class Image
/// <content>
/// Adds static methods allowing the creation of new image from a given stream.
/// </content>
public static partial class Image
{
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream)
{
return Load(null, stream, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream) => Load<Rgba32>(stream);
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IDecoderOptions options)
{
return Load(null, stream, options);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Configuration config, Stream stream)
{
return Load(config, stream, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, IDecoderOptions options) => Load<Rgba32>(stream, options);
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IImageDecoder decoder)
{
return Load(stream, decoder, null);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, IImageDecoder decoder) => Load<Rgba32>(stream, decoder);
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Configuration config, Stream stream, IDecoderOptions options)
{
Image<Rgba32> image = Load<Rgba32>(config, stream, options);
return image as Image ?? new Image(image);
}
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>>
public static Image<Rgba32> Load(Configuration config, Stream stream) => Load<Rgba32>(config, stream);
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given stream.
/// </summary>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
@ -100,23 +69,18 @@ namespace ImageSharp
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
public static Image Load(Stream stream, IImageDecoder decoder, IDecoderOptions options)
{
Image<Rgba32> image = new Image(Load<Rgba32>(stream, decoder, options));
return image as Image ?? new Image(image);
}
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<Rgba32> Load(Stream stream, IImageDecoder decoder, IDecoderOptions options) => Load<Rgba32>(stream, decoder, options);
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream)
where TPixel : struct, IPixel<TPixel>
{
@ -124,15 +88,15 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -140,15 +104,15 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="config">The config for the decoder.</param>
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
@ -156,15 +120,15 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream, IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
{
@ -172,16 +136,16 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream, IImageDecoder decoder, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
@ -189,21 +153,20 @@ namespace ImageSharp
}
/// <summary>
/// Loads the image from the given stream.
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="config">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param>
/// <param name="options">The options for the decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>The image</returns>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream, IDecoderOptions options)
where TPixel : struct, IPixel<TPixel>
{
config = config ?? Configuration.Default;
Image<TPixel> img = WithSeekableStream(stream, s => Decode<TPixel>(s, options, config));
if (img != null)
@ -233,17 +196,15 @@ namespace ImageSharp
{
return action(stream);
}
else
// We want to be able to load images from things like HttpContext.Request.Body
using (MemoryStream ms = new MemoryStream())
{
// We want to be able to load images from things like HttpContext.Request.Body
using (MemoryStream ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0;
return action(ms);
}
stream.CopyTo(ms);
ms.Position = 0;
return action(ms);
}
}
}
}
}

8
src/ImageSharp/Image/ImageBase{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp
{
using System;
using System.Diagnostics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
using Processing;
@ -59,15 +61,15 @@ namespace ImageSharp
/// <summary>
/// Initializes a new instance of the <see cref="ImageBase{TPixel}"/> class.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if either <paramref name="width"/> or <paramref name="height"/> are less than or equal to 0.
/// </exception>
protected ImageBase(int width, int height, Configuration configuration)
protected ImageBase(Configuration configuration, int width, int height)
: this(configuration)
{
Guard.MustBeGreaterThan(width, 0, nameof(width));

2
src/ImageSharp/Image/ImageFrame{TPixel}.cs

@ -26,7 +26,7 @@ namespace ImageSharp
/// The configuration providing initialization code which allows extending the library.
/// </param>
public ImageFrame(int width, int height, Configuration configuration = null)
: base(width, height, configuration)
: base(configuration, width, height)
{
}

22
src/ImageSharp/Image/Image{TPixel}.cs

@ -29,13 +29,13 @@ namespace ImageSharp
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
public Image(int width, int height, Configuration configuration)
: this(width, height, new ImageMetaData(), configuration)
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public Image(Configuration configuration, int width, int height)
: this(configuration, width, height, new ImageMetaData())
{
}
@ -46,7 +46,7 @@ namespace ImageSharp
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
public Image(int width, int height)
: this(width, height, null)
: this(null, width, height)
{
}
@ -85,14 +85,14 @@ namespace ImageSharp
/// Initializes a new instance of the <see cref="Image{TPixel}"/> class
/// with the height and the width of the image.
/// </summary>
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
/// <param name="configuration">
/// The configuration providing initialization code which allows extending the library.
/// </param>
internal Image(int width, int height, ImageMetaData metadata, Configuration configuration)
: base(width, height, configuration)
/// <param name="width">The width of the image in pixels.</param>
/// <param name="height">The height of the image in pixels.</param>
/// <param name="metadata">The images metadata.</param>
internal Image(Configuration configuration, int width, int height, ImageMetaData metadata)
: base(configuration, width, height)
{
if (!this.Configuration.ImageFormats.Any())
{
@ -359,7 +359,7 @@ namespace ImageSharp
{
scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TPixel, TPixel2>(scaleFunc);
Image<TPixel2> target = new Image<TPixel2>(this.Width, this.Height, this.Configuration);
Image<TPixel2> target = new Image<TPixel2>(this.Configuration, this.Width, this.Height);
target.CopyProperties(this);
using (PixelAccessor<TPixel> pixels = this.Lock())

38
src/ImageSharp/Image/PixelAccessor{TPixel}.cs

@ -9,6 +9,8 @@ namespace ImageSharp
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -114,7 +116,7 @@ namespace ImageSharp
public ParallelOptions ParallelOptions { get; }
/// <inheritdoc />
BufferSpan<TPixel> IBuffer2D<TPixel>.Span => this.pixelBuffer;
Span<TPixel> IBuffer2D<TPixel>.Span => this.pixelBuffer;
private static PixelOperations<TPixel> Operations => PixelOperations<TPixel>.Instance;
@ -250,7 +252,7 @@ namespace ImageSharp
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TPixel> target)
{
BufferSpan.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span);
SpanHelper.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span);
}
/// <summary>
@ -266,8 +268,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromZyxBytes(source, destination, width);
}
@ -286,8 +288,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromZyxwBytes(source, destination, width);
}
@ -306,8 +308,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromXyzBytes(source, destination, width);
}
@ -326,8 +328,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<byte> source = area.GetRowSpan(y);
BufferSpan<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Span<byte> source = area.GetRowSpan(y);
Span<TPixel> destination = this.GetRowSpan(targetX, targetY + y);
Operations.PackFromXyzwBytes(source, destination, width);
}
}
@ -345,8 +347,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
Span<byte> destination = area.GetRowSpan(y);
Operations.ToZyxBytes(source, destination, width);
}
}
@ -364,8 +366,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
Span<byte> destination = area.GetRowSpan(y);
Operations.ToZyxwBytes(source, destination, width);
}
}
@ -383,8 +385,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
Span<byte> destination = area.GetRowSpan(y);
Operations.ToXyzBytes(source, destination, width);
}
}
@ -402,8 +404,8 @@ namespace ImageSharp
{
for (int y = 0; y < height; y++)
{
BufferSpan<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
BufferSpan<byte> destination = area.GetRowSpan(y);
Span<TPixel> source = this.GetRowSpan(sourceX, sourceY + y);
Span<byte> destination = area.GetRowSpan(y);
Operations.ToXyzwBytes(source, destination, width);
}
}

8
src/ImageSharp/Image/PixelArea{TPixel}.cs

@ -8,6 +8,8 @@ namespace ImageSharp
using System;
using System.Diagnostics;
using System.IO;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -191,11 +193,11 @@ namespace ImageSharp
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row y.
/// Gets a <see cref="Span{T}"/> to the row y.
/// </summary>
/// <param name="y">The y coordinate</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
internal BufferSpan<byte> GetRowSpan(int y)
/// <returns>The <see cref="Span{T}"/></returns>
internal Span<byte> GetRowSpan(int y)
{
return this.byteBuffer.Slice(y * this.RowStride);
}

5
src/ImageSharp/ImageSharp.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>A cross-platform library for the processing of image files; written in C#</Description>
<AssemblyTitle>ImageSharp</AssemblyTitle>
<VersionPrefix>1.0.0-alpha8</VersionPrefix>
<VersionPrefix>1.0.0-alpha9</VersionPrefix>
<Authors>James Jackson-South and contributors</Authors>
<TargetFrameworks>netstandard1.3;netstandard1.1</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -38,8 +38,9 @@
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.3.0" />
<PackageReference Include="System.Memory" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0-preview1-25305-02" />
<PackageReference Include="System.Numerics.Vectors" Version="4.3.0" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
</ItemGroup>

31
src/ImageSharp/Common/Memory/Buffer.cs → src/ImageSharp/Memory/Buffer.cs

@ -3,10 +3,9 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -97,9 +96,9 @@ namespace ImageSharp
public T[] Array { get; private set; }
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
/// Gets a <see cref="Span{T}"/> to the backing buffer.
/// </summary>
public BufferSpan<T> Span => this;
public Span<T> Span => this;
/// <summary>
/// Returns a reference to specified element of the buffer.
@ -117,13 +116,13 @@ namespace ImageSharp
}
/// <summary>
/// Converts <see cref="Buffer{T}"/> to an <see cref="BufferSpan{T}"/>.
/// Converts <see cref="Buffer{T}"/> to an <see cref="Span{T}"/>.
/// </summary>
/// <param name="buffer">The <see cref="Buffer{T}"/> to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator BufferSpan<T>(Buffer<T> buffer)
public static implicit operator Span<T>(Buffer<T> buffer)
{
return new BufferSpan<T>(buffer.Array, 0, buffer.Length);
return new Span<T>(buffer.Array, 0, buffer.Length);
}
/// <summary>
@ -140,26 +139,26 @@ namespace ImageSharp
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to an offseted position inside the buffer.
/// Gets a <see cref="Span{T}"/> to an offseted position inside the buffer.
/// </summary>
/// <param name="start">The start</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start)
public Span<T> Slice(int start)
{
return new BufferSpan<T>(this.Array, start, this.Length - start);
return new Span<T>(this.Array, start, this.Length - start);
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to an offseted position inside the buffer.
/// Gets a <see cref="Span{T}"/> to an offsetted position inside the buffer.
/// </summary>
/// <param name="start">The start</param>
/// <param name="length">The length of the slice</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan<T> Slice(int start, int length)
public Span<T> Slice(int start, int length)
{
return new BufferSpan<T>(this.Array, start, length);
return new Span<T>(this.Array, start, length);
}
/// <summary>
@ -210,7 +209,7 @@ namespace ImageSharp
}
/// <summary>
/// Clears the buffer, filling elements between 0 and <see cref="Length"/>-1 with default(T)
/// Clears the contents of this buffer.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()

3
src/ImageSharp/Common/Memory/Buffer2D.cs → src/ImageSharp/Memory/Buffer2D.cs

@ -3,9 +3,8 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Runtime.CompilerServices;
/// <summary>

14
src/ImageSharp/Common/Memory/Buffer2DExtensions.cs → src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Runtime.CompilerServices;
@ -14,29 +14,29 @@ namespace ImageSharp
internal static class Buffer2DExtensions
{
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="x">The x coordinate (position in the row)</param>
/// <param name="y">The y (row) coordinate</param>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BufferSpan<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int x, int y)
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int x, int y)
where T : struct
{
return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x);
}
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// Gets a <see cref="Span{T}"/> to the row 'y' beginning from the pixel at 'x'.
/// </summary>
/// <param name="buffer">The buffer</param>
/// <param name="y">The y (row) coordinate</param>
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BufferSpan<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y)
public static Span<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y)
where T : struct
{
return buffer.Span.Slice(y * buffer.Width, buffer.Width);

6
src/ImageSharp/Common/Memory/Fast2DArray{T}.cs → src/ImageSharp/Memory/Fast2DArray{T}.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Diagnostics;
@ -94,11 +94,11 @@ namespace ImageSharp
}
/// <summary>
/// Performs an implicit conversion from a 2D array to a <see cref="ImageSharp.Fast2DArray{T}" />.
/// Performs an implicit conversion from a 2D array to a <see cref="Fast2DArray{T}" />.
/// </summary>
/// <param name="data">The source array.</param>
/// <returns>
/// The <see cref="ImageSharp.Fast2DArray{T}"/> represenation on the source data.
/// The <see cref="Fast2DArray{T}"/> represenation on the source data.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Fast2DArray<T>(T[,] data)

8
src/ImageSharp/Common/Memory/IBuffer2D.cs → src/ImageSharp/Memory/IBuffer2D.cs

@ -3,8 +3,10 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
/// <summary>
/// An interface that represents a pinned buffer of value type objects
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
@ -24,8 +26,8 @@ namespace ImageSharp
int Height { get; }
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
/// Gets a <see cref="Span{T}"/> to the backing buffer.
/// </summary>
BufferSpan<T> Span { get; }
Span<T> Span { get; }
}
}

3
src/ImageSharp/Common/Memory/PixelDataPool{T}.cs → src/ImageSharp/Memory/PixelDataPool{T}.cs

@ -3,9 +3,8 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Buffers;
using ImageSharp.PixelFormats;

36
src/ImageSharp/Common/Memory/BufferSpan.cs → src/ImageSharp/Memory/SpanHelper.cs

@ -1,28 +1,41 @@
// <copyright file="BufferSpan.cs" company="James Jackson-South">
// <copyright file="SpanHelper.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
namespace ImageSharp.Memory
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Utility methods for <see cref="BufferSpan{T}"/>
/// Utility methods for <see cref="Span{T}"/>
/// </summary>
internal static class BufferSpan
internal static class SpanHelper
{
/// <summary>
/// Fetches a <see cref="Vector{T}"/> from the beginning of the span.
/// </summary>
/// <typeparam name="T">The value type</typeparam>
/// <param name="span">The span to fetch the vector from</param>
/// <returns>A <see cref="Vector{T}"/> reference to the beginning of the span</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref Vector<T> FetchVector<T>(this Span<T> span)
where T : struct
{
return ref Unsafe.As<T, Vector<T>>(ref span.DangerousGetPinnableReference());
}
/// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="source">The <see cref="Span{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="Span{T}"/>.</param>
/// <param name="count">The number of elements to copy</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination, int count)
public static unsafe void Copy<T>(Span<T> source, Span<T> destination, int count)
where T : struct
{
DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count));
@ -34,6 +47,7 @@ namespace ImageSharp
int byteCount = Unsafe.SizeOf<T>() * count;
// TODO: Use unfixed Unsafe.CopyBlock(ref T, ref T, int) for small blocks, when it gets available!
// This is now available. Check with Anton re intent. Do we replace both ifdefs?
fixed (byte* pSrc = &srcRef)
fixed (byte* pDest = &destRef)
{
@ -50,10 +64,10 @@ namespace ImageSharp
/// Copy all elements of 'source' into 'destination'.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="source">The <see cref="Span{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="Span{T}"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination)
public static void Copy<T>(Span<T> source, Span<T> destination)
where T : struct
{
Copy(source, destination, source.Length);

22
src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs

@ -5,7 +5,6 @@
namespace ImageSharp
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
@ -137,7 +136,7 @@ namespace ImageSharp
return null;
}
using (MemoryStream memStream = new MemoryStream(this.data, this.thumbnailOffset, this.thumbnailLength))
using (var memStream = new MemoryStream(this.data, this.thumbnailOffset, this.thumbnailLength))
{
return Image.Load<TPixel>(memStream);
}
@ -202,7 +201,7 @@ namespace ImageSharp
}
}
ExifValue newExifValue = ExifValue.Create(tag, value);
var newExifValue = ExifValue.Create(tag, value);
this.values.Add(newExifValue);
}
@ -222,7 +221,7 @@ namespace ImageSharp
return null;
}
ExifWriter writer = new ExifWriter(this.values, this.Parts);
var writer = new ExifWriter(this.values, this.Parts);
return writer.GetData();
}
@ -239,11 +238,18 @@ namespace ImageSharp
private void SyncResolution(ExifTag tag, double resolution)
{
ExifValue value = this.GetValue(tag);
if (value != null)
if (value == null)
{
Rational newResolution = new Rational(resolution, false);
this.SetValue(tag, newResolution);
return;
}
if (value.IsArray || value.DataType != ExifDataType.Rational)
{
this.RemoveValue(value.Tag);
}
var newResolution = new Rational(resolution, false);
this.SetValue(tag, newResolution);
}
private void InitializeValues()
@ -259,7 +265,7 @@ namespace ImageSharp
return;
}
ExifReader reader = new ExifReader();
var reader = new ExifReader();
this.values = reader.Read(this.data);
this.invalidTags = new List<ExifTag>(reader.InvalidTags);
this.thumbnailOffset = (int)reader.ThumbnailOffset;

6
src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs

@ -75,7 +75,7 @@ namespace ImageSharp
{
DebugGuard.NotNull(data, nameof(data));
Collection<ExifValue> result = new Collection<ExifValue>();
var result = new Collection<ExifValue>();
this.exifData = data;
@ -357,7 +357,7 @@ namespace ImageSharp
private TEnum ToEnum<TEnum>(int value, TEnum defaultValue)
where TEnum : struct
{
TEnum enumValue = (TEnum)(object)value;
var enumValue = (TEnum)(object)value;
if (Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Any(v => v.Equals(enumValue)))
{
return enumValue;
@ -403,7 +403,7 @@ namespace ImageSharp
private void GetThumbnail(uint offset)
{
Collection<ExifValue> values = new Collection<ExifValue>();
var values = new Collection<ExifValue>();
this.AddValues(values, offset);
foreach (ExifValue value in values)

4
src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs

@ -39,7 +39,7 @@ namespace ImageSharp
}
else
{
Array array = (Array)other.exifValue;
var array = (Array)other.exifValue;
this.exifValue = array.Clone();
}
}
@ -264,7 +264,7 @@ namespace ImageSharp
return this.ToString(this.exifValue);
}
StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();
foreach (object value in (Array)this.exifValue)
{
sb.Append(this.ToString(value));

8
src/ImageSharp/PixelFormats/Alpha8.cs

@ -87,7 +87,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = 0;
bytes[startIndex + 1] = 0;
@ -96,7 +96,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = 0;
bytes[startIndex + 1] = 0;
@ -106,7 +106,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = 0;
bytes[startIndex + 1] = 0;
@ -115,7 +115,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = 0;
bytes[startIndex + 1] = 0;

9
src/ImageSharp/PixelFormats/Argb32.cs

@ -5,6 +5,7 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -241,7 +242,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = this.R;
bytes[startIndex + 1] = this.G;
@ -250,7 +251,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = this.R;
bytes[startIndex + 1] = this.G;
@ -260,7 +261,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = this.B;
bytes[startIndex + 1] = this.G;
@ -269,7 +270,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
bytes[startIndex] = this.B;
bytes[startIndex + 1] = this.G;

8
src/ImageSharp/PixelFormats/Bgr565.cs

@ -110,7 +110,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)MathF.Round(vector.X);
@ -120,7 +120,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)MathF.Round(vector.X);
@ -131,7 +131,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)MathF.Round(vector.Z);
@ -141,7 +141,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)MathF.Round(vector.Z);

8
src/ImageSharp/PixelFormats/Bgra4444.cs

@ -101,7 +101,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
@ -111,7 +111,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
@ -122,7 +122,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;
@ -132,7 +132,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;

8
src/ImageSharp/PixelFormats/Bgra5551.cs

@ -101,7 +101,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
@ -111,7 +111,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
@ -122,7 +122,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;
@ -132,7 +132,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;

8
src/ImageSharp/PixelFormats/Byte4.cs

@ -102,7 +102,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.X;
@ -112,7 +112,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.X;
@ -123,7 +123,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.Z;
@ -133,7 +133,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.Z;

9
src/ImageSharp/PixelFormats/HalfSingle.cs

@ -5,6 +5,7 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -110,7 +111,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -124,7 +125,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -139,7 +140,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -153,7 +154,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;

9
src/ImageSharp/PixelFormats/HalfVector2.cs

@ -5,6 +5,7 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -124,7 +125,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -138,7 +139,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -153,7 +154,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -167,7 +168,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;

9
src/ImageSharp/PixelFormats/HalfVector4.cs

@ -5,6 +5,7 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -117,7 +118,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -131,7 +132,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -146,7 +147,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
@ -160,7 +161,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;

8
src/ImageSharp/PixelFormats/IPixel.cs

@ -56,7 +56,7 @@ namespace ImageSharp.PixelFormats
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToXyzBytes(byte[] bytes, int startIndex);
void ToXyzBytes(Span<byte> bytes, int startIndex);
/// <summary>
/// Expands the packed representation into a given byte array.
@ -64,7 +64,7 @@ namespace ImageSharp.PixelFormats
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToXyzwBytes(byte[] bytes, int startIndex);
void ToXyzwBytes(Span<byte> bytes, int startIndex);
/// <summary>
/// Expands the packed representation into a given byte array.
@ -72,7 +72,7 @@ namespace ImageSharp.PixelFormats
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToZyxBytes(byte[] bytes, int startIndex);
void ToZyxBytes(Span<byte> bytes, int startIndex);
/// <summary>
/// Expands the packed representation into a given byte array.
@ -80,6 +80,6 @@ namespace ImageSharp.PixelFormats
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToZyxwBytes(byte[] bytes, int startIndex);
void ToZyxwBytes(Span<byte> bytes, int startIndex);
}
}

8
src/ImageSharp/PixelFormats/NormalizedByte2.cs

@ -134,7 +134,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -150,7 +150,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -167,7 +167,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -183,7 +183,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;

8
src/ImageSharp/PixelFormats/NormalizedByte4.cs

@ -127,7 +127,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -143,7 +143,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -160,7 +160,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -176,7 +176,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;

9
src/ImageSharp/PixelFormats/NormalizedShort2.cs

@ -5,6 +5,7 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -120,7 +121,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -136,7 +137,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -153,7 +154,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -169,7 +170,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;

9
src/ImageSharp/PixelFormats/NormalizedShort4.cs

@ -5,6 +5,7 @@
namespace ImageSharp.PixelFormats
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -128,7 +129,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
public void ToXyzBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -144,7 +145,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
public void ToXyzwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -161,7 +162,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
public void ToZyxBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
@ -177,7 +178,7 @@ namespace ImageSharp.PixelFormats
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
public void ToZyxwBytes(Span<byte> bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultAddPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultDarkenPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultHardLightPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultLightenPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

10
src/ImageSharp/PixelFormats/PixelBlenders/DefaultMultiplyPixelBlender{TPixel}.cs

@ -7,6 +7,8 @@ namespace ImageSharp.PixelFormats.PixelBlenders
{
using System;
using System.Numerics;
using ImageSharp.Memory;
using ImageSharp.PixelFormats;
/// <summary>
@ -28,7 +30,7 @@ namespace ImageSharp.PixelFormats.PixelBlenders
}
/// <inheritdoc />
public override void Blend(BufferSpan<TPixel> destination, BufferSpan<TPixel> background, BufferSpan<TPixel> source, BufferSpan<float> amount)
public override void Blend(Span<TPixel> destination, Span<TPixel> background, Span<TPixel> source, Span<float> amount)
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
@ -36,9 +38,9 @@ namespace ImageSharp.PixelFormats.PixelBlenders
using (Buffer<Vector4> buffer = new Buffer<Vector4>(destination.Length * 3))
{
BufferSpan<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
BufferSpan<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
BufferSpan<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan, destination.Length);

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

Loading…
Cancel
Save