Browse Source

Merge branch 'master' into master

pull/379/head
Dirk Lemstra 8 years ago
committed by GitHub
parent
commit
236bf3106f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .travis.yml
  2. 10
      appveyor.yml
  3. 24
      build.cmd
  4. 113
      build.ps1
  5. 31
      gitversion.yml
  6. 104
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  7. 15
      src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
  8. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs
  9. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs
  10. 3
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs
  11. 3
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs
  12. 3
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs
  13. 3
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs
  14. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs
  15. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs
  16. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs
  17. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs
  18. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs
  19. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs
  20. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs
  21. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec2020Companding.cs
  22. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec709Companding.cs
  23. 1
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/SRgbCompanding.cs
  24. 2
      src/ImageSharp/Common/Extensions/Vector4Extensions.cs
  25. 21
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  26. 291
      src/ImageSharp/Common/Helpers/MathF.cs
  27. 4
      src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
  28. 28
      src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs
  29. 46
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  30. 10
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  31. 2
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  32. 1
      src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs
  33. 3
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
  34. 2
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  35. 20
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  36. 45
      src/ImageSharp/Formats/Png/Zlib/Adler32.cs
  37. 35
      src/ImageSharp/Formats/Png/Zlib/Crc32.cs
  38. 65
      src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
  39. 6
      src/ImageSharp/Image/PixelAccessorExtensions.cs
  40. 1
      src/ImageSharp/Image/PixelAccessor{TPixel}.cs
  41. 4
      src/ImageSharp/Image/PixelArea{TPixel}.cs
  42. 234
      src/ImageSharp/ImageSharp.csproj
  43. 2
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  44. 1
      src/ImageSharp/Memory/SpanHelper.cs
  45. 8
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  46. 8
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  47. 1
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
  48. 79
      src/ImageSharp/PixelFormats/PixelConversionExtensions.cs
  49. 4
      src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
  50. 3
      src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs
  51. 6
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
  52. 4
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  53. 1
      src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs
  54. 2
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs
  55. 2
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs
  56. 2
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs
  57. 2
      src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs
  58. 2
      src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs
  59. 1
      src/ImageSharp/Processing/Transforms/Resize.cs
  60. 5
      src/ImageSharp/Quantizers/Box.cs
  61. 208
      src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
  62. 7
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  63. 8
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  64. 2
      tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs
  65. 20
      tests/ImageSharp.Benchmarks/Image/DecodePng.cs
  66. 6
      tests/ImageSharp.Benchmarks/Samplers/Glow.cs
  67. 6
      tests/ImageSharp.Tests/Common/SimdUtilsTests.cs
  68. 8
      tests/ImageSharp.Tests/Drawing/SolidPolygonTests.cs
  69. 43
      tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
  70. 2
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
  71. 6
      tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
  72. 3
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  73. 123
      tests/ImageSharp.Tests/Helpers/MathFTests.cs
  74. 58
      tests/ImageSharp.Tests/Issues/Issue412.cs
  75. 519
      tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs
  76. 26
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs
  77. 76
      tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs
  78. 10
      tests/ImageSharp.Tests/Processing/Processors/ColorMatrix/GrayscaleTest.cs
  79. 4
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
  80. 13
      tests/ImageSharp.Tests/TestImages.cs
  81. 1
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
  82. 16
      tests/ImageSharp.Tests/TestUtilities/TestUtils.cs
  83. 20
      tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
  84. 2
      tests/Images/External
  85. BIN
      tests/Images/Input/Gif/issues/issue403_baddescriptorwidth.gif
  86. BIN
      tests/Images/Input/Gif/issues/issue405_badappextlength252-2.gif
  87. BIN
      tests/Images/Input/Gif/issues/issue405_badappextlength252.gif
  88. BIN
      tests/Images/Input/Gif/kumin.gif
  89. BIN
      tests/Images/Input/Jpg/issues/Issue385-BadZigZag-Progressive.jpg
  90. BIN
      tests/Images/Input/Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg
  91. BIN
      tests/Images/Input/Png/icon.png

2
.travis.yml

@ -6,7 +6,7 @@ matrix:
- os: linux # Ubuntu 14.04
dist: trusty
sudo: required
dotnet: 1.0.1
dotnet: 1.0.4
mono: latest
# - os: osx # OSX 10.11
# osx_image: xcode7.3.1

10
appveyor.yml

@ -4,14 +4,10 @@ image: Visual Studio 2017
# prevent the double build when a branch has an active PR
skip_branch_with_pr: true
install:
- choco install gitversion.portable -pre -y
before_build:
- git submodule -q update --init
- cmd: dotnet --version
- ps: c:\ProgramData\chocolatey\lib\gitversion.portable\tools\gitversion.exe /l console /output buildserver
build_script:
- cmd: build.cmd
@ -19,8 +15,8 @@ test_script:
- tests\CodeCoverage\CodeCoverage.cmd
after_test:
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.%GitVersion_NuGetVersion%.nupkg"
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.Drawing.%GitVersion_NuGetVersion%.nupkg"
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.%APPVEYOR_BUILD_VERSION%.nupkg"
- cmd: appveyor PushArtifact "artifacts\SixLabors.ImageSharp.Drawing.%APPVEYOR_BUILD_VERSION%.nupkg"
deploy:
# MyGet Deployment for builds & releases

24
build.cmd

@ -1,29 +1,7 @@
@echo Off
SET versionCommand=
if not "%GitVersion_NuGetVersion%" == "" (
SET versionCommand=/p:packageversion=%GitVersion_NuGetVersion%
@echo building with version set to '%GitVersion_NuGetVersion%'
)
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '.\build.ps1'"
dotnet restore %versionCommand%
ECHO Building projects
dotnet build -c Release %versionCommand%
if not "%errorlevel%"=="0" goto failure
if not "%CI%" == "True" (
ECHO NOT on CI server running tests
dotnet test ./tests/ImageSharp.Tests/ImageSharp.Tests.csproj --no-build -c Release
)
if not "%errorlevel%"=="0" goto failure
ECHO Packaging projects
dotnet pack ./src/ImageSharp/ -c Release --output ../../artifacts --no-build %versionCommand%
if not "%errorlevel%"=="0" goto failure
dotnet pack ./src/ImageSharp.Drawing/ -c Release --output ../../artifacts --no-build %versionCommand%
if not "%errorlevel%"=="0" goto failure
:success

113
build.ps1

@ -0,0 +1,113 @@
# lets calulat the correct version here
$fallbackVersion = "1.0.0";
$version = ''
$tagRegex = '^v?(\d+\.\d+\.\d+)(-([a-zA-Z]+)\.?(\d*))?$'
# we are running on the build server
$isVersionTag = $env:APPVEYOR_REPO_TAG_NAME -match $tagRegex
if($isVersionTag){
Write-Debug "Building commit tagged with a compatable version number"
$version = $matches[1]
$postTag = $matches[3]
$count = $matches[4]
Write-Debug "version number: ${version} post tag: ${postTag} count: ${count}"
if("$postTag" -ne ""){
$version = "${version}-${postTag}"
}
if("$count" -ne ""){
# for consistancy with previous releases we pad the counter to only 4 places
$padded = $count.Trim().Trim('0').PadLeft(4,"0");
Write-Debug "count '$count', padded '${padded}'"
$version = "${version}${padded}"
}
}else {
Write-Debug "Untagged"
$lastTag = (git tag --list --sort=-taggerdate) | Out-String
$list = $lastTag.Split("`n")
foreach ($tag in $list) {
Write-Debug "testing ${tag}"
$tag = $tag.Trim();
if($tag -match $tagRegex){
Write-Debug "matched ${tag}"
$version = $matches[1];
break;
}
}
if("$version" -eq ""){
$version = $fallbackVersion
Write-Debug "Failed to discover base version Fallback to '${version}'"
}else{
Write-Debug "Discovered base version from tags '${version}'"
}
$buildNumber = $env:APPVEYOR_BUILD_NUMBER
# build number replacement is padded to 6 places
$buildNumber = "$buildNumber".Trim().Trim('0').PadLeft(6,"0");
if("$env:APPVEYOR_PULL_REQUEST_NUMBER" -ne ""){
Write-Debug "building a PR"
$prNumber = "$env:APPVEYOR_PULL_REQUEST_NUMBER".Trim().Trim('0').PadLeft(5,"0");
# this is a PR
$version = "${version}-PullRequest${prNumber}${buildNumber}";
}else{
Write-Debug "building a branch commit"
# this is a general branch commit
$branch = $env:APPVEYOR_REPO_BRANCH
if("$branch" -eq ""){
$branch = ((git rev-parse --abbrev-ref HEAD) | Out-String).Trim()
if("$branch" -eq ""){
$branch = "unknown"
}
}
$branch = $branch.Replace("/","-").ToLower()
if($branch.ToLower() -eq "master"){
$branch = "dev"
}
$version = "${version}-${branch}${buildNumber}";
}
}
if("$env:APPVEYOR_API_URL" -ne ""){
# update appveyor build number for this build
Invoke-RestMethod -Method "PUT" `
-Uri "${env:APPVEYOR_API_URL}api/build" `
-Body "{version:'${version}'}" `
-ContentType "application/json"
}
Write-Host "Building version '${version}'"
dotnet restore /p:packageversion=$version
Write-Host "Building projects"
dotnet build -c Release /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
if ( $env:CI -ne "True") {
dotnet test ./tests/ImageSharp.Tests/ImageSharp.Tests.csproj --no-build -c Release
}
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
Write-Host "Packaging projects"
dotnet pack ./src/ImageSharp/ -c Release --output ../../artifacts --no-build /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }
dotnet pack ./src/ImageSharp.Drawing/ -c Release --output ../../artifacts --no-build /p:packageversion=$version
if ($LASTEXITCODE ){ Exit $LASTEXITCODE }

31
gitversion.yml

@ -1,31 +0,0 @@
# to create a new package you create a new release/tag
# in github appveyor will build it without the -cixxx tag
# it will then be deployable cleanly to nuget.org
branches:
master:
tag: ci
mode: ContinuousDeployment
increment: Minor
prevent-increment-of-merged-branch-version: false
track-merge-target: true
pull-request:
regex: (pull|pull\-requests|pr)[/-]
mode: ContinuousDelivery
tag: PullRequest
increment: Inherit
prevent-increment-of-merged-branch-version: false
tag-number-pattern: '[/-](?<number>\d+)[-/]'
track-merge-target: false
tracks-release-branches: false
is-release-branch: false
otherbranches:
regex: '.*'
mode: ContinuousDeployment
tag: ci
increment: Patch
prevent-increment-of-merged-branch-version: false
track-merge-target: true
is-release-branch: false
ignore:
sha: []

104
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -1,54 +1,54 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<AssemblyTitle>SixLabors.ImageSharp.Drawing</AssemblyTitle>
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>Six Labor and contributors</Authors>
<TargetFramework>netstandard1.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
<PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<DebugType Condition="$(codecov) != ''">full</DebugType>
<DebugType Condition="$(codecov) == ''">portable</DebugType>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
<AdditionalFiles Include="..\..\stylecop.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0003" />
<PackageReference Include="SixLabors.Shapes.Text" Version="1.0.0-beta0002" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0002" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>
<RootNamespace>SixLabors.ImageSharp.Drawing</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<AssemblyTitle>SixLabors.ImageSharp.Drawing</AssemblyTitle>
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>SixLabors and contributors</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>
<PackageId>SixLabors.ImageSharp.Drawing</PackageId>
<PackageTags>Image Draw Shape Path Font</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<DebugType Condition="$(codecov) != ''">full</DebugType>
<DebugType Condition="$(codecov) == ''">portable</DebugType>
<DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImageSharp\ImageSharp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0004" />
<PackageReference Include="SixLabors.Shapes.Text" Version="1.0.0-beta0003" />
<PackageReference Include="SixLabors.Shapes" Version="1.0.0-beta0003" />
<AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>
<RootNamespace>SixLabors.ImageSharp.Drawing</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
</Project>

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

@ -82,8 +82,15 @@ namespace SixLabors.ImageSharp.Drawing.Processors
int maxIntersections = region.MaxIntersections;
float subpixelCount = 4;
// we need to offset the pixel grid to account for when we outline a path.
// basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
// and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
// region to alline with the pixel grid.
float offset = 0.5f;
if (this.Options.Antialias)
{
offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
subpixelCount = this.Options.AntialiasSubpixelDepth;
if (subpixelCount < 4)
{
@ -117,7 +124,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
{
int pointsFound = region.Scan(subPixel, buffer, 0);
int pointsFound = region.Scan(subPixel + offset, buffer, 0);
if (pointsFound == 0)
{
// nothing on this line skip
@ -131,8 +138,8 @@ namespace SixLabors.ImageSharp.Drawing.Processors
// points will be paired up
float scanStart = buffer[point] - minX;
float scanEnd = buffer[point + 1] - minX;
int startX = (int)MathF.Floor(scanStart);
int endX = (int)MathF.Floor(scanEnd);
int startX = (int)MathF.Floor(scanStart + offset);
int endX = (int)MathF.Floor(scanEnd + offset);
if (startX >= 0 && startX < scanline.Length)
{
@ -169,7 +176,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
{
for (int x = 0; x < scanlineWidth; x++)
{
if (scanline[x] > 0.5)
if (scanline[x] >= 0.5)
{
scanline[x] = 1;
}

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce
{

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

3
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColor
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = MathF.DegreeToRadian(hDegrees);
float hRadians = MathFExtensions.DegreeToRadian(hDegrees);
float a = c * MathF.Cos(hRadians);
float b = c * MathF.Sin(hRadians);

3
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
@ -22,7 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColor
float l = input.L, a = input.A, b = input.B;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = MathF.RadianToDegree(hRadians);
float hDegrees = MathFExtensions.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees = hDegrees % 360;

3
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvCol
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = MathF.DegreeToRadian(hDegrees);
float hRadians = MathFExtensions.DegreeToRadian(hDegrees);
float u = c * MathF.Cos(hRadians);
float v = c * MathF.Sin(hRadians);

3
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;
@ -22,7 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvCol
float l = input.L, a = input.U, b = input.V;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = MathF.RadianToDegree(hRadians);
float hDegrees = MathFExtensions.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees = hDegrees % 360;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces;

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec2020Companding.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec709Companding.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce

1
src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/SRgbCompanding.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce

2
src/ImageSharp/Common/Extensions/Vector4Extensions.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
{

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

@ -64,6 +64,27 @@ namespace SixLabors.ImageSharp
return left * right;
}
/// <summary>
/// Returns the result of a normalized sine cardinal function for the given value.
/// SinC(x) = sin(pi*x)/(pi*x).
/// </summary>
/// <param name="f">A single-precision floating-point number to calculate the result for.</param>
/// <returns>
/// The sine cardinal of <paramref name="f" />.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SinC(float f)
{
if (MathF.Abs(f) > Constants.Epsilon)
{
f *= MathF.PI;
float result = MathF.Sin(f) / f;
return MathF.Abs(result) < Constants.Epsilon ? 0F : result;
}
return 1F;
}
/// <summary>
/// Returns the result of a B-C filter against the given value.
/// <see href="http://www.imagemagick.org/Usage/filter/#cubic_bc"/>

291
src/ImageSharp/Common/Helpers/MathF.cs

@ -1,291 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Provides single-precision floating point constants and static methods for trigonometric, logarithmic, and other common mathematical functions.
/// </summary>
// ReSharper disable InconsistentNaming
internal static class MathF
{
/// <summary>
/// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π.
/// </summary>
public const float PI = (float)Math.PI;
/// <summary>
/// Returns the absolute value of a single-precision floating-point number.
/// </summary>
/// <param name="f">
/// A number that is greater than or equal to <see cref="F:System.Single.MinValue" />, but less than or equal to <see cref="F:System.Single.MaxValue" />.
/// </param>
/// <returns>
/// A single-precision floating-point number, x, such that 0 ≤ x ≤<see cref="F:System.Single.MaxValue" />.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Abs(float f)
{
return Math.Abs(f);
}
/// <summary>
/// Returns the angle whose tangent is the quotient of two specified numbers.
/// </summary>
/// <param name="y">The y coordinate of a point.</param>
/// <param name="x">The x coordinate of a point.</param>
/// <returns>
/// An angle, θ, measured in radians, such that -π≤θ≤π, and tan(θ) = y / x, where
/// (x, y) is a point in the Cartesian plane. Observe the following: For (x, y) in
/// quadrant 1, 0 &lt; θ &lt; π/2.For (x, y) in quadrant 2, π/2 &lt; θ≤π.For (x, y) in quadrant
/// 3, -π &lt; θ &lt; -π/2.For (x, y) in quadrant 4, -π/2 &lt; θ &lt; 0.For points on the boundaries
/// of the quadrants, the return value is the following:If y is 0 and x is not negative,
/// θ = 0.If y is 0 and x is negative, θ = π.If y is positive and x is 0, θ = π/2.If
/// y is negative and x is 0, θ = -π/2.If y is 0 and x is 0, θ = 0. If x or y is
/// <see cref="F:System.Single.NaN"/>, or if x and y are either <see cref="F:System.Single.PositiveInfinity"/> or
/// <see cref="F:System.Single.NegativeInfinity"/>, the method returns <see cref="F:System.Single.NaN"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Atan2(float y, float x)
{
return (float)Math.Atan2(y, x);
}
/// <summary>
/// Returns the smallest integral value that is greater than or equal to the specified single-precision floating-point number.
/// </summary>
/// <param name="f">A single-precision floating-point number.</param>
/// <returns>
/// The smallest integral value that is greater than or equal to <paramref name="f" />.
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
/// or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Ceiling(float f)
{
return (float)Math.Ceiling(f);
}
/// <summary>
/// Returns the cosine of the specified angle.
/// </summary>
/// <param name="f">An angle, measured in radians.</param>
/// <returns>
/// The cosine of <paramref name="f"/>. If <paramref name="f"/> is equal to <see cref="F:System.Float.NaN"/>, <see cref="F:System.Float.NegativeInfinity"/>,
/// or <see cref="F:System.Float.PositiveInfinity"/>, this method returns <see cref="F:System.Float.NaN"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Cos(float f)
{
return (float)Math.Cos(f);
}
/// <summary>
/// Converts a degree (360-periodic) angle to a radian (2*Pi-periodic) angle.
/// </summary>
/// <param name="degree">The angle in degrees.</param>
/// <returns>
/// The <see cref="float"/> representing the degree as radians.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DegreeToRadian(float degree)
{
return degree * (PI / 180F);
}
/// <summary>
/// Returns e raised to the specified power.
/// </summary>
/// <param name="f">A number specifying a power.</param>
/// <returns>
/// The number e raised to the power <paramref name="f" />.
/// If <paramref name="f" /> equals <see cref="F:System.Single.NaN" /> or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
/// If <paramref name="f" /> equals <see cref="F:System.Single.NegativeInfinity" />, 0 is returned.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Exp(float f)
{
return (float)Math.Exp(f);
}
/// <summary>
/// Returns the largest integer less than or equal to the specified single-precision floating-point number.
/// </summary>
/// <param name="f">A single-precision floating-point number. </param>
/// <returns>
/// The largest integer less than or equal to <paramref name="f" />.
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
/// or <see cref="F:System.Single.PositiveInfinity" />, that value is returned.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Floor(float f)
{
return (float)Math.Floor(f);
}
/// <summary>
/// Returns the larger of two single-precision floating-point numbers.
/// </summary>
/// <param name="val1">The first of two single-precision floating-point numbers to compare. </param>
/// <param name="val2">The second of two single-precision floating-point numbers to compare. </param>
/// <returns>
/// Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is larger.
/// If <paramref name="val1" />, or <paramref name="val2" />, or both <paramref name="val1" /> and <paramref name="val2" /> are
/// equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NaN" /> is returned.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Max(float val1, float val2)
{
return Math.Max(val1, val2);
}
/// <summary>
/// Returns the smaller of two single-precision floating-point numbers.
/// </summary>
/// <param name="val1">The first of two single-precision floating-point numbers to compare. </param>
/// <param name="val2">The second of two single-precision floating-point numbers to compare. </param>
/// <returns>
/// Parameter <paramref name="val1" /> or <paramref name="val2" />, whichever is smaller.
/// If <paramref name="val1" />, <paramref name="val2" />, or both <paramref name="val1" /> and <paramref name="val2" /> are equal
/// to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NaN" /> is returned.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Min(float val1, float val2)
{
return Math.Min(val1, val2);
}
/// <summary>
/// Returns a specified number raised to the specified power.
/// </summary>
/// <param name="x">A single-precision floating-point number to be raised to a power. </param>
/// <param name="y">A single-precision floating-point number that specifies a power. </param>
/// <returns>The number <paramref name="x" /> raised to the power <paramref name="y" />.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Pow(float x, float y)
{
return (float)Math.Pow(x, y);
}
/// <summary>
/// Converts a radian (2*Pi-periodic) angle to a degree (360-periodic) angle.
/// </summary>
/// <param name="radian">The angle in radians.</param>
/// <returns>
/// The <see cref="float"/> representing the degree as radians.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float RadianToDegree(float radian)
{
return radian / (PI / 180F);
}
/// <summary>
/// Rounds a single-precision floating-point value to the nearest integral value.
/// </summary>
/// <param name="f">A single-precision floating-point number to be rounded.</param>
/// <returns>
/// The integer nearest <paramref name="f" />.
/// If the fractional component of <paramref name="f" /> is halfway between two integers, one of which is even and the other odd, then the even number is returned.
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Round(float f)
{
return (float)Math.Round(f);
}
/// <summary>
/// Rounds a single-precision floating-point value to the nearest integer.
/// A parameter specifies how to round the value if it is midway between two numbers.
/// </summary>
/// <param name="f">A single-precision floating-point number to be rounded. </param>
/// <param name="mode">Specification for how to round <paramref name="f" /> if it is midway between two other numbers.</param>
/// <returns>
/// The integer nearest <paramref name="f" />. If <paramref name="f" /> is halfway between two integers, one of which is even
/// and the other odd, then <paramref name="mode" /> determines which of the two is returned.
/// Note that this method returns a <see cref="T:System.Single" /> instead of an integral type.
/// </returns>
/// <exception cref="T:System.ArgumentException">
/// <paramref name="mode" /> is not a valid value of <see cref="T:System.MidpointRounding" />.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Round(float f, MidpointRounding mode)
{
return (float)Math.Round(f, mode);
}
/// <summary>
/// Returns the sine of the specified angle.
/// </summary>
/// <param name="f">An angle, measured in radians.</param>
/// <returns>
/// The sine of <paramref name="f" />.
/// If <paramref name="f" /> is equal to <see cref="F:System.Single.NaN" />, <see cref="F:System.Single.NegativeInfinity" />,
/// or <see cref="F:System.Single.PositiveInfinity" />, this method returns <see cref="F:System.Single.NaN" />.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Sin(float f)
{
return (float)Math.Sin(f);
}
/// <summary>
/// Returns the result of a normalized sine cardinal function for the given value.
/// SinC(x) = sin(pi*x)/(pi*x).
/// </summary>
/// <param name="f">A single-precision floating-point number to calculate the result for.</param>
/// <returns>
/// The sine cardinal of <paramref name="f" />.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SinC(float f)
{
if (Abs(f) > Constants.Epsilon)
{
f *= PI;
return Clean(Sin(f) / f);
}
return 1F;
}
/// <summary>
/// Returns the square root of a specified number.
/// </summary>
/// <param name="f">The number whose square root is to be found.</param>
/// <returns>
/// One of the values in the following table.
/// <paramref name="f" /> parameter Return value Zero or positive The positive square root of <paramref name="f" />.
/// Negative <see cref="F:System.Single.NaN" />Equals <see cref="F:System.Single.NaN" />
/// <see cref="F:System.Single.NaN" />Equals <see cref="F:System.Single.PositiveInfinity" />
/// <see cref="F:System.Single.PositiveInfinity" />
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Sqrt(float f)
{
return (float)Math.Sqrt(f);
}
/// <summary>
/// Ensures that any passed float is correctly rounded to zero
/// </summary>
/// <param name="x">The value to clean.</param>
/// <returns>
/// The <see cref="float"/>
/// </returns>.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float Clean(float x)
{
if (Abs(x) < Constants.Epsilon)
{
return 0F;
}
return x;
}
}
}

4
src/ImageSharp/Dithering/Ordered/IOrderedDither.cs

@ -17,12 +17,12 @@ namespace SixLabors.ImageSharp.Dithering
/// <param name="source">The source pixel</param>
/// <param name="upper">The color to apply to the pixels above the threshold.</param>
/// <param name="lower">The color to apply to the pixels below the threshold.</param>
/// <param name="bytes">The byte array to pack/unpack to. Must have a length of 4. Bytes are unpacked to Xyzw order.</param>
/// <param name="rgba">The <see cref="Rgba32"/> to pack/unpack to.</param>
/// <param name="index">The component index to test the threshold against. Must range from 0 to 3.</param>
/// <param name="x">The column index.</param>
/// <param name="y">The row index.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
void Dither<TPixel>(ImageFrame<TPixel> image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y)
void Dither<TPixel>(ImageFrame<TPixel> image, TPixel source, TPixel upper, TPixel lower, ref Rgba32 rgba, int index, int x, int y)
where TPixel : struct, IPixel<TPixel>;
}
}

28
src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs

@ -1,13 +1,14 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Dithering.Base
{
/// <summary>
/// The base class for performing ordered ditheroing using a 4x4 matrix.
/// The base class for performing ordered dithering using a 4x4 matrix.
/// </summary>
public abstract class OrderedDitherBase : IOrderedDither
{
@ -26,14 +27,27 @@ namespace SixLabors.ImageSharp.Dithering.Base
}
/// <inheritdoc />
public void Dither<TPixel>(ImageFrame<TPixel> image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y)
public void Dither<TPixel>(ImageFrame<TPixel> image, TPixel source, TPixel upper, TPixel lower, ref Rgba32 rgba, int index, int x, int y)
where TPixel : struct, IPixel<TPixel>
{
// TODO: This doesn't really cut it for me.
// I'd rather be using float but we need to add some sort of normalization vector methods to all IPixel implementations
// before we can do that as the vectors all cover different ranges.
source.ToXyzwBytes(bytes, 0);
image[x, y] = this.matrix[y % 3, x % 3] >= bytes[index] ? lower : upper;
source.ToRgba32(ref rgba);
switch (index)
{
case 0:
image[x, y] = this.matrix[y % 3, x % 3] >= rgba.R ? lower : upper;
return;
case 1:
image[x, y] = this.matrix[y % 3, x % 3] >= rgba.G ? lower : upper;
return;
case 2:
image[x, y] = this.matrix[y % 3, x % 3] >= rgba.B ? lower : upper;
return;
case 3:
image[x, y] = this.matrix[y % 3, x % 3] >= rgba.A ? lower : upper;
return;
}
throw new ArgumentOutOfRangeException(nameof(index), "Index should be between 0 and 3 inclusive.");
}
}
}

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

@ -7,6 +7,7 @@ using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@ -38,7 +39,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// The global color table.
/// </summary>
private byte[] globalColorTable;
private Buffer<byte> globalColorTable;
/// <summary>
/// The global color table length
@ -123,10 +124,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (this.logicalScreenDescriptor.GlobalColorTableFlag)
{
this.globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;
this.globalColorTable = ArrayPool<byte>.Shared.Rent(this.globalColorTableLength);
this.globalColorTable = Buffer<byte>.CreateClean(this.globalColorTableLength);
// Read the global color table from the stream
stream.Read(this.globalColorTable, 0, this.globalColorTableLength);
stream.Read(this.globalColorTable.Array, 0, this.globalColorTableLength);
}
// Loop though the respective gif parts and read the data.
@ -154,10 +155,15 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.ReadComments();
break;
case GifConstants.ApplicationExtensionLabel:
this.Skip(12); // No need to read.
// The application extension length should be 11 but we've got test images that incorrectly
// set this to 252.
int appLength = stream.ReadByte();
this.Skip(appLength); // No need to read.
break;
case GifConstants.PlainTextLabel:
this.Skip(13); // Not supported by any known decoder.
int plainLength = stream.ReadByte();
this.Skip(plainLength); // Not supported by any known decoder.
break;
}
}
@ -175,10 +181,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
finally
{
if (this.globalColorTable != null)
{
ArrayPool<byte>.Shared.Return(this.globalColorTable);
}
this.globalColorTable?.Dispose();
}
return this.image;
@ -309,19 +312,19 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
GifImageDescriptor imageDescriptor = this.ReadImageDescriptor();
byte[] localColorTable = null;
byte[] indices = null;
Buffer<byte> localColorTable = null;
Buffer<byte> indices = null;
try
{
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
if (imageDescriptor.LocalColorTableFlag)
{
int length = imageDescriptor.LocalColorTableSize * 3;
localColorTable = ArrayPool<byte>.Shared.Rent(length);
this.currentStream.Read(localColorTable, 0, length);
localColorTable = Buffer<byte>.CreateClean(length);
this.currentStream.Read(localColorTable.Array, 0, length);
}
indices = ArrayPool<byte>.Shared.Rent(imageDescriptor.Width * imageDescriptor.Height);
indices = Buffer<byte>.CreateClean(imageDescriptor.Width * imageDescriptor.Height);
this.ReadFrameIndices(imageDescriptor, indices);
this.ReadFrameColors(indices, localColorTable ?? this.globalColorTable, imageDescriptor);
@ -331,12 +334,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
finally
{
if (localColorTable != null)
{
ArrayPool<byte>.Shared.Return(localColorTable);
}
ArrayPool<byte>.Shared.Return(indices);
localColorTable?.Dispose();
indices?.Dispose();
}
}
@ -346,7 +345,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param>
/// <param name="indices">The pixel array to write to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadFrameIndices(GifImageDescriptor imageDescriptor, byte[] indices)
private void ReadFrameIndices(GifImageDescriptor imageDescriptor, Span<byte> indices)
{
int dataSize = this.currentStream.ReadByte();
using (var lzwDecoder = new LzwDecoder(this.currentStream))
@ -361,7 +360,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="indices">The indexed pixels.</param>
/// <param name="colorTable">The color table containing the available colors.</param>
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor)
private void ReadFrameColors(Span<byte> indices, Span<byte> colorTable, GifImageDescriptor descriptor)
{
int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height;
@ -444,7 +443,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
var rgba = new Rgba32(0, 0, 0, 255);
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++)
// #403 The left + width value can be larger than the image width
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < rowSpan.Length; x++)
{
int index = indices[i];

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

@ -351,16 +351,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Get max colors for bit depth.
int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3;
byte[] colorTable = ArrayPool<byte>.Shared.Rent(colorTableLength);
var rgb = default(Rgb24);
try
{
for (int i = 0; i < pixelCount; i++)
{
int offset = i * 3;
image.Palette[i].ToXyzBytes(this.buffer, 0);
colorTable[offset] = this.buffer[0];
colorTable[offset + 1] = this.buffer[1];
colorTable[offset + 2] = this.buffer[2];
image.Palette[i].ToRgb24(ref rgb);
colorTable[offset] = rgb.R;
colorTable[offset + 1] = rgb.G;
colorTable[offset + 2] = rgb.B;
}
writer.Write(colorTable, 0, colorTableLength);

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

@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="height">The height of the pixel index array.</param>
/// <param name="dataSize">Size of the data.</param>
/// <param name="pixels">The pixel array to decode to.</param>
public void DecodePixels(int width, int height, int dataSize, byte[] pixels)
public void DecodePixels(int width, int height, int dataSize, Span<byte> pixels)
{
Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize));

1
src/ImageSharp/Formats/Jpeg/Common/SizeExtensions.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.Primitives;

3
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs

@ -583,7 +583,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
}
zig = this.RefineNonZeroes(ref bp, zig, val0, delta);
if (bp.ReachedEOF)
if (bp.ReachedEOF || bp.HasError)
{
return;
}

2
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -688,7 +688,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
}
int th = this.Temp[0] & 0x0f;
if (th > OrigHuffmanTree.MaxTh || (!this.IsProgressive && (th > 1)))
if (th > OrigHuffmanTree.MaxTh)
{
throw new ImageFormatException("Bad Th value");
}

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

@ -318,6 +318,7 @@ namespace SixLabors.ImageSharp.Formats.Png
where TPixel : struct, IPixel<TPixel>
{
byte[] rawScanlineArray = this.rawScanline.Array;
var rgba = default(Rgba32);
// Copy the pixels across from the image.
// Reuse the chunk type buffer.
@ -326,8 +327,8 @@ namespace SixLabors.ImageSharp.Formats.Png
// Convert the color to YCbCr and store the luminance
// Optionally store the original color alpha.
int offset = x * this.bytesPerPixel;
rowSpan[x].ToXyzwBytes(this.chunkTypeBuffer, 0);
byte luminance = (byte)((0.299F * this.chunkTypeBuffer[0]) + (0.587F * this.chunkTypeBuffer[1]) + (0.114F * this.chunkTypeBuffer[2]));
rowSpan[x].ToRgba32(ref rgba);
byte luminance = (byte)((0.299F * rgba.R) + (0.587F * rgba.G) + (0.114F * rgba.B));
for (int i = 0; i < this.bytesPerPixel; i++)
{
@ -337,7 +338,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
rawScanlineArray[offset + i] = this.chunkTypeBuffer[3];
rawScanlineArray[offset + i] = rgba.A;
}
}
}
@ -518,7 +519,7 @@ namespace SixLabors.ImageSharp.Formats.Png
int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3;
byte[] colorTable = ArrayPool<byte>.Shared.Rent(colorTableLength);
byte[] alphaTable = ArrayPool<byte>.Shared.Rent(pixelCount);
byte[] bytes = ArrayPool<byte>.Shared.Rent(4);
var rgba = default(Rgba32);
bool anyAlpha = false;
try
{
@ -527,13 +528,13 @@ namespace SixLabors.ImageSharp.Formats.Png
if (quantized.Pixels.Contains(i))
{
int offset = i * 3;
palette[i].ToXyzwBytes(bytes, 0);
palette[i].ToRgba32(ref rgba);
byte alpha = bytes[3];
byte alpha = rgba.A;
colorTable[offset] = bytes[0];
colorTable[offset + 1] = bytes[1];
colorTable[offset + 2] = bytes[2];
colorTable[offset] = rgba.R;
colorTable[offset + 1] = rgba.G;
colorTable[offset + 2] = rgba.B;
if (alpha > this.threshold)
{
@ -557,7 +558,6 @@ namespace SixLabors.ImageSharp.Formats.Png
{
ArrayPool<byte>.Shared.Return(colorTable);
ArrayPool<byte>.Shared.Return(alphaTable);
ArrayPool<byte>.Shared.Return(bytes);
}
return quantized;

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
@ -74,9 +75,17 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
public long Value => this.checksum;
public long Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.checksum;
}
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
this.checksum = 1;
@ -88,6 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <param name="value">
/// The data value to add. The high byte of the int is ignored.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(int value)
{
// We could make a length 1 byte array and call update again, but I
@ -102,6 +112,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer)
{
if (buffer == null)
@ -113,32 +124,14 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset), "cannot be negative");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "cannot be negative");
}
if (offset >= buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset), "not a valid index into buffer");
}
if (offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(count), "exceeds buffer size");
}
DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset));
DebugGuard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
DebugGuard.MustBeLessThan(offset, buffer.Length, nameof(offset));
DebugGuard.MustBeLessThanOrEqualTo(offset + count, buffer.Length, nameof(count));
// (By Per Bothner)
uint s1 = this.checksum & 0xFFFF;
@ -169,4 +162,4 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.checksum = (s2 << 16) | s1;
}
}
}
}

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
@ -108,18 +109,15 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <inheritdoc/>
public long Value
{
get
{
return this.crc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.crc;
set
{
this.crc = (uint)value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => this.crc = (uint)value;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset()
{
this.crc = 0;
@ -129,6 +127,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// Updates the checksum with the given value.
/// </summary>
/// <param name="value">The byte is taken as the lower 8 bits of value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(int value)
{
this.crc ^= CrcSeed;
@ -137,6 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer)
{
if (buffer == null)
@ -148,22 +148,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Update(byte[] buffer, int offset, int count)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
if (count < 0)
{
throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be less than zero");
}
if (offset < 0 || offset + count > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(offset));
}
DebugGuard.NotNull(buffer, nameof(buffer));
DebugGuard.MustBeGreaterThanOrEqualTo(count, 0, nameof(count));
DebugGuard.MustBeGreaterThanOrEqualTo(offset, 0, nameof(offset));
DebugGuard.MustBeLessThanOrEqualTo(offset + count, buffer.Length, nameof(count));
this.crc ^= CrcSeed;

65
src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs

@ -2,10 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
namespace SixLabors.ImageSharp.Formats.Png.Zlib
{
@ -14,6 +12,13 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// </summary>
internal sealed class ZlibInflateStream : Stream
{
/// <summary>
/// Used to read the Adler-32 and Crc-32 checksums
/// We don't actually use this for anything so it doesn't
/// have to be threadsafe.
/// </summary>
private static readonly byte[] ChecksumBuffer = new byte[4];
/// <summary>
/// The inner raw memory stream
/// </summary>
@ -38,9 +43,9 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private bool isDisposed;
/// <summary>
/// The read crc data.
/// Whether the crc value has been read.
/// </summary>
private byte[] crcread;
private bool crcRead;
/// <summary>
/// The current data remaining to be read
@ -149,14 +154,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
this.compressedStream.Dispose();
this.compressedStream = null;
if (this.crcread == null)
if (!this.crcRead)
{
// Consume the trailing 4 bytes
this.crcread = new byte[4];
for (int i = 0; i < 4; i++)
{
this.crcread[i] = (byte)this.innerStream.ReadByte();
}
this.innerStream.Read(ChecksumBuffer, 0, 4);
this.currentDataRemaining -= 4;
this.crcRead = true;
}
}
}
@ -171,11 +174,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
private void InitializeInflateStream()
{
// The DICT dictionary identifier identifying the used dictionary.
// The preset dictionary.
bool fdict;
// Read the zlib header : http://tools.ietf.org/html/rfc1950
// CMF(Compression Method and flags)
// This byte is divided into a 4 - bit compression method and a
@ -195,30 +193,35 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
return;
}
if ((cmf & 0x0f) != 8)
if ((cmf & 0x0F) == 8)
{
throw new Exception($"Bad compression method for ZLIB header: cmf={cmf}");
}
// CINFO is the base-2 logarithm of the LZ77 window size, minus eight.
int cinfo = (cmf & 0xF0) >> 4;
// CINFO is the base-2 logarithm of the LZ77 window size, minus eight.
// int cinfo = ((cmf & (0xf0)) >> 8);
fdict = (flag & 32) != 0;
if (cinfo > 7)
{
// Values of CINFO above 7 are not allowed in RFC1950.
// CINFO is not defined in this specification for CM not equal to 8.
throw new ImageFormatException($"Invalid window size for ZLIB header: cinfo={cinfo}");
}
}
else
{
throw new ImageFormatException($"Bad method for ZLIB header: cmf={cmf}");
}
// The preset dictionary.
bool fdict = (flag & 32) != 0;
if (fdict)
{
// The DICT dictionary identifier identifying the used dictionary.
byte[] dictId = new byte[4];
for (int i = 0; i < 4; i++)
{
// We consume but don't use this.
dictId[i] = (byte)this.innerStream.ReadByte();
this.currentDataRemaining--;
}
// We don't need this for inflate so simply skip by the next four bytes.
// https://tools.ietf.org/html/rfc1950#page-6
this.innerStream.Read(ChecksumBuffer, 0, 4);
this.currentDataRemaining -= 4;
}
// Initialize the deflate Stream.
this.compressedStream = new DeflateStream(this, CompressionMode.Decompress, true);
}
}
}
}

6
src/ImageSharp/Image/PixelAccessorExtensions.cs

@ -1,14 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Unsafe = System.Runtime.CompilerServices.Unsafe;
namespace SixLabors.ImageSharp
{

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

@ -7,7 +7,6 @@ using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Unsafe = System.Runtime.CompilerServices.Unsafe;
namespace SixLabors.ImageSharp
{

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

@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp
/// <summary>
/// The underlying buffer containing the raw pixel data.
/// </summary>
private Buffer<byte> byteBuffer;
private readonly Buffer<byte> byteBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TPixel}"/> class.
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp
this.RowStride = (width * GetComponentCount(componentOrder)) + padding;
this.Length = this.RowStride * height;
this.byteBuffer = new Buffer<byte>(this.Length);
this.byteBuffer = Buffer<byte>.CreateClean(this.Length);
}
/// <summary>

234
src/ImageSharp/ImageSharp.csproj

@ -1,118 +1,120 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A cross-platform library for the processing of image files; written in C#</Description>
<AssemblyTitle>SixLabors.ImageSharp</AssemblyTitle>
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>Six Labors and contributors</Authors>
<TargetFrameworks>netstandard1.1;netstandard1.3</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp</AssemblyName>
<PackageId>SixLabors.ImageSharp</PackageId>
<PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Core</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<DebugType Condition="$(codecov) != ''">full</DebugType>
<DebugType Condition="$(codecov) == ''">portable</DebugType>
<DebugSymbols>True</DebugSymbols>
<Features>IOperation</Features>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0003" />
<AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.4.0" />
<PackageReference Include="System.Memory" Version="4.4.0-preview2-25405-01" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.4.0" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>
<RootNamespace>SixLabors.ImageSharp</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<None Update="Formats\Jpeg\Common\Block8x8F.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None>
<None Update="Formats\Jpeg\Components\Block8x8F.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\PixelOperations{TPixel}.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt">
<LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
<None Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.tt">
<LastGenOutput>DefaultPixelBlenders.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Formats\Jpeg\Common\Block8x8F.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Update="Formats\Jpeg\Components\Block8x8F.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\PixelOperations{TPixel}.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>PixelOperations{TPixel}.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DefaultPixelBlenders.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>PorterDuffFunctions.Generated.tt</DependentUpon>
</Compile>
</ItemGroup>
<PropertyGroup>
<Description>A cross-platform library for the processing of image files; written in C#</Description>
<AssemblyTitle>SixLabors.ImageSharp</AssemblyTitle>
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>Six Labors and contributors</Authors>
<TargetFrameworks>netstandard1.1;netstandard1.3;netstandard2.0</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp</AssemblyName>
<PackageId>SixLabors.ImageSharp</PackageId>
<PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Core</PackageTags>
<PackageIconUrl>https://raw.githubusercontent.com/SixLabors/ImageSharp/master/build/icons/imagesharp-logo-128.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/SixLabors/ImageSharp</PackageProjectUrl>
<PackageLicenseUrl>http://www.apache.org/licenses/LICENSE-2.0</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/SixLabors/ImageSharp</RepositoryUrl>
<GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateNeutralResourcesLanguageAttribute>false</GenerateNeutralResourcesLanguageAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<GenerateAssemblyInformationalVersionAttribute>false</GenerateAssemblyInformationalVersionAttribute>
<DebugType Condition="$(codecov) != ''">full</DebugType>
<DebugType Condition="$(codecov) == ''">portable</DebugType>
<DebugSymbols>True</DebugSymbols>
<Features>IOperation</Features>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Shared\*.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="SixLabors.Core" Version="1.0.0-beta0004" />
<AdditionalFiles Include="..\..\stylecop.json" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta004">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.4.0" />
<PackageReference Include="System.Memory" Version="4.4.0-preview2-25405-01" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.4.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' OR '$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.4.0" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>
<RootNamespace>SixLabors.ImageSharp</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<None Update="Formats\Jpeg\Common\Block8x8F.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None>
<None Update="Formats\Jpeg\Components\Block8x8F.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\PixelOperations{TPixel}.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt">
<LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
<None Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.tt">
<LastGenOutput>DefaultPixelBlenders.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
</None>
</ItemGroup>
<ItemGroup>
<Service Include="{508349b6-6b84-4df5-91f0-309beebad82d}" />
</ItemGroup>
<ItemGroup>
<Compile Update="Formats\Jpeg\Common\Block8x8F.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Update="Formats\Jpeg\Components\Block8x8F.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\PixelOperations{TPixel}.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>PixelOperations{TPixel}.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>DefaultPixelBlenders.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>PorterDuffFunctions.Generated.tt</DependentUpon>
</Compile>
</ItemGroup>
</Project>

2
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param>
/// <param name="rectangle">The rectangel subarea</param>
/// <param name="rectangle">The rectangle subarea</param>
/// <returns>The <see cref="BufferArea{T}"/></returns>
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer, Rectangle rectangle)
where T : struct => new BufferArea<T>(buffer, rectangle);

1
src/ImageSharp/Memory/SpanHelper.cs

@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using Unsafe = System.Runtime.CompilerServices.Unsafe;
namespace SixLabors.ImageSharp.Memory
{

8
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs

@ -2,11 +2,13 @@
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
internal static partial class PorterDuffFunctions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]

8
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt

@ -12,11 +12,13 @@
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{
using System.Numerics;
using System.Runtime.CompilerServices;
internal static partial class PorterDuffFunctions
{
<#

1
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;

79
src/ImageSharp/PixelFormats/PixelConversionExtensions.cs

@ -1,79 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Extension methods for copying single pixel data into byte Spans.
/// TODO: This utility class exists for legacy reasons. Need to do a lot of chore work to remove it (mostly in test classes).
/// </summary>
internal static class PixelConversionExtensions
{
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in <see cref="Rgb24"/>
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="pixel">The pixel to copy the data from.</param>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToXyzBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex)
where TPixel : struct, IPixel<TPixel>
{
ref Rgb24 dest = ref bytes.GetRgb24(startIndex);
pixel.ToRgb24(ref dest);
}
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in <see cref="Rgba32"/>
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="pixel">The pixel to copy the data from.</param>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToXyzwBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex)
where TPixel : struct, IPixel<TPixel>
{
ref Rgba32 dest = ref Unsafe.As<byte, Rgba32>(ref bytes[startIndex]);
pixel.ToRgba32(ref dest);
}
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in <see cref="Bgr24"/>
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="pixel">The pixel to copy the data from.</param>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToZyxBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex)
where TPixel : struct, IPixel<TPixel>
{
ref Bgr24 dest = ref Unsafe.As<byte, Bgr24>(ref bytes[startIndex]);
pixel.ToBgr24(ref dest);
}
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in <see cref="Bgra32"/>
/// </summary>
/// <typeparam name="TPixel">The pixel type.</typeparam>
/// <param name="pixel">The pixel to copy the data from.</param>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToZyxwBytes<TPixel>(this TPixel pixel, Span<byte> bytes, int startIndex)
where TPixel : struct, IPixel<TPixel>
{
ref Bgra32 dest = ref Unsafe.As<byte, Bgra32>(ref bytes[startIndex]);
pixel.ToBgra32(ref dest);
}
}
}

4
src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs

@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
int startX = interest.X;
int endX = interest.Right;
byte[] bytes = new byte[4];
var rgba = default(Rgba32);
for (int y = startY; y < endY; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
for (int x = startX; x < endX; x++)
{
TPixel sourceColor = row[x];
this.Dither.Dither(source, sourceColor, this.UpperColor, this.LowerColor, bytes, this.Index, x, y);
this.Dither.Dither(source, sourceColor, this.UpperColor, this.LowerColor, ref rgba, this.Index, x, y);
}
}
}

3
src/ImageSharp/Processing/Processors/ColorMatrix/HueProcessor.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
@ -30,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
this.Angle = angle;
float radians = MathF.DegreeToRadian(angle);
float radians = MathFExtensions.DegreeToRadian(angle);
float cosradians = MathF.Cos(radians);
float sinradians = MathF.Sin(radians);

6
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal abstract partial class ResamplingWeightedProcessor<TPixel>
{
/// <summary>
/// Points to a collection of of weights allocated in <see cref="WeightsBuffer"/>.
/// Points to a collection of weights allocated in <see cref="WeightsBuffer"/>.
/// </summary>
internal struct WeightsWindow
{
@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
/// <summary>
/// Holds the <see cref="WeightsWindow"/> values in an optimized contigous memory region.
/// Holds the <see cref="WeightsWindow"/> values in an optimized contiguous memory region.
/// </summary>
internal class WeightsBuffer : IDisposable
{
@ -196,4 +196,4 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
}
}
}
}

4
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -58,9 +58,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
// We will always be creating the clone even for mutate because thats the way this base processor works
// ------------
// For resize we know we are going to populate every pixel with fresh data and we want a different target size so
// let's manually clone an empty set of images at the correct target and then have the base class processs them in turn.
// let's manually clone an empty set of images at the correct target and then have the base class process them in turn.
IEnumerable<ImageFrame<TPixel>> frames = source.Frames.Select(x => new ImageFrame<TPixel>(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders
var image = new Image<TPixel>(config, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added
var image = new Image<TPixel>(config, source.MetaData.Clone(), frames); // base the place holder images in to prevent a extra frame being added
return image;
}

1
src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Linq;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;

2
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos2Resampler.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing
if (x < 2F)
{
return MathF.SinC(x) * MathF.SinC(x / 2F);
return ImageMaths.SinC(x) * ImageMaths.SinC(x / 2F);
}
return 0F;

2
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos3Resampler.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing
if (x < 3F)
{
return MathF.SinC(x) * MathF.SinC(x / 3F);
return ImageMaths.SinC(x) * ImageMaths.SinC(x / 3F);
}
return 0F;

2
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos5Resampler.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing
if (x < 5F)
{
return MathF.SinC(x) * MathF.SinC(x / 5F);
return ImageMaths.SinC(x) * ImageMaths.SinC(x / 5F);
}
return 0F;

2
src/ImageSharp/Processing/Transforms/Resamplers/Lanczos8Resampler.cs

@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Processing
if (x < 8F)
{
return MathF.SinC(x) * MathF.SinC(x / 8F);
return ImageMaths.SinC(x) * ImageMaths.SinC(x / 8F);
}
return 0F;

2
src/ImageSharp/Processing/Transforms/Resamplers/WelchResampler.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing
if (x < 3F)
{
return MathF.SinC(x) * (1F - (x * x / 9F));
return ImageMaths.SinC(x) * (1F - (x * x / 9F));
}
return 0F;

1
src/ImageSharp/Processing/Transforms/Resize.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors;

5
src/ImageSharp/Quantizers/Box.cs

@ -5,9 +5,8 @@ namespace SixLabors.ImageSharp.Quantizers
{
/// <summary>
/// Represents a box color cube.
/// TODO: This should be a struct for performance
/// </summary>
internal sealed class Box
internal struct Box
{
/// <summary>
/// Gets or sets the min red value, exclusive.
@ -54,4 +53,4 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
public int Volume { get; set; }
}
}
}

208
src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs

@ -60,11 +60,6 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount;
/// <summary>
/// A buffer for storing pixels
/// </summary>
private readonly byte[] rgbaBuffer = new byte[4];
/// <summary>
/// A lookup table for colors
/// </summary>
@ -173,20 +168,19 @@ namespace SixLabors.ImageSharp.Quantizers
this.palette = new TPixel[this.colors];
for (int k = 0; k < this.colors; k++)
{
this.Mark(this.colorCube[k], (byte)k);
this.Mark(ref this.colorCube[k], (byte)k);
float weight = Volume(this.colorCube[k], this.vwt);
float weight = Volume(ref this.colorCube[k], this.vwt);
if (MathF.Abs(weight) > Constants.Epsilon)
{
float r = Volume(this.colorCube[k], this.vmr) / weight;
float g = Volume(this.colorCube[k], this.vmg) / weight;
float b = Volume(this.colorCube[k], this.vmb) / weight;
float a = Volume(this.colorCube[k], this.vma) / weight;
var color = default(TPixel);
color.PackFromVector4(new Vector4(r, g, b, a) / 255F);
this.palette[k] = color;
float r = Volume(ref this.colorCube[k], this.vmr);
float g = Volume(ref this.colorCube[k], this.vmg);
float b = Volume(ref this.colorCube[k], this.vmb);
float a = Volume(ref this.colorCube[k], this.vma);
ref TPixel color = ref this.palette[k];
color.PackFromVector4(new Vector4(r, g, b, a) / weight / 255F);
}
}
}
@ -199,26 +193,24 @@ namespace SixLabors.ImageSharp.Quantizers
{
// Add the color to a 3-D color histogram.
// Colors are expected in r->g->b->a format
pixel.ToXyzwBytes(this.rgbaBuffer, 0);
byte r = this.rgbaBuffer[0];
byte g = this.rgbaBuffer[1];
byte b = this.rgbaBuffer[2];
byte a = this.rgbaBuffer[3];
int inr = r >> (8 - IndexBits);
int ing = g >> (8 - IndexBits);
int inb = b >> (8 - IndexBits);
int ina = a >> (8 - IndexAlphaBits);
int ind = GetPaletteIndex(inr + 1, ing + 1, inb + 1, ina + 1);
this.vwt[ind]++;
this.vmr[ind] += r;
this.vmg[ind] += g;
this.vmb[ind] += b;
this.vma[ind] += a;
this.m2[ind] += (r * r) + (g * g) + (b * b) + (a * a);
var rgba = default(Rgba32);
pixel.ToRgba32(ref rgba);
int r = rgba.R >> (8 - IndexBits);
int g = rgba.G >> (8 - IndexBits);
int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits);
int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
this.vwt[index]++;
this.vmr[index] += rgba.R;
this.vmg[index] += rgba.G;
this.vmb[index] += rgba.B;
this.vma[index] += rgba.A;
var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A);
this.m2[index] += Vector4.Dot(vector, vector);
}
/// <inheritdoc/>
@ -310,7 +302,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="cube">The cube.</param>
/// <param name="moment">The moment.</param>
/// <returns>The result.</returns>
private static float Volume(Box cube, long[] moment)
private static float Volume(ref Box cube, long[] moment)
{
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
@ -337,12 +329,12 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="direction">The direction.</param>
/// <param name="moment">The moment.</param>
/// <returns>The result.</returns>
private static long Bottom(Box cube, int direction, long[] moment)
private static long Bottom(ref Box cube, int direction, long[] moment)
{
switch (direction)
{
// Red
case 0:
case 3:
return -moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R0, cube.G1, cube.B0, cube.A1)]
@ -353,7 +345,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Green
case 1:
case 2:
return -moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
@ -364,7 +356,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Blue
case 2:
case 1:
return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A1)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B0, cube.A1)]
@ -375,7 +367,7 @@ namespace SixLabors.ImageSharp.Quantizers
+ moment[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
// Alpha
case 3:
case 0:
return -moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, cube.A0)]
+ moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, cube.A0)]
@ -398,12 +390,12 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="position">The position.</param>
/// <param name="moment">The moment.</param>
/// <returns>The result.</returns>
private static long Top(Box cube, int direction, int position, long[] moment)
private static long Top(ref Box cube, int direction, int position, long[] moment)
{
switch (direction)
{
// Red
case 0:
case 3:
return moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A1)]
- moment[GetPaletteIndex(position, cube.G1, cube.B1, cube.A0)]
- moment[GetPaletteIndex(position, cube.G1, cube.B0, cube.A1)]
@ -414,7 +406,7 @@ namespace SixLabors.ImageSharp.Quantizers
- moment[GetPaletteIndex(position, cube.G0, cube.B0, cube.A0)];
// Green
case 1:
case 2:
return moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A1)]
- moment[GetPaletteIndex(cube.R1, position, cube.B1, cube.A0)]
- moment[GetPaletteIndex(cube.R1, position, cube.B0, cube.A1)]
@ -425,7 +417,7 @@ namespace SixLabors.ImageSharp.Quantizers
- moment[GetPaletteIndex(cube.R0, position, cube.B0, cube.A0)];
// Blue
case 2:
case 1:
return moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A1)]
- moment[GetPaletteIndex(cube.R1, cube.G1, position, cube.A0)]
- moment[GetPaletteIndex(cube.R1, cube.G0, position, cube.A1)]
@ -436,7 +428,7 @@ namespace SixLabors.ImageSharp.Quantizers
- moment[GetPaletteIndex(cube.R0, cube.G0, position, cube.A0)];
// Alpha
case 3:
case 0:
return moment[GetPaletteIndex(cube.R1, cube.G1, cube.B1, position)]
- moment[GetPaletteIndex(cube.R1, cube.G1, cube.B0, position)]
- moment[GetPaletteIndex(cube.R1, cube.G0, cube.B1, position)]
@ -562,12 +554,12 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
/// <param name="cube">The cube.</param>
/// <returns>The <see cref="float"/>.</returns>
private float Variance(Box cube)
private float Variance(ref Box cube)
{
float dr = Volume(cube, this.vmr);
float dg = Volume(cube, this.vmg);
float db = Volume(cube, this.vmb);
float da = Volume(cube, this.vma);
float dr = Volume(ref cube, this.vmr);
float dg = Volume(ref cube, this.vmg);
float db = Volume(ref cube, this.vmb);
float da = Volume(ref cube, this.vma);
float xx =
this.m2[GetPaletteIndex(cube.R1, cube.G1, cube.B1, cube.A1)]
@ -587,7 +579,8 @@ namespace SixLabors.ImageSharp.Quantizers
- this.m2[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A1)]
+ this.m2[GetPaletteIndex(cube.R0, cube.G0, cube.B0, cube.A0)];
return xx - (((dr * dr) + (dg * dg) + (db * db) + (da * da)) / Volume(cube, this.vwt));
var vector = new Vector4(dr, dg, db, da);
return xx - (Vector4.Dot(vector, vector) / Volume(ref cube, this.vwt));
}
/// <summary>
@ -608,38 +601,33 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="wholeA">The whole alpha.</param>
/// <param name="wholeW">The whole weight.</param>
/// <returns>The <see cref="float"/>.</returns>
private float Maximize(Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW)
private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW)
{
long baseR = Bottom(cube, direction, this.vmr);
long baseG = Bottom(cube, direction, this.vmg);
long baseB = Bottom(cube, direction, this.vmb);
long baseA = Bottom(cube, direction, this.vma);
long baseW = Bottom(cube, direction, this.vwt);
long baseR = Bottom(ref cube, direction, this.vmr);
long baseG = Bottom(ref cube, direction, this.vmg);
long baseB = Bottom(ref cube, direction, this.vmb);
long baseA = Bottom(ref cube, direction, this.vma);
long baseW = Bottom(ref cube, direction, this.vwt);
float max = 0F;
cut = -1;
for (int i = first; i < last; i++)
{
float halfR = baseR + Top(cube, direction, i, this.vmr);
float halfG = baseG + Top(cube, direction, i, this.vmg);
float halfB = baseB + Top(cube, direction, i, this.vmb);
float halfA = baseA + Top(cube, direction, i, this.vma);
float halfW = baseW + Top(cube, direction, i, this.vwt);
float temp;
float halfR = baseR + Top(ref cube, direction, i, this.vmr);
float halfG = baseG + Top(ref cube, direction, i, this.vmg);
float halfB = baseB + Top(ref cube, direction, i, this.vmb);
float halfA = baseA + Top(ref cube, direction, i, this.vma);
float halfW = baseW + Top(ref cube, direction, i, this.vwt);
if (MathF.Abs(halfW) < Constants.Epsilon)
{
continue;
}
temp = ((halfR * halfR) + (halfG * halfG) + (halfB * halfB) + (halfA * halfA)) / halfW;
var vector = new Vector4(halfR, halfG, halfB, halfA);
float temp = Vector4.Dot(vector, vector) / halfW;
halfR = wholeR - halfR;
halfG = wholeG - halfG;
halfB = wholeB - halfB;
halfA = wholeA - halfA;
halfW = wholeW - halfW;
if (MathF.Abs(halfW) < Constants.Epsilon)
@ -647,7 +635,14 @@ namespace SixLabors.ImageSharp.Quantizers
continue;
}
temp += ((halfR * halfR) + (halfG * halfG) + (halfB * halfB) + (halfA * halfA)) / halfW;
halfR = wholeR - halfR;
halfG = wholeG - halfG;
halfB = wholeB - halfB;
halfA = wholeA - halfA;
vector = new Vector4(halfR, halfG, halfB, halfA);
temp += Vector4.Dot(vector, vector) / halfW;
if (temp > max)
{
@ -665,24 +660,24 @@ namespace SixLabors.ImageSharp.Quantizers
/// <param name="set1">The first set.</param>
/// <param name="set2">The second set.</param>
/// <returns>Returns a value indicating whether the box has been split.</returns>
private bool Cut(Box set1, Box set2)
private bool Cut(ref Box set1, ref Box set2)
{
float wholeR = Volume(set1, this.vmr);
float wholeG = Volume(set1, this.vmg);
float wholeB = Volume(set1, this.vmb);
float wholeA = Volume(set1, this.vma);
float wholeW = Volume(set1, this.vwt);
float wholeR = Volume(ref set1, this.vmr);
float wholeG = Volume(ref set1, this.vmg);
float wholeB = Volume(ref set1, this.vmb);
float wholeA = Volume(ref set1, this.vma);
float wholeW = Volume(ref set1, this.vwt);
float maxr = this.Maximize(set1, 0, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(set1, 1, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxb = this.Maximize(set1, 2, set1.B0 + 1, set1.B1, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxa = this.Maximize(set1, 3, set1.A0 + 1, set1.A1, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxr = this.Maximize(ref set1, 3, set1.R0 + 1, set1.R1, out int cutr, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxg = this.Maximize(ref set1, 2, set1.G0 + 1, set1.G1, out int cutg, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxb = this.Maximize(ref set1, 1, set1.B0 + 1, set1.B1, out int cutb, wholeR, wholeG, wholeB, wholeA, wholeW);
float maxa = this.Maximize(ref set1, 0, set1.A0 + 1, set1.A1, out int cuta, wholeR, wholeG, wholeB, wholeA, wholeW);
int dir;
if ((maxr >= maxg) && (maxr >= maxb) && (maxr >= maxa))
{
dir = 0;
dir = 3;
if (cutr < 0)
{
@ -691,15 +686,15 @@ namespace SixLabors.ImageSharp.Quantizers
}
else if ((maxg >= maxr) && (maxg >= maxb) && (maxg >= maxa))
{
dir = 1;
dir = 2;
}
else if ((maxb >= maxr) && (maxb >= maxg) && (maxb >= maxa))
{
dir = 2;
dir = 1;
}
else
{
dir = 3;
dir = 0;
}
set2.R1 = set1.R1;
@ -710,7 +705,7 @@ namespace SixLabors.ImageSharp.Quantizers
switch (dir)
{
// Red
case 0:
case 3:
set2.R0 = set1.R1 = cutr;
set2.G0 = set1.G0;
set2.B0 = set1.B0;
@ -718,7 +713,7 @@ namespace SixLabors.ImageSharp.Quantizers
break;
// Green
case 1:
case 2:
set2.G0 = set1.G1 = cutg;
set2.R0 = set1.R0;
set2.B0 = set1.B0;
@ -726,7 +721,7 @@ namespace SixLabors.ImageSharp.Quantizers
break;
// Blue
case 2:
case 1:
set2.B0 = set1.B1 = cutb;
set2.R0 = set1.R0;
set2.G0 = set1.G0;
@ -734,7 +729,7 @@ namespace SixLabors.ImageSharp.Quantizers
break;
// Alpha
case 3:
case 0:
set2.A0 = set1.A1 = cuta;
set2.R0 = set1.R0;
set2.G0 = set1.G0;
@ -753,7 +748,7 @@ namespace SixLabors.ImageSharp.Quantizers
/// </summary>
/// <param name="cube">The cube.</param>
/// <param name="label">A label.</param>
private void Mark(Box cube, byte label)
private void Mark(ref Box cube, byte label)
{
for (int r = cube.R0 + 1; r <= cube.R1; r++)
{
@ -778,23 +773,21 @@ namespace SixLabors.ImageSharp.Quantizers
this.colorCube = new Box[this.colors];
float[] vv = new float[this.colors];
for (int i = 0; i < this.colors; i++)
{
this.colorCube[i] = new Box();
}
this.colorCube[0].R0 = this.colorCube[0].G0 = this.colorCube[0].B0 = this.colorCube[0].A0 = 0;
this.colorCube[0].R1 = this.colorCube[0].G1 = this.colorCube[0].B1 = IndexCount - 1;
this.colorCube[0].A1 = IndexAlphaCount - 1;
ref var cube = ref this.colorCube[0];
cube.R0 = cube.G0 = cube.B0 = cube.A0 = 0;
cube.R1 = cube.G1 = cube.B1 = IndexCount - 1;
cube.A1 = IndexAlphaCount - 1;
int next = 0;
for (int i = 1; i < this.colors; i++)
{
if (this.Cut(this.colorCube[next], this.colorCube[i]))
ref var nextCube = ref this.colorCube[next];
ref var currentCube = ref this.colorCube[i];
if (this.Cut(ref nextCube, ref currentCube))
{
vv[next] = this.colorCube[next].Volume > 1 ? this.Variance(this.colorCube[next]) : 0F;
vv[i] = this.colorCube[i].Volume > 1 ? this.Variance(this.colorCube[i]) : 0F;
vv[next] = nextCube.Volume > 1 ? this.Variance(ref nextCube) : 0F;
vv[i] = currentCube.Volume > 1 ? this.Variance(ref currentCube) : 0F;
}
else
{
@ -814,7 +807,7 @@ namespace SixLabors.ImageSharp.Quantizers
}
}
if (temp <= 0.0)
if (temp <= 0F)
{
this.colors = i + 1;
break;
@ -840,12 +833,13 @@ namespace SixLabors.ImageSharp.Quantizers
}
// Expected order r->g->b->a
pixel.ToXyzwBytes(this.rgbaBuffer, 0);
var rgba = default(Rgba32);
pixel.ToRgba32(ref rgba);
int r = this.rgbaBuffer[0] >> (8 - IndexBits);
int g = this.rgbaBuffer[1] >> (8 - IndexBits);
int b = this.rgbaBuffer[2] >> (8 - IndexBits);
int a = this.rgbaBuffer[3] >> (8 - IndexAlphaBits);
int r = rgba.R >> (8 - IndexBits);
int g = rgba.G >> (8 - IndexBits);
int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits);
return this.tag[GetPaletteIndex(r + 1, g + 1, b + 1, a + 1)];
}

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

@ -35,11 +35,16 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
{
TPixel[] s = this.source.Array;
byte[] d = this.destination.Array;
var rgb = default(Rgb24);
for (int i = 0; i < this.Count; i++)
{
TPixel c = s[i];
c.ToXyzBytes(d, i * 4);
int i3 = i * 3;
c.ToRgb24(ref rgb);
d[i3] = rgb.R;
d[i3 + 1] = rgb.G;
d[i3 + 2] = rgb.B;
}
}

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

@ -40,11 +40,17 @@ namespace SixLabors.ImageSharp.Benchmarks.Color.Bulk
{
TPixel[] s = this.source.Array;
byte[] d = this.destination.Array;
var rgba = default(Rgba32);
for (int i = 0; i < this.Count; i++)
{
TPixel c = s[i];
c.ToXyzwBytes(d, i * 4);
int i4 = i * 4;
c.ToRgba32(ref rgba);
d[i4] = rgba.R;
d[i4 + 1] = rgba.G;
d[i4 + 2] = rgba.B;
d[i4 + 3] = rgba.A;
}
}

2
tests/ImageSharp.Benchmarks/General/Block8x8F_Round.cs

@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General
for (int i = 0; i < Block8x8F.Size; i++)
{
ref float v = ref Unsafe.Add(ref b, i);
v = MathF.Round(v);
v = (float)Math.Round(v);
}
}

20
tests/ImageSharp.Benchmarks/Image/DecodePng.cs

@ -10,29 +10,39 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Tests;
using CoreImage = ImageSharp.Image;
using CoreSize = SixLabors.Primitives.Size;
[Config(typeof(Config.ShortClr))]
public class DecodePng : BenchmarkBase
{
private byte[] pngBytes;
private string TestImageFullPath => Path.Combine(
TestEnvironment.InputImagesDirectoryFullPath,
this.TestImage);
[Params(TestImages.Png.Splash)]
public string TestImage { get; set; }
[GlobalSetup]
public void ReadImages()
{
if (this.pngBytes == null)
{
this.pngBytes = File.ReadAllBytes("../ImageSharp.Tests/TestImages/Formats/Png/splash.png");
this.pngBytes = File.ReadAllBytes(this.TestImageFullPath);
}
}
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public Size PngSystemDrawing()
{
using (MemoryStream memoryStream = new MemoryStream(this.pngBytes))
using (var memoryStream = new MemoryStream(this.pngBytes))
{
using (Image image = Image.FromStream(memoryStream))
using (var image = Image.FromStream(memoryStream))
{
return image.Size;
}
@ -42,9 +52,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Image
[Benchmark(Description = "ImageSharp Png")]
public CoreSize PngCore()
{
using (MemoryStream memoryStream = new MemoryStream(this.pngBytes))
using (var memoryStream = new MemoryStream(this.pngBytes))
{
using (Image<Rgba32> image = CoreImage.Load<Rgba32>(memoryStream))
using (var image = CoreImage.Load<Rgba32>(memoryStream))
{
return new CoreSize(image.Width, image.Height);
}

6
tests/ImageSharp.Benchmarks/Samplers/Glow.cs

@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.Benchmarks
int endX = sourceRectangle.Right;
TPixel glowColor = this.GlowColor;
Vector2 centre = Rectangle.Center(sourceRectangle);
float maxDistance = this.Radius > 0 ? MathF.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
float maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
// Align start/end positions.
int minX = Math.Max(0, startX);
@ -136,13 +136,13 @@ namespace SixLabors.ImageSharp.Benchmarks
amount = amount.Clamp(0, 1);
// Santize on zero alpha
if (MathF.Abs(backdrop.W) < Constants.Epsilon)
if (Math.Abs(backdrop.W) < Constants.Epsilon)
{
source.W *= amount;
return source;
}
if (MathF.Abs(source.W) < Constants.Epsilon)
if (Math.Abs(source.W) < Constants.Epsilon)
{
return backdrop;
}

6
tests/ImageSharp.Tests/Common/SimdUtilsTests.cs

@ -22,9 +22,9 @@ namespace SixLabors.ImageSharp.Tests.Common
this.Output = output;
}
private static int R(float f) => (int)MathF.Round(f, MidpointRounding.AwayFromZero);
private static int R(float f) => (int)Math.Round(f, MidpointRounding.AwayFromZero);
private static int Re(float f) => (int)MathF.Round(f, MidpointRounding.ToEven);
private static int Re(float f) => (int)Math.Round(f, MidpointRounding.ToEven);
// TODO: Move this to a proper test class!
[Theory]
@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.Tests.Common
Assert.Equal(expected, dest);
}
private static float Clamp255(float x) => MathF.Min(255f, MathF.Max(0f, x));
private static float Clamp255(float x) => Math.Min(255f, Math.Max(0f, x));
[Theory]
[InlineData(1, 0)]

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

@ -81,13 +81,13 @@ namespace SixLabors.ImageSharp.Tests.Drawing
using (PixelAccessor<Rgba32> sourcePixels = image.Lock())
{
Assert.Equal(Rgba32.HotPink, sourcePixels[11, 11]);
Assert.True(Rgba32.HotPink == sourcePixels[11, 11], "[11, 11] wrong");
Assert.Equal(Rgba32.HotPink, sourcePixels[199, 150]);
Assert.True(Rgba32.HotPink == sourcePixels[199, 149], "[199, 149] wrong");
Assert.Equal(Rgba32.HotPink, sourcePixels[50, 50]);
Assert.True(Rgba32.HotPink == sourcePixels[50, 50], "[50, 50] wrong");
Assert.Equal(Rgba32.Blue, sourcePixels[2, 2]);
Assert.True(Rgba32.Blue == sourcePixels[2, 2], "[2, 2] wrong");
}
}
}

43
tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs

@ -10,12 +10,16 @@ using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests
{
using SixLabors.ImageSharp.Advanced;
public class GifDecoderTests
{
private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32 | Tests.PixelTypes.RgbaVector | Tests.PixelTypes.Argb32;
public static readonly string[] TestFiles = { TestImages.Gif.Giphy, TestImages.Gif.Rings, TestImages.Gif.Trans };
public static readonly string[] BadAppExtFiles = { TestImages.Gif.Issues.BadAppExtLength, TestImages.Gif.Issues.BadAppExtLength_2 };
[Theory]
[WithFileCollection(nameof(TestFiles), PixelTypes)]
public void DecodeAndReSave<TPixel>(TestImageProvider<TPixel> imageProvider)
@ -27,6 +31,7 @@ namespace SixLabors.ImageSharp.Tests
imageProvider.Utility.SaveTestOutputFile(image, "gif");
}
}
[Theory]
[WithFileCollection(nameof(TestFiles), PixelTypes)]
public void DecodeResizeAndSave<TPixel>(TestImageProvider<TPixel> imageProvider)
@ -113,5 +118,43 @@ namespace SixLabors.ImageSharp.Tests
Assert.True(image.Frames.Count > 1);
}
}
[Fact]
public void CanDecodeIntermingledImages()
{
using (var kumin1 = Image.Load(TestFile.Create(TestImages.Gif.Kumin).Bytes))
using (var icon = Image.Load(TestFile.Create(TestImages.Png.Icon).Bytes))
using (var kumin2 = Image.Load(TestFile.Create(TestImages.Gif.Kumin).Bytes))
{
for (int i = 0; i < kumin1.Frames.Count; i++)
{
ImageFrame<Rgba32> first = kumin1.Frames[i];
ImageFrame<Rgba32> second = kumin2.Frames[i];
first.ComparePixelBufferTo(second.GetPixelSpan());
}
}
}
[Theory]
[WithFileCollection(nameof(BadAppExtFiles), PixelTypes.Rgba32)]
public void DecodeBadApplicationExtensionLength<TPixel>(TestImageProvider<TPixel> imageProvider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = imageProvider.GetImage())
{
imageProvider.Utility.SaveTestOutputFile(image, "bmp");
}
}
[Theory]
[WithFile(TestImages.Gif.Issues.BadDescriptorWidth, PixelTypes.Rgba32)]
public void DecodeBadDescriptorDimensionsLength<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
provider.Utility.SaveTestOutputFile(image, "bmp");
}
}
}
}

2
tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs

@ -335,7 +335,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
for (int i = 0; i < 64; i++)
{
float expected = MathF.Round(s[i]);
float expected = (float)Math.Round(s[i]);
float actual = d[i];
Assert.Equal(expected, actual);

6
tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs

@ -236,11 +236,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
float cr = values.Component2[i] - 128F;
float k = values.Component3[i] / 255F;
v.X = (255F - MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k;
v.Y = (255F - MathF.Round(
v.X = (255F - (float)Math.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero)) * k;
v.Y = (255F - (float)Math.Round(
y - (0.344136F * cb) - (0.714136F * cr),
MidpointRounding.AwayFromZero)) * k;
v.Z = (255F - MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k;
v.Z = (255F - (float)Math.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero)) * k;
v.W = 1F;
v *= scale;

3
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -42,6 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Baseline.Jpeg444,
TestImages.Jpeg.Baseline.Bad.BadEOF,
TestImages.Jpeg.Baseline.Bad.ExifUndefType,
TestImages.Jpeg.Issues.MultiHuffmanBaseline394,
};
public static string[] ProgressiveTestJpegs =
@ -50,6 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
TestImages.Jpeg.Progressive.Festzug, TestImages.Jpeg.Progressive.Bad.BadEOF,
TestImages.Jpeg.Issues.BadCoeffsProgressive178,
TestImages.Jpeg.Issues.MissingFF00ProgressiveGirl159,
TestImages.Jpeg.Issues.BadZigZagProgressive385
};
private static readonly Dictionary<string, float> CustomToleranceValues = new Dictionary<string, float>
@ -67,6 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
[TestImages.Jpeg.Progressive.Festzug] = 0.02f / 100,
[TestImages.Jpeg.Progressive.Fb] = 0.16f / 100,
[TestImages.Jpeg.Progressive.Progress] = 0.31f / 100,
[TestImages.Jpeg.Issues.BadZigZagProgressive385] = 0.23f / 100,
};
public const PixelTypes CommonNonDefaultPixelTypes = PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector;

123
tests/ImageSharp.Tests/Helpers/MathFTests.cs

@ -1,123 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Helpers
{
public class MathFTests
{
[Fact]
public void MathF_PI_Is_Equal()
{
Assert.Equal(MathF.PI, (float)Math.PI);
}
[Fact]
public void MathF_Ceililng_Is_Equal()
{
Assert.Equal(MathF.Ceiling(0.3333F), (float)Math.Ceiling(0.3333F));
}
[Fact]
public void MathF_Cos_Is_Equal()
{
Assert.Equal(MathF.Cos(0.3333F), (float)Math.Cos(0.3333F));
}
[Fact]
public void MathF_Abs_Is_Equal()
{
Assert.Equal(MathF.Abs(-0.3333F), (float)Math.Abs(-0.3333F));
}
[Fact]
public void MathF_Atan2_Is_Equal()
{
Assert.Equal(MathF.Atan2(1.2345F, 1.2345F), (float)Math.Atan2(1.2345F, 1.2345F));
}
[Fact]
public void MathF_Exp_Is_Equal()
{
Assert.Equal(MathF.Exp(1.2345F), (float)Math.Exp(1.2345F));
}
[Fact]
public void MathF_Floor_Is_Equal()
{
Assert.Equal(MathF.Floor(1.2345F), (float)Math.Floor(1.2345F));
}
[Fact]
public void MathF_Min_Is_Equal()
{
Assert.Equal(MathF.Min(1.2345F, 5.4321F), (float)Math.Min(1.2345F, 5.4321F));
}
[Fact]
public void MathF_Max_Is_Equal()
{
Assert.Equal(MathF.Max(1.2345F, 5.4321F), (float)Math.Max(1.2345F, 5.4321F));
}
[Fact]
public void MathF_Pow_Is_Equal()
{
Assert.Equal(MathF.Pow(1.2345F, 5.4321F), (float)Math.Pow(1.2345F, 5.4321F));
}
[Fact]
public void MathF_Round_Is_Equal()
{
Assert.Equal(MathF.Round(1.2345F), (float)Math.Round(1.2345F));
}
[Fact]
public void MathF_Round_With_Midpoint_Is_Equal()
{
Assert.Equal(MathF.Round(1.2345F, MidpointRounding.AwayFromZero), (float)Math.Round(1.2345F, MidpointRounding.AwayFromZero));
}
[Fact]
public void MathF_Sin_Is_Equal()
{
Assert.Equal(MathF.Sin(1.2345F), (float)Math.Sin(1.2345F));
}
[Fact]
public void MathF_SinC_Is_Equal()
{
float f = 1.2345F;
float expected = 1F;
if (Math.Abs(f) > Constants.Epsilon)
{
f *= (float)Math.PI;
float sinC = (float)Math.Sin(f) / f;
expected = Math.Abs(sinC) < Constants.Epsilon ? 0F : sinC;
}
Assert.Equal(MathF.SinC(1.2345F), expected);
}
[Fact]
public void MathF_Sqrt_Is_Equal()
{
Assert.Equal(MathF.Sqrt(2F), (float)Math.Sqrt(2F));
}
[Fact]
public void Convert_Degree_To_Radian()
{
Assert.Equal((float)(Math.PI / 2D), MathF.DegreeToRadian(90F), new FloatRoundingComparer(6));
}
[Fact]
public void Convert_Radian_To_Degree()
{
Assert.Equal(60F, MathF.RadianToDegree((float)(Math.PI / 3D)), new FloatRoundingComparer(5));
}
}
}

58
tests/ImageSharp.Tests/Issues/Issue412.cs

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Text;
using SixLabors.Primitives;
using SixLabors.ImageSharp.Advanced;
using Xunit;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Tests.Issues
{
public class Issue412
{
[Theory]
[WithBlankImages(40, 30, PixelTypes.Rgba32)]
public void AllPixelsExpectedToBeRedWhenAntialisedDisabled<TPixel>(TestImageProvider<TPixel> provider) where TPixel : struct, IPixel<TPixel>
{
using (var image = provider.GetImage())
{
image.Mutate(
context =>
{
for (var i = 0; i < 40; ++i)
{
context.DrawLines(
NamedColors<TPixel>.Black,
1,
new[]
{
new PointF(i, 0.1066f),
new PointF(i, 10.1066f)
},
new GraphicsOptions(true));
context.DrawLines(
NamedColors<TPixel>.Red,
1,
new[]
{
new PointF(i, 15.1066f),
new PointF(i, 25.1066f)
},
new GraphicsOptions(false));
}
});
image.DebugSave(provider);
for (var y = 15; y < 25; y++)
{
for (var x = 0; x < 40; x++)
{
Assert.True(NamedColors<TPixel>.Red.Equals(image[x, y]), $"expected {NamedColors<TPixel>.Red} but found {image[x, y]} at [{x}, {y}]");
}
}
}
}
}
}

519
tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs

@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
@ -34,29 +33,29 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(26, new Alpha8(0.1F).PackedValue);
// Test ordering
Vector4 vector = new Alpha8(.5F).ToVector4();
var vector = new Alpha8(.5F).ToVector4();
Assert.Equal(0, vector.X);
Assert.Equal(0, vector.Y);
Assert.Equal(0, vector.Z);
Assert.Equal(.5F, vector.W, 2);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Alpha8(.5F).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 0, 0, 0 });
new Alpha8(.5F).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(0, 0, 0));
new Alpha8(.5F).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 0, 0, 0, 128 });
new Alpha8(.5F).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(0, 0, 0, 128));
new Alpha8(.5F).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 0 });
new Alpha8(.5F).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(0, 0, 0));
new Alpha8(.5F).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 0, 128 });
new Alpha8(.5F).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(0, 0, 0, 128));
}
[Fact]
@ -82,26 +81,26 @@ namespace SixLabors.ImageSharp.Tests.Colors
float y = -0.3f;
float z = +0.5f;
float w = -0.7f;
Argb32 argb = new Argb32(x, y, z, w);
var argb = new Argb32(x, y, z, w);
Assert.Equal(0x001a0080u, argb.PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
argb.ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 0x1a, 0, 0x80 });
argb.ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(0x1a, 0, 0x80));
argb.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 0x1a, 0, 0x80, 0 });
argb.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(0x1a, 0, 0x80, 0));
argb.ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0x80, 0, 0x1a });
argb.ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(0x1a, 0, 0x80));
argb.ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0x80, 0, 0x1a, 0 });
argb.ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(0x1a, 0, 0x80, 0));
}
[Fact]
@ -133,22 +132,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(6160, new Bgr565(x, y, z).PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Bgr565(x, y, z).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 25, 0, 132 });
new Bgr565(x, y, z).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(25, 0, 132));
new Bgr565(x, y, z).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 132, 255 });
new Bgr565(x, y, z).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(25, 0, 132, 255));
new Bgr565(x, y, z).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 132, 0, 25 });
new Bgr565(x, y, z).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(25, 0, 132));
new Bgr565(x, y, z).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 132, 0, 25, 255 });
new Bgr565(x, y, z).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(25, 0, 132, 255));
}
[Fact]
@ -183,22 +182,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(520, new Bgra4444(x, y, z, w).PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Bgra4444(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 34, 0, 136 });
new Bgra4444(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(34, 0, 136));
new Bgra4444(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 34, 0, 136, 0 });
new Bgra4444(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(34, 0, 136, 0));
new Bgra4444(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 136, 0, 34 });
new Bgra4444(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(34, 0, 136));
new Bgra4444(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 136, 0, 34, 0 });
new Bgra4444(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(34, 0, 136, 0));
}
[Fact]
@ -229,22 +228,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(3088, new Bgra5551(x, y, z, w).PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Bgra5551(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 24, 0, 131 });
new Bgra5551(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(24, 0, 131));
new Bgra5551(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 24, 0, 131, 0 });
new Bgra5551(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(24, 0, 131, 0));
new Bgra5551(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 131, 0, 24 });
new Bgra5551(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(24, 0, 131));
new Bgra5551(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 131, 0, 24, 0 });
new Bgra5551(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(24, 0, 131, 0));
}
[Fact]
@ -280,27 +279,27 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal((uint)128, new Byte4(x, y, z, w).PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Byte4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 0, 0 });
new Byte4(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(128, 0, 0));
new Byte4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 0, 0, 0 });
new Byte4(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(128, 0, 0, 0));
new Byte4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 128 });
new Byte4(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(128, 0, 0));
new Byte4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 128, 0 });
new Byte4(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(128, 0, 0, 0));
Byte4 r = new Byte4();
var r = new Byte4();
r.PackFromRgba32(new Rgba32(20, 38, 0, 255));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(20, 38, 0, 255));
}
[Fact]
@ -319,22 +318,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
float x = .5F;
Assert.True(Equal(new Vector4(x, 0, 0, 1), new HalfSingle(x).ToVector4()));
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new HalfSingle(x).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 0, 0 });
new HalfSingle(x).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(128, 0, 0));
new HalfSingle(x).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 0, 0, 255 });
new HalfSingle(x).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(128, 0, 0, 255));
new HalfSingle(x).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 128 });
new HalfSingle(x).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(128, 0, 0));
new HalfSingle(x).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 128, 255 });
new HalfSingle(x).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(128, 0, 0, 255));
}
[Fact]
@ -356,22 +355,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
float y = .25F;
Assert.True(Equal(new Vector4(x, y, 0, 1), new HalfVector2(x, y).ToVector4()));
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new HalfVector2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 64, 0 });
new HalfVector2(x, y).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(128, 64, 0));
new HalfVector2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 64, 0, 255 });
new HalfVector2(x, y).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(128, 64, 0, 255));
new HalfVector2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 64, 128 });
new HalfVector2(x, y).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(128, 64, 0));
new HalfVector2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 64, 128, 255 });
new HalfVector2(x, y).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(128, 64, 0, 255));
}
[Fact]
@ -402,22 +401,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
float z = .75F;
float w = 1F;
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new HalfVector4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 64, 128, 191 });
new HalfVector4(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(64, 128, 191));
new HalfVector4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 64, 128, 191, 255 });
new HalfVector4(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(64, 128, 191, 255));
new HalfVector4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 191, 128, 64 });
new HalfVector4(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(64, 128, 191));
new HalfVector4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 191, 128, 64, 255 });
new HalfVector4(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(64, 128, 191, 255));
}
[Fact]
@ -443,26 +442,26 @@ namespace SixLabors.ImageSharp.Tests.Colors
float x = 0.1f;
float y = -0.3f;
Assert.Equal(0xda0d, new NormalizedByte2(x, y).PackedValue);
NormalizedByte2 n = new NormalizedByte2();
var n = new NormalizedByte2();
n.PackFromRgba32(new Rgba32(141, 90, 0, 0));
Assert.Equal(0xda0d, n.PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new NormalizedByte2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 0 });
new NormalizedByte2(x, y).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(141, 90, 0));
new NormalizedByte2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 });
new NormalizedByte2(x, y).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(141, 90, 0, 255));
new NormalizedByte2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 90, 141 });
new NormalizedByte2(x, y).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(141, 90, 0));
new NormalizedByte2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 });
new NormalizedByte2(x, y).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(141, 90, 0, 255));
}
[Fact]
@ -486,38 +485,38 @@ namespace SixLabors.ImageSharp.Tests.Colors
float z = 0.5f;
float w = -0.7f;
Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue);
NormalizedByte4 n = new NormalizedByte4();
var n = new NormalizedByte4();
n.PackFromRgba32(new Rgba32(141, 90, 192, 39));
Assert.Equal(0xA740DA0D, n.PackedValue);
Assert.Equal((uint)958796544, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new NormalizedByte4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 192 });
new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(141, 90, 192));
new NormalizedByte4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 });
new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(141, 90, 192, 39));
new NormalizedByte4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 192, 90, 141 });
new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(141, 90, 192));
new NormalizedByte4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 });
new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(141, 90, 192, 39));
// http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8
NormalizedByte4 r = new NormalizedByte4();
var r = new NormalizedByte4();
r.PackFromRgba32(new Rgba32(9, 115, 202, 127));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(9, 115, 202, 127));
r.PackedValue = 0xff4af389;
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(9, 115, 202, 127));
}
[Fact]
@ -544,30 +543,30 @@ namespace SixLabors.ImageSharp.Tests.Colors
y = -0.3f;
Assert.Equal(3650751693, new NormalizedShort2(x, y).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
NormalizedShort2 n = new NormalizedShort2();
var n = new NormalizedShort2();
n.PackFromRgba32(new Rgba32(141, 90, 0, 0));
n.ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 0 });
n.ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(141, 90, 0));
// TODO: I don't think this can ever pass since the bytes are already truncated.
// Assert.Equal(3650751693, n.PackedValue);
new NormalizedShort2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 0 });
new NormalizedShort2(x, y).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(141, 90, 0));
new NormalizedShort2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 });
new NormalizedShort2(x, y).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(141, 90, 0, 255));
new NormalizedShort2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 90, 141 });
new NormalizedShort2(x, y).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(141, 90, 0));
new NormalizedShort2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 });
new NormalizedShort2(x, y).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(141, 90, 0, 255));
}
[Fact]
@ -593,27 +592,27 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue);
Assert.Equal((ulong)4150390751449251866, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new NormalizedShort4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 192 });
new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(141, 90, 192));
new NormalizedShort4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 });
new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(141, 90, 192, 39));
new NormalizedShort4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 192, 90, 141 });
new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(141, 90, 192));
new NormalizedShort4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 });
new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(141, 90, 192, 39));
NormalizedShort4 r = new NormalizedShort4();
var r = new NormalizedShort4();
r.PackFromRgba32(new Rgba32(9, 115, 202, 127));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(9, 115, 202, 127));
}
[Fact]
@ -640,22 +639,22 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal((uint)6554, new Rg32(x, y).PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Rg32(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 25, 0, 0 });
new Rg32(x, y).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(25, 0, 0));
new Rg32(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 0, 255 });
new Rg32(x, y).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(25, 0, 0, 255));
new Rg32(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 25 });
new Rg32(x, y).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(25, 0, 0));
new Rg32(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 25, 255 });
new Rg32(x, y).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(25, 0, 0, 255));
}
[Fact]
@ -685,28 +684,28 @@ namespace SixLabors.ImageSharp.Tests.Colors
w = -0.7f;
Assert.Equal((uint)536871014, new Rgba1010102(x, y, z, w).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Rgba1010102(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 25, 0, 128 });
new Rgba1010102(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(25, 0, 128));
new Rgba1010102(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 });
new Rgba1010102(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(25, 0, 128, 0));
new Rgba1010102(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 128, 0, 25 });
new Rgba1010102(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(25, 0, 128));
new Rgba1010102(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 128, 0, 25, 0 });
new Rgba1010102(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(25, 0, 128, 0));
// Alpha component accuracy will be awful.
Rgba1010102 r = new Rgba1010102();
var r = new Rgba1010102();
r.PackFromRgba32(new Rgba32(25, 0, 128, 0));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(25, 0, 128, 0));
}
[Fact]
@ -732,26 +731,26 @@ namespace SixLabors.ImageSharp.Tests.Colors
float y = -0.3f;
float z = +0.5f;
float w = -0.7f;
Rgba32 rgba32 = new Rgba32(x, y, z, w);
var rgba32 = new Rgba32(x, y, z, w);
Assert.Equal(0x80001Au, rgba32.PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
rgba32.ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 0x1a, 0, 0x80 });
rgba32.ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(0x1a, 0, 0x80));
rgba32.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 0x1a, 0, 0x80, 0 });
rgba32.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(0x1a, 0, 0x80, 0));
rgba32.ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0x80, 0, 0x1a });
rgba32.ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(0x1a, 0, 0x80));
rgba32.ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0x80, 0, 0x1a, 0 });
rgba32.ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(0x1a, 0, 0x80, 0));
}
[Fact]
@ -779,27 +778,27 @@ namespace SixLabors.ImageSharp.Tests.Colors
float w = 0.45f;
Assert.Equal((ulong)0x73334CCC2666147B, new Rgba64(x, y, z, w).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Rgba64(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 20, 38, 76 });
new Rgba64(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(20, 38, 76));
new Rgba64(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 });
new Rgba64(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(20, 38, 76, 115));
new Rgba64(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 76, 38, 20 });
new Rgba64(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(20, 38, 76));
new Rgba64(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 76, 38, 20, 115 });
new Rgba64(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(20, 38, 76, 115));
Rgba64 r = new Rgba64();
var r = new Rgba64();
r.PackFromRgba32(new Rgba32(20, 38, 76, 115));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(20, 38, 76, 115));
}
[Fact]
@ -834,27 +833,27 @@ namespace SixLabors.ImageSharp.Tests.Colors
y = -5.3f;
Assert.Equal(4294639744, new Short2(x, y).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Short2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 127, 0 });
new Short2(x, y).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(128, 127, 0));
new Short2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 127, 0, 255 });
new Short2(x, y).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(128, 127, 0, 255));
new Short2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 127, 128 });
new Short2(x, y).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(128, 127, 0));
new Short2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 127, 128, 255 });
new Short2(x, y).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(128, 127, 0, 255));
Short2 r = new Short2();
var r = new Short2();
r.PackFromRgba32(new Rgba32(20, 38, 0, 255));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(20, 38, 0, 255));
}
[Fact]
@ -891,27 +890,27 @@ namespace SixLabors.ImageSharp.Tests.Colors
w = 193;
Assert.Equal((ulong)0x00c173b7316d2d1b, new Short4(x, y, z, w).PackedValue);
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
var bgra = default(Bgra32);
new Short4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 172, 177, 243 });
new Short4(x, y, z, w).ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(172, 177, 243));
new Short4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 172, 177, 243, 128 });
new Short4(x, y, z, w).ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(172, 177, 243, 128));
new Short4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 243, 177, 172 });
new Short4(x, y, z, w).ToBgr24(ref bgr);
Assert.Equal(bgr, new Bgr24(172, 177, 243));
new Short4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 243, 177, 172, 128 });
new Short4(x, y, z, w).ToBgra32(ref bgra);
Assert.Equal(bgra, new Bgra32(172, 177, 243, 128));
Short4 r = new Short4();
var r = new Short4();
r.PackFromRgba32(new Rgba32(20, 38, 0, 255));
r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 });
r.ToRgba32(ref rgba);
Assert.Equal(rgba, new Rgba32(20, 38, 0, 255));
}
// Comparison helpers with small tolerance to allow for floating point rounding during computations.

26
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs

@ -173,11 +173,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
{
TPixel[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 3];
var rgb = default(Rgb24);
for (int i = 0; i < count; i++)
{
int i3 = i * 3;
source[i].ToXyzBytes(expected, i3);
source[i].ToRgb24(ref rgb);
expected[i3] = rgb.R;
expected[i3 + 1] = rgb.G;
expected[i3 + 2] = rgb.B;
}
TestOperation(
@ -214,11 +218,16 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
{
TPixel[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 4];
var rgba = default(Rgba32);
for (int i = 0; i < count; i++)
{
int i4 = i * 4;
source[i].ToXyzwBytes(expected, i4);
source[i].ToRgba32(ref rgba);
expected[i4] = rgba.R;
expected[i4 + 1] = rgba.G;
expected[i4 + 2] = rgba.B;
expected[i4 + 3] = rgba.A;
}
TestOperation(
@ -255,11 +264,15 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
{
TPixel[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 3];
var bgr = default(Bgr24);
for (int i = 0; i < count; i++)
{
int i3 = i * 3;
source[i].ToZyxBytes(expected, i3);
source[i].ToBgr24(ref bgr);
expected[i3] = bgr.B;
expected[i3 + 1] = bgr.G;
expected[i3 + 2] = bgr.R;
}
TestOperation(
@ -296,11 +309,16 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
{
TPixel[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 4];
var bgra = default(Bgra32);
for (int i = 0; i < count; i++)
{
int i4 = i * 4;
source[i].ToZyxwBytes(expected, i4);
source[i].ToBgra32(ref bgra);
expected[i4] = bgra.B;
expected[i4 + 1] = bgra.G;
expected[i4 + 2] = bgra.R;
expected[i4 + 3] = bgra.A;
}
TestOperation(

76
tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs

@ -12,8 +12,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
@ -24,8 +24,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_From_Floats_Produce_Equal_Scaled_Component_OutPut()
{
Rgba32 color = new Rgba32(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
RgbaVector colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
var color = new Rgba32(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
@ -36,8 +36,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut()
{
Rgba32 color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F));
RgbaVector colorVector = new RgbaVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F));
var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F));
var colorVector = new RgbaVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F));
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
@ -48,8 +48,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut()
{
Rgba32 color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F));
RgbaVector colorVector = new RgbaVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F));
var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F));
var colorVector = new RgbaVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F));
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
@ -60,8 +60,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_From_Hex_Produce_Equal_Scaled_Component_OutPut()
{
Rgba32 color = Rgba32.FromHex("183060C0");
RgbaVector colorVector = RgbaVector.FromHex("183060C0");
var color = Rgba32.FromHex("183060C0");
var colorVector = RgbaVector.FromHex("183060C0");
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_To_Vector4_Produce_Equal_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
Assert.Equal(color.ToVector4(), colorVector.ToVector4());
}
@ -81,14 +81,14 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_To_RgbBytes_Produce_Equal_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
byte[] rgb = new byte[3];
byte[] rgbVector = new byte[3];
var rgb = default(Rgb24);
var rgbVector = default(Rgb24);
color.ToXyzBytes(rgb, 0);
colorVector.ToXyzBytes(rgbVector, 0);
color.ToRgb24(ref rgb);
colorVector.ToRgb24(ref rgbVector);
Assert.Equal(rgb, rgbVector);
}
@ -96,14 +96,14 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
byte[] rgba = new byte[4];
byte[] rgbaVector = new byte[4];
var rgba = default(Rgba32);
var rgbaVector = default(Rgba32);
color.ToXyzwBytes(rgba, 0);
colorVector.ToXyzwBytes(rgbaVector, 0);
color.ToRgba32(ref rgba);
colorVector.ToRgba32(ref rgbaVector);
Assert.Equal(rgba, rgbaVector);
}
@ -111,14 +111,14 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_To_BgrBytes_Produce_Equal_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
byte[] bgr = new byte[3];
byte[] bgrVector = new byte[3];
var bgr = default(Bgr24);
var bgrVector = default(Bgr24);
color.ToZyxBytes(bgr, 0);
colorVector.ToZyxBytes(bgrVector, 0);
color.ToBgr24(ref bgr);
colorVector.ToBgr24(ref bgrVector);
Assert.Equal(bgr, bgrVector);
}
@ -126,14 +126,14 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_To_BgraBytes_Produce_Equal_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
byte[] bgra = new byte[4];
byte[] bgraVector = new byte[4];
var bgra = default(Bgra32);
var bgraVector = default(Bgra32);
color.ToZyxwBytes(bgra, 0);
colorVector.ToZyxwBytes(bgraVector, 0);
color.ToBgra32(ref bgra);
colorVector.ToBgra32(ref bgraVector);
Assert.Equal(bgra, bgraVector);
}
@ -141,8 +141,8 @@ namespace SixLabors.ImageSharp.Tests.Colors
[Fact]
public void Color_Types_To_Hex_Produce_Equal_OutPut()
{
Rgba32 color = new Rgba32(24, 48, 96, 192);
RgbaVector colorVector = new RgbaVector(24, 48, 96, 192);
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24, 48, 96, 192);
// 183060C0
Assert.Equal(color.ToHex(), colorVector.ToHex());

10
tests/ImageSharp.Tests/Processing/Processors/ColorMatrix/GrayscaleTest.cs

@ -31,13 +31,13 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.ColorMatrix
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Grayscale(value));
byte[] data = new byte[3];
var rgb = default(Rgb24);
System.Span<TPixel> span = image.Frames.RootFrame.GetPixelSpan();
for (int i = 0; i < span.Length; i++)
{
span[i].ToXyzBytes(data, 0);
Assert.Equal(data[0], data[1]);
Assert.Equal(data[1], data[2]);
span[i].ToRgb24(ref rgb);
Assert.Equal(rgb.R, rgb.B);
Assert.Equal(rgb.B, rgb.G);
}
image.DebugSave(provider, value.ToString());
@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.ColorMatrix
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> source = provider.GetImage())
using (var image = source.Clone())
using (Image<TPixel> image = source.Clone())
{
var bounds = new Rectangle(image.Width / 4, image.Height / 4, image.Width / 2, image.Height / 2);
image.Mutate(x => x.Grayscale(value, bounds));

4
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@ -245,7 +247,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{
var options = new ResizeOptions
{
Size = new Size((int)MathF.Round(image.Width * .75F), (int)MathF.Round(image.Height * .95F)),
Size = new Size((int)Math.Round(image.Width * .75F), (int)Math.Round(image.Height * .95F)),
Mode = ResizeMode.Min
};

13
tests/ImageSharp.Tests/TestImages.cs

@ -31,6 +31,7 @@ namespace SixLabors.ImageSharp.Tests
public const string BikeGrayscale = "Png/BikeGrayscale.png";
public const string Rgb48BppInterlaced = "Png/rgb-48bpp-interlaced.png";
public const string SnakeGame = "Png/SnakeGame.png";
public const string Icon = "Png/icon.png";
// Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html
public const string Filter0 = "Png/filter0.png";
@ -122,6 +123,8 @@ namespace SixLabors.ImageSharp.Tests
public const string CriticalEOF214 = "Jpg/issues/Issue214-CriticalEOF.jpg";
public const string MissingFF00ProgressiveGirl159 = "Jpg/issues/Issue159-MissingFF00-Progressive-Girl.jpg";
public const string BadCoeffsProgressive178 = "Jpg/issues/Issue178-BadCoeffsProgressive-Lemon.jpg";
public const string BadZigZagProgressive385 = "Jpg/issues/Issue385-BadZigZag-Progressive.jpg";
public const string MultiHuffmanBaseline394 = "Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg";
}
public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray();
@ -152,8 +155,16 @@ namespace SixLabors.ImageSharp.Tests
public const string Giphy = "Gif/giphy.gif";
public const string Cheers = "Gif/cheers.gif";
public const string Trans = "Gif/trans.gif";
public const string Kumin = "Gif/kumin.gif";
public static readonly string[] All = { Rings, Giphy, Cheers, Trans };
public class Issues
{
public const string BadAppExtLength = "Gif/issues/issue405_badappextlength252.gif";
public const string BadAppExtLength_2 = "Gif/issues/issue405_badappextlength252-2.gif";
public const string BadDescriptorWidth = "Gif/issues/issue403_baddescriptorwidth.gif";
}
public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin };
}
}
}

1
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -29,7 +29,6 @@ namespace SixLabors.ImageSharp.Tests
/// <param name="provider">The image provider</param>
/// <param name="testOutputDetails">Details to be concatenated to the test output file, describing the parameters of the test.</param>
/// <param name="extension">The extension</param>
/// <param name="grayscale">A boolean indicating whether we should save a smaller in size.</param>
/// <param name="appendPixelTypeToFileName">A boolean indicating whether to append the pixel type to the output file name.</param>
public static Image<TPixel> DebugSave<TPixel>(
this Image<TPixel> image,

16
tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

@ -54,8 +54,8 @@ namespace SixLabors.ImageSharp.Tests
return false;
}
byte[] bytesA = new byte[3];
byte[] bytesB = new byte[3];
var rgb1 = default(Rgb24);
var rgb2 = default(Rgb24);
using (PixelAccessor<TPixel> pixA = a.Lock())
{
@ -77,12 +77,12 @@ namespace SixLabors.ImageSharp.Tests
}
else
{
ca.ToXyzBytes(bytesA, 0);
cb.ToXyzBytes(bytesB, 0);
ca.ToRgb24(ref rgb1);
cb.ToRgb24(ref rgb2);
if (bytesA[0] != bytesB[0] ||
bytesA[1] != bytesB[1] ||
bytesA[2] != bytesB[2])
if (rgb1.R != rgb2.R ||
rgb1.G != rgb2.G ||
rgb1.B != rgb2.B)
{
return false;
}
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Tests
/// <returns></returns>
public static PixelTypes GetPixelType(this Type colorStructClrType) => ClrTypes2PixelTypes[colorStructClrType];
public static IEnumerable<KeyValuePair<PixelTypes, Type>> ExpandAllTypes(this PixelTypes pixelTypes)
{

20
tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Tests
{
Assert.Equal(expected, provider.PixelType);
}
[Theory]
[WithFile(TestImages.Bmp.Car, PixelTypes.All, 88)]
[WithFile(TestImages.Bmp.F, PixelTypes.All, 88)]
@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Tests
}
internal static int GetInvocationCount(string callerName) => invocationCounts[callerName];
private static readonly object Monitor = new object();
public static void DoTestThreadSafe(Action action)
@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.Tests
}
internal static int GetInvocationCount(string callerName) => invocationCounts[callerName];
private static readonly object Monitor = new object();
public static void DoTestThreadSafe(Action action)
@ -234,7 +234,7 @@ namespace SixLabors.ImageSharp.Tests
Image<TPixel> image = provider.GetImage();
provider.Utility.SaveTestOutputFile(image, "png");
}
[Theory]
[WithSolidFilledImages(10, 20, 255, 100, 50, 200, PixelTypes.Rgba32 | PixelTypes.Argb32)]
public void Use_WithSolidFilledImagesAttribute<TPixel>(TestImageProvider<TPixel> provider)
@ -244,7 +244,7 @@ namespace SixLabors.ImageSharp.Tests
Assert.Equal(10, img.Width);
Assert.Equal(20, img.Height);
byte[] colors = new byte[4];
var rgba = default(Rgba32);
using (PixelAccessor<TPixel> pixels = img.Lock())
{
@ -252,12 +252,12 @@ namespace SixLabors.ImageSharp.Tests
{
for (int x = 0; x < pixels.Width; x++)
{
pixels[x, y].ToXyzwBytes(colors, 0);
pixels[x, y].ToRgba32(ref rgba);
Assert.Equal(255, colors[0]);
Assert.Equal(100, colors[1]);
Assert.Equal(50, colors[2]);
Assert.Equal(200, colors[3]);
Assert.Equal(255, rgba.R);
Assert.Equal(100, rgba.G);
Assert.Equal(50, rgba.B);
Assert.Equal(200, rgba.A);
}
}
}

2
tests/Images/External

@ -1 +1 @@
Subproject commit f99c2ea41419cb3b3e80e5beeab611682252df78
Subproject commit dc5479d00b2312f691e6249b9f7765e2316d4a30

BIN
tests/Images/Input/Gif/issues/issue403_baddescriptorwidth.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 KiB

BIN
tests/Images/Input/Gif/issues/issue405_badappextlength252-2.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
tests/Images/Input/Gif/issues/issue405_badappextlength252.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
tests/Images/Input/Gif/kumin.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 KiB

BIN
tests/Images/Input/Jpg/issues/Issue385-BadZigZag-Progressive.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

BIN
tests/Images/Input/Jpg/issues/Issue394-MultiHuffmanBaseline-Speakers.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 KiB

BIN
tests/Images/Input/Png/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Loading…
Cancel
Save