Browse Source

Merge branch 'master' into bp/tiff-fax4

pull/1747/head
Brian Popow 5 years ago
committed by GitHub
parent
commit
743f4e9609
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 141
      .github/workflows/build-and-test.yml
  2. 5
      Directory.Build.props
  3. 2
      shared-infrastructure
  4. 86
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  5. 5
      src/ImageSharp/ImageSharp.csproj
  6. 2
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs
  7. 6
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  8. 6
      tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
  9. 13
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  10. 7
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj
  11. 1
      tests/ImageSharp.Tests/TestImages.cs
  12. 3
      tests/Images/Input/Jpg/issues/Issue1732-WrongColorSpace.jpg

141
.github/workflows/build-and-test.yml

@ -1,19 +1,37 @@
name: Build name: Build
on: on:
push: push:
branches: branches:
- master - master
tags: tags:
- "v*" - "v*"
pull_request: pull_request:
branches: branches:
- master - master
jobs: jobs:
Build: Build:
strategy: strategy:
matrix: matrix:
options: options:
- os: ubuntu-latest
framework: net6.0
sdk: 6.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: macos-latest
framework: net6.0
sdk: 6.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: windows-latest
framework: net6.0
sdk: 6.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: ubuntu-latest - os: ubuntu-latest
framework: net5.0 framework: net5.0
runtime: -x64 runtime: -x64
@ -52,37 +70,38 @@ jobs:
codecov: false codecov: false
runs-on: ${{matrix.options.os}} runs-on: ${{matrix.options.os}}
if: "!contains(github.event.head_commit.message, '[skip ci]')"
steps: steps:
- uses: actions/checkout@v2 - name: Git Config
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.longpaths true
- name: Git Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
# See https://github.com/actions/checkout/issues/165#issuecomment-657673315 # See https://github.com/actions/checkout/issues/165#issuecomment-657673315
- name: Create LFS file list - name: Git Create LFS FileList
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Restore LFS cache - name: Git Setup LFS Cache
uses: actions/cache@v2 uses: actions/cache@v2
id: lfs-cache id: lfs-cache
with: with:
path: .git/lfs path: .git/lfs
key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1 key: ${{ runner.os }}-lfs-${{ hashFiles('.lfs-assets-id') }}-v1
- name: Git LFS Pull - name: Git Pull LFS
run: git lfs pull run: git lfs pull
- name: Install NuGet - name: NuGet Install
uses: NuGet/setup-nuget@v1 uses: NuGet/setup-nuget@v1
- name: Setup Git - name: NuGet Setup Cache
shell: bash
run: |
git config --global core.autocrlf false
git config --global core.longpaths true
git fetch --prune --unshallow
git submodule -q update --init --recursive
- name: Setup NuGet Cache
uses: actions/cache@v2 uses: actions/cache@v2
id: nuget-cache id: nuget-cache
with: with:
@ -90,60 +109,94 @@ jobs:
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }} key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
restore-keys: ${{ runner.os }}-nuget- restore-keys: ${{ runner.os }}-nuget-
- name: Build - name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }}
uses: actions/setup-dotnet@v1
with:
dotnet-version: ${{ matrix.options.sdk }}
include-prerelease: true
- name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh shell: pwsh
run: ./ci-build.ps1 "${{matrix.options.framework}}" run: ./ci-build.ps1 "${{matrix.options.framework}}"
env: env:
SIXLABORS_TESTING: True SIXLABORS_TESTING: True
- name: Test - name: DotNet Build Preview
if: ${{ matrix.options.sdk-preview == true }}
shell: pwsh
run: ./ci-build.ps1 "${{matrix.options.framework}}"
env:
SIXLABORS_TESTING_PREVIEW: True
- name: DotNet Test
if: ${{ matrix.options.sdk-preview != true }}
shell: pwsh shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}" run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env: env:
SIXLABORS_TESTING: True SIXLABORS_TESTING: True
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: DotNet Test Preview
if: ${{ matrix.options.sdk-preview == true }}
shell: pwsh
run: ./ci-test.ps1 "${{matrix.options.os}}" "${{matrix.options.framework}}" "${{matrix.options.runtime}}" "${{matrix.options.codecov}}"
env:
SIXLABORS_TESTING_PREVIEW: True
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output - name: Export Failed Output
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
if: failure() if: failure()
with: with:
name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
path: tests/Images/ActualOutput/ path: tests/Images/ActualOutput/
- name: Update Codecov - name: Codecov Update
uses: codecov/codecov-action@v1 uses: codecov/codecov-action@v1
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors') if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with: with:
flags: unittests flags: unittests
Publish: Publish:
needs: [Build] needs: [Build]
runs-on: windows-latest runs-on: ubuntu-latest
if: (github.event_name == 'push') if: (github.event_name == 'push')
steps: steps:
- uses: actions/checkout@v2 - name: Git Config
- name: Install NuGet
uses: NuGet/setup-nuget@v1
- name: Setup Git
shell: bash shell: bash
run: | run: |
git config --global core.autocrlf false git config --global core.autocrlf false
git config --global core.longpaths true git config --global core.longpaths true
git fetch --prune --unshallow
git submodule -q update --init --recursive
- name: Pack - name: Git Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
- name: NuGet Install
uses: NuGet/setup-nuget@v1
- name: NuGet Setup Cache
uses: actions/cache@v2
id: nuget-cache
with:
path: ~/.nuget
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
restore-keys: ${{ runner.os }}-nuget-
- name: DotNet Pack
shell: pwsh shell: pwsh
run: ./ci-pack.ps1 run: ./ci-pack.ps1
- name: Publish to MyGet - name: MyGet Publish
shell: pwsh shell: pwsh
run: | run: |
nuget.exe push .\artifacts\*.nupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v2/package dotnet nuget push .\artifacts\*.nupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v2/package
nuget.exe push .\artifacts\*.snupkg ${{secrets.MYGET_TOKEN}} -Source https://www.myget.org/F/sixlabors/api/v3/index.json dotnet nuget push .\artifacts\*.snupkg -k ${{secrets.MYGET_TOKEN}} -s https://www.myget.org/F/sixlabors/api/v3/index.json
# TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org # TODO: If github.ref starts with 'refs/tags' then it was tag push and we can optionally push out package to nuget.org

5
Directory.Build.props

@ -18,6 +18,11 @@
<!-- Import the shared global .props file --> <!-- Import the shared global .props file -->
<Import Project="$(MSBuildThisFileDirectory)shared-infrastructure\msbuild\props\SixLabors.Global.props" /> <Import Project="$(MSBuildThisFileDirectory)shared-infrastructure\msbuild\props\SixLabors.Global.props" />
<PropertyGroup Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<!-- Workaround various issues bound to implicit language features. -->
<LangVersion>preview</LangVersion>
</PropertyGroup>
<!-- <!--
Ensure all custom build configurations based upon "Release" are optimized. Ensure all custom build configurations based upon "Release" are optimized.
This is easier than setting each project individually. This is easier than setting each project individually.

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 9b94ebc4be9b7a8d7620c257e6ee485455973332 Subproject commit f48ab829167c42c69242ed0d303683232fbfccd1

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

@ -345,10 +345,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
} }
/// <summary> /// <summary>
/// Returns the correct colorspace based on the image component count /// Returns the correct colorspace based on the image component count and the jpeg frame components.
/// </summary> /// </summary>
/// <returns>The <see cref="JpegColorSpace"/></returns> /// <returns>The <see cref="JpegColorSpace"/></returns>
private JpegColorSpace DeduceJpegColorSpace(byte componentCount) private JpegColorSpace DeduceJpegColorSpace(byte componentCount, JpegComponent[] components)
{ {
if (componentCount == 1) if (componentCount == 1)
{ {
@ -362,6 +362,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return JpegColorSpace.RGB; return JpegColorSpace.RGB;
} }
// If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr.
if (components[2].Id == 66 && components[1].Id == 71 && components[0].Id == 82)
{
return JpegColorSpace.RGB;
}
// Some images are poorly encoded and contain incorrect colorspace transform metadata. // Some images are poorly encoded and contain incorrect colorspace transform metadata.
// We ignore that and always fall back to the default colorspace. // We ignore that and always fall back to the default colorspace.
return JpegColorSpace.YCbCr; return JpegColorSpace.YCbCr;
@ -836,60 +842,60 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// 1 byte: Number of components // 1 byte: Number of components
byte componentCount = this.temp[5]; byte componentCount = this.temp[5];
this.ColorSpace = this.DeduceJpegColorSpace(componentCount);
this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr;
this.Frame = new JpegFrame(frameMarker, precision, frameWidth, frameHeight, componentCount); this.Frame = new JpegFrame(frameMarker, precision, frameWidth, frameHeight, componentCount);
if (!metadataOnly) remaining -= length;
// Validate: remaining part must be equal to components * 3
const int componentBytes = 3;
if (remaining != componentCount * componentBytes)
{ {
remaining -= length; JpegThrowHelper.ThrowBadMarker("SOFn", remaining);
}
// Validate: remaining part must be equal to components * 3 // components*3 bytes: component data
const int componentBytes = 3; stream.Read(this.temp, 0, remaining);
if (remaining != componentCount * componentBytes)
{ // No need to pool this. They max out at 4
JpegThrowHelper.ThrowBadMarker("SOFn", remaining); this.Frame.ComponentIds = new byte[componentCount];
} this.Frame.ComponentOrder = new byte[componentCount];
this.Frame.Components = new JpegComponent[componentCount];
// components*3 bytes: component data int maxH = 0;
stream.Read(this.temp, 0, remaining); int maxV = 0;
int index = 0;
for (int i = 0; i < componentCount; i++)
{
byte hv = this.temp[index + 1];
int h = (hv >> 4) & 15;
int v = hv & 15;
// No need to pool this. They max out at 4 if (maxH < h)
this.Frame.ComponentIds = new byte[componentCount]; {
this.Frame.ComponentOrder = new byte[componentCount]; maxH = h;
this.Frame.Components = new JpegComponent[componentCount]; }
int maxH = 0; if (maxV < v)
int maxV = 0;
int index = 0;
for (int i = 0; i < componentCount; i++)
{ {
byte hv = this.temp[index + 1]; maxV = v;
int h = (hv >> 4) & 15; }
int v = hv & 15;
if (maxH < h) var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
{
maxH = h;
}
if (maxV < v) this.Frame.Components[i] = component;
{ this.Frame.ComponentIds[i] = component.Id;
maxV = v;
}
var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i); index += componentBytes;
}
this.Frame.Components[i] = component; this.ColorSpace = this.DeduceJpegColorSpace(componentCount, this.Frame.Components);
this.Frame.ComponentIds[i] = component.Id;
index += componentBytes; this.Metadata.GetJpegMetadata().ColorType = this.ColorSpace == JpegColorSpace.Grayscale ? JpegColorType.Luminance : JpegColorType.YCbCr;
}
if (!metadataOnly)
{
this.Frame.Init(maxH, maxV); this.Frame.Init(maxH, maxV);
this.scanDecoder.InjectFrameData(this.Frame, this); this.scanDecoder.InjectFrameData(this.Frame, this);
} }
} }

5
src/ImageSharp/ImageSharp.csproj

@ -16,6 +16,11 @@
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472</TargetFrameworks>
</PropertyGroup>
</When>
<When Condition="$(SIXLABORS_TESTING) == true"> <When Condition="$(SIXLABORS_TESTING) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472</TargetFrameworks> <TargetFrameworks>net5.0;netcoreapp3.1;netcoreapp2.1;netstandard2.1;netstandard2.0;netstandard1.3;net472</TargetFrameworks>

2
src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs

@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private void AddPixelsToHistogram(ref Vector4 greyValuesBase, ref int histogramBase, int luminanceLevels, int length) private void AddPixelsToHistogram(ref Vector4 greyValuesBase, ref int histogramBase, int luminanceLevels, int length)
{ {
for (int idx = 0; idx < length; idx++) for (nint idx = 0; idx < length; idx++)
{ {
int luminance = ColorNumerics.GetBT709Luminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels); int luminance = ColorNumerics.GetBT709Luminance(ref Unsafe.Add(ref greyValuesBase, idx), luminanceLevels);
Unsafe.Add(ref histogramBase, luminance)++; Unsafe.Add(ref histogramBase, luminance)++;

6
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -9,12 +9,16 @@
<!--Used to hide test project from dotnet test--> <!--Used to hide test project from dotnet test-->
<IsTestProject>false</IsTestProject> <IsTestProject>false</IsTestProject>
<Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations> <Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations>
<LangVersion>9</LangVersion>
<!-- Uncomment this to run benchmarks depending on Colorful or Pfim (colorspaces and TGA): --> <!-- Uncomment this to run benchmarks depending on Colorful or Pfim (colorspaces and TGA): -->
<!--<SignAssembly>false</SignAssembly>--> <!--<SignAssembly>false</SignAssembly>-->
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;net472</TargetFrameworks>
</PropertyGroup>
</When>
<When Condition="$(Configuration.EndsWith('InnerLoop')) == true"> <When Condition="$(Configuration.EndsWith('InnerLoop')) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks> <TargetFrameworks>netcoreapp3.1</TargetFrameworks>

6
tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj

@ -14,10 +14,14 @@
<EnsureNETCoreAppRuntime>false</EnsureNETCoreAppRuntime> <EnsureNETCoreAppRuntime>false</EnsureNETCoreAppRuntime>
<Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations> <Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained> <ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
<LangVersion>9</LangVersion>
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;net472</TargetFrameworks>
</PropertyGroup>
</When>
<When Condition="$(Configuration.EndsWith('InnerLoop')) == true"> <When Condition="$(Configuration.EndsWith('InnerLoop')) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks> <TargetFrameworks>netcoreapp3.1</TargetFrameworks>

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

@ -174,6 +174,19 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
await Assert.ThrowsAsync<TaskCanceledException>(async () => await Image.IdentifyAsync(config, "someFakeFile", cts.Token)); await Assert.ThrowsAsync<TaskCanceledException>(async () => await Image.IdentifyAsync(config, "someFakeFile", cts.Token));
} }
// https://github.com/SixLabors/ImageSharp/pull/1732
[Theory]
[WithFile(TestImages.Jpeg.Issues.WrongColorSpace, PixelTypes.Rgba32)]
public void Issue1732_DecodesWithRgbColorSpace<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(new JpegDecoder()))
{
image.DebugSave(provider);
image.CompareToOriginal(provider);
}
}
// DEBUG ONLY! // DEBUG ONLY!
// The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm" // The PDF.js output should be saved by "tests\ImageSharp.Tests\Formats\Jpg\pdfjs\jpeg-converter.htm"
// into "\tests\Images\ActualOutput\JpegDecoderTests\" // into "\tests\Images\ActualOutput\JpegDecoderTests\"

7
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -10,6 +10,11 @@
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net6.0;net5.0;netcoreapp3.1;netcoreapp2.1;net472</TargetFrameworks>
</PropertyGroup>
</When>
<When Condition="$(Configuration.EndsWith('InnerLoop')) == true"> <When Condition="$(Configuration.EndsWith('InnerLoop')) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks> <TargetFrameworks>netcoreapp3.1</TargetFrameworks>
@ -21,7 +26,7 @@
</PropertyGroup> </PropertyGroup>
</Otherwise> </Otherwise>
</Choose> </Choose>
<ItemGroup> <ItemGroup>
<InternalsVisibleTo Include="ImageSharp.Tests.ProfilingSandbox" Key="$(SixLaborsPublicKey)" /> <InternalsVisibleTo Include="ImageSharp.Tests.ProfilingSandbox" Key="$(SixLaborsPublicKey)" />
</ItemGroup> </ItemGroup>

1
tests/ImageSharp.Tests/TestImages.cs

@ -237,6 +237,7 @@ namespace SixLabors.ImageSharp.Tests
public const string ExifResize1049 = "Jpg/issues/issue1049-exif-resize.jpg"; public const string ExifResize1049 = "Jpg/issues/issue1049-exif-resize.jpg";
public const string BadSubSampling1076 = "Jpg/issues/issue-1076-invalid-subsampling.jpg"; public const string BadSubSampling1076 = "Jpg/issues/issue-1076-invalid-subsampling.jpg";
public const string IdentifyMultiFrame1211 = "Jpg/issues/issue-1221-identify-multi-frame.jpg"; public const string IdentifyMultiFrame1211 = "Jpg/issues/issue-1221-identify-multi-frame.jpg";
public const string WrongColorSpace = "Jpg/issues/Issue1732-WrongColorSpace.jpg";
public static class Fuzz public static class Fuzz
{ {

3
tests/Images/Input/Jpg/issues/Issue1732-WrongColorSpace.jpg

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3c72235954cdfb9d0cc7f09c537704e617313dc77708b4dca27b47c94c5e67a6
size 2852
Loading…
Cancel
Save