Browse Source

Merge remote-tracking branch 'origin/master' into webp

pull/1552/head
Brian Popow 6 years ago
parent
commit
653b26a3a4
  1. 15
      src/ImageSharp/Advanced/IPixelSource.cs
  2. 2
      src/ImageSharp/ColorSpaces/Cmyk.cs
  3. 4
      src/ImageSharp/ColorSpaces/Companding/LCompanding.cs
  4. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
  5. 3
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  6. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  7. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  8. 4
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  9. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  10. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  11. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  12. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  13. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  14. 4
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  15. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  16. 6
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  17. 5
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
  18. 5
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs
  19. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs
  20. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
  21. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs
  22. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs
  23. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs
  24. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs
  25. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs
  26. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
  27. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs
  28. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
  29. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
  30. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs
  31. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
  32. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
  33. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
  34. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs
  35. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs
  36. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs
  37. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs
  38. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs
  39. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs
  40. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs
  41. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
  42. 0
      src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs
  43. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs
  44. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs
  45. 5
      src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs
  46. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs
  47. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs
  48. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs
  49. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs
  50. 6
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs
  51. 4
      src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs
  52. 6
      src/ImageSharp/ColorSpaces/LinearRgb.cs
  53. 6
      src/ImageSharp/ColorSpaces/Rgb.cs
  54. 6
      src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs
  55. 6
      src/ImageSharp/Common/Extensions/ComparableExtensions.cs
  56. 12
      src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs
  57. 2
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  58. 7
      src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
  59. 2
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  60. 18
      src/ImageSharp/Common/Helpers/Vector4Utilities.cs
  61. 49
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  62. 3
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  63. 24
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  64. 179
      src/ImageSharp/Formats/Gif/LzwEncoder.cs
  65. 32
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
  66. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
  67. 2
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
  68. 4
      src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs
  69. 2
      src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs
  70. 36
      src/ImageSharp/Formats/Tga/ImageExtensions.cs
  71. 1
      src/ImageSharp/Formats/Tga/TgaDecoder.cs
  72. 555
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  73. 20
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  74. 28
      src/ImageSharp/Formats/Tga/TgaImageOrigin.cs
  75. 5
      src/ImageSharp/Formats/Tga/TgaMetadata.cs
  76. 6
      src/ImageSharp/GeometryUtilities.cs
  77. 125
      src/ImageSharp/Image.FromBytes.cs
  78. 99
      src/ImageSharp/Image.FromFile.cs
  79. 68
      src/ImageSharp/Image.FromStream.cs
  80. 12
      src/ImageSharp/ImageExtensions.cs
  81. 28
      src/ImageSharp/IndexedImageFrame{TPixel}.cs
  82. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
  83. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
  84. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
  85. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs
  86. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs
  87. 2
      src/ImageSharp/PixelFormats/PixelImplementations/L16.cs
  88. 2
      src/ImageSharp/PixelFormats/PixelImplementations/L8.cs
  89. 2
      src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
  90. 2
      src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
  91. 2
      src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs
  92. 2
      src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs
  93. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs
  94. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs
  95. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs
  96. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
  97. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
  98. 2
      src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
  99. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs
  100. 4
      src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs

15
src/ImageSharp/Advanced/IPixelSource.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -6,6 +6,17 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Advanced namespace SixLabors.ImageSharp.Advanced
{ {
/// <summary>
/// Encapsulates the basic properties and methods required to manipulate images.
/// </summary>
internal interface IPixelSource
{
/// <summary>
/// Gets the pixel buffer.
/// </summary>
Buffer2D<byte> PixelBuffer { get; }
}
/// <summary> /// <summary>
/// Encapsulates the basic properties and methods required to manipulate images. /// Encapsulates the basic properties and methods required to manipulate images.
/// </summary> /// </summary>
@ -18,4 +29,4 @@ namespace SixLabors.ImageSharp.Advanced
/// </summary> /// </summary>
Buffer2D<TPixel> PixelBuffer { get; } Buffer2D<TPixel> PixelBuffer { get; }
} }
} }

2
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Cmyk(Vector4 vector) public Cmyk(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Min, Max); vector = Vector4Utilities.FastClamp(vector, Min, Max);
this.C = vector.X; this.C = vector.X;
this.M = vector.Y; this.M = vector.Y;
this.Y = vector.Z; this.Y = vector.Z;

4
src/ImageSharp/ColorSpaces/Companding/LCompanding.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -35,4 +35,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Companding
public static float Compress(float channel) public static float Compress(float channel)
=> channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F; => channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F;
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -157,4 +155,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return this.ToRgb(linearOutput); return this.ToRgb(linearOutput);
} }
} }
} }

3
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs

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

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -447,4 +445,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -447,4 +445,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

4
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs

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

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -475,4 +473,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return this.linearRgbToCieXyzConverter = new LinearRgbToCieXyzConverter(workingSpace); return this.linearRgbToCieXyzConverter = new LinearRgbToCieXyzConverter(workingSpace);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -440,4 +438,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

4
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs

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

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -438,4 +436,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
return this.Adapt(rgb); return this.Adapt(rgb);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs

@ -1,12 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <content> /// <content>
@ -407,4 +405,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// <returns>The <see cref="YCbCr"/></returns> /// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color);
} }
} }

5
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs

@ -1,8 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
@ -58,4 +57,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace); this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace);
} }
} }
} }

5
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs

@ -1,8 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
@ -52,4 +51,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
/// </summary> /// </summary>
public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix; public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix;
} }
} }

6
src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs → src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs

@ -1,11 +1,11 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
// ReSharper disable CompareOfFloatsByEqualityOperator // ReSharper disable CompareOfFloatsByEqualityOperator
namespace SixLabors.ImageSharp.ColorSpaces namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Represents the coordinates of CIEXY chromaticity space. /// Represents the coordinates of CIEXY chromaticity space.
@ -76,4 +76,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y);
} }
} }

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>. /// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>. /// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
@ -38,4 +38,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new CieLch(l, c, hDegrees, input.WhitePoint); return new CieLch(l, c, hDegrees, input.WhitePoint);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieXyz"/>. /// Converts from <see cref="CieLab"/> to <see cref="CieXyz"/>.
@ -41,4 +41,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new CieXyz(xyz); return new CieXyz(xyz);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>. /// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
@ -30,4 +30,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new CieLuv(l, u, v, input.WhitePoint); return new CieLuv(l, u, v, input.WhitePoint);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>. /// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
@ -38,4 +38,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new CieLchuv(l, c, hDegrees, input.WhitePoint); return new CieLchuv(l, c, hDegrees, input.WhitePoint);
} }
} }
} }

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs

@ -3,7 +3,7 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>. /// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between CIE XYZ and CIE xyY. /// Color converter between CIE XYZ and CIE xyY.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs

@ -3,7 +3,7 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// The base class for converting between <see cref="HunterLab"/> and <see cref="CieXyz"/> color spaces. /// The base class for converting between <see cref="HunterLab"/> and <see cref="CieXyz"/> color spaces.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs

@ -4,7 +4,7 @@
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="Lms"/> /// Color converter between <see cref="CieXyz"/> and <see cref="Lms"/>

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLab"/>. /// Converts from <see cref="CieXyz"/> to <see cref="CieLab"/>.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLuv"/>. /// Converts from <see cref="CieXyz"/> to <see cref="CieLuv"/>.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="HunterLab"/> /// Color converter between <see cref="CieXyz"/> and <see cref="HunterLab"/>

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs

@ -4,7 +4,7 @@
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="LinearRgb"/> /// Color converter between <see cref="CieXyz"/> and <see cref="LinearRgb"/>

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs

@ -5,7 +5,7 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>. /// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>.

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between HSL and Rgb /// Color converter between HSL and Rgb

4
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs

@ -4,7 +4,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between HSV and Rgb /// Color converter between HSV and Rgb
@ -127,4 +127,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new Hsv(h, s, v); return new Hsv(h, s, v);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="HunterLab"/> and <see cref="CieXyz"/> /// Color converter between <see cref="HunterLab"/> and <see cref="CieXyz"/>
@ -36,4 +36,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new CieXyz(x, y, z); return new CieXyz(x, y, z);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Provides base methods for converting between <see cref="LinearRgb"/> and <see cref="CieXyz"/> color spaces. /// Provides base methods for converting between <see cref="LinearRgb"/> and <see cref="CieXyz"/> color spaces.
@ -74,4 +74,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
}; };
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="LinearRgb"/> and <see cref="CieXyz"/> /// Color converter between <see cref="LinearRgb"/> and <see cref="CieXyz"/>
@ -50,4 +50,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return new CieXyz(vector); return new CieXyz(vector);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>. /// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>.
@ -25,4 +25,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
workingSpace: input.WorkingSpace); workingSpace: input.WorkingSpace);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between Rgb and LinearRgb. /// Color converter between Rgb and LinearRgb.
@ -25,4 +25,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
workingSpace: input.WorkingSpace); workingSpace: input.WorkingSpace);
} }
} }
} }

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs

@ -5,7 +5,7 @@ using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Color converter between <see cref="YCbCr"/> and <see cref="Rgb"/> /// Color converter between <see cref="YCbCr"/> and <see cref="Rgb"/>

0
src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs → src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Numerics; using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Matrices used for transformation from <see cref="CieXyz"/> to <see cref="Lms"/>, defining the cone response domain. /// Matrices used for transformation from <see cref="CieXyz"/> to <see cref="Lms"/>, defining the cone response domain.
@ -131,4 +131,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
M44 = 1F M44 = 1F
}); });
} }
} }

4
src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Represents the chromaticity coordinates of RGB primaries. /// Represents the chromaticity coordinates of RGB primaries.

5
src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs → src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs

@ -1,11 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
@ -99,4 +98,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion
} }
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs

@ -1,11 +1,11 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// The gamma working space. /// The gamma working space.
@ -63,4 +63,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
this.ChromaticityCoordinates, this.ChromaticityCoordinates,
this.Gamma); this.Gamma);
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// L* working space. /// L* working space.
@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => LCompanding.Expand(channel); public override float Expand(float channel) => LCompanding.Expand(channel);
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space.
@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => Rec2020Companding.Expand(channel); public override float Expand(float channel) => Rec2020Companding.Expand(channel);
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Rec. 709 (ITU-R Recommendation BT.709) working space. /// Rec. 709 (ITU-R Recommendation BT.709) working space.
@ -29,4 +29,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => Rec709Companding.Expand(channel); public override float Expand(float channel) => Rec709Companding.Expand(channel);
} }
} }

6
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// Base class for all implementations of <see cref="RgbWorkingSpace"/>. /// Base class for all implementations of <see cref="RgbWorkingSpace"/>.
@ -81,4 +81,4 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation
return HashCode.Combine(this.WhitePoint, this.ChromaticityCoordinates); return HashCode.Combine(this.WhitePoint, this.ChromaticityCoordinates);
} }
} }
} }

4
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation namespace SixLabors.ImageSharp.ColorSpaces.Conversion
{ {
/// <summary> /// <summary>
/// The sRgb working space. /// The sRgb working space.

6
src/ImageSharp/ColorSpaces/LinearRgb.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorSpaces namespace SixLabors.ImageSharp.ColorSpaces
{ {
@ -143,4 +143,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.B.Equals(other.B); && this.B.Equals(other.B);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/Rgb.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.ColorSpaces namespace SixLabors.ImageSharp.ColorSpaces
@ -164,4 +164,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
&& this.B.Equals(other.B); && this.B.Equals(other.B);
} }
} }
} }

6
src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Companding;
using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using SixLabors.ImageSharp.ColorSpaces.Conversion;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.ColorSpaces namespace SixLabors.ImageSharp.ColorSpaces
@ -112,4 +112,4 @@ namespace SixLabors.ImageSharp.ColorSpaces
/// </summary> /// </summary>
public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F)));
} }
} }

6
src/ImageSharp/Common/Extensions/ComparableExtensions.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Restricts a <see cref="byte"/> to be within a specified range. /// Restricts a <see cref="byte"/> to be within a specified range.
/// </summary> /// </summary>
/// <param name="value">The The value to clamp.</param> /// <param name="value">The value to clamp.</param>
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param> /// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param> /// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
/// <returns> /// <returns>
@ -137,4 +137,4 @@ namespace SixLabors.ImageSharp
return value; return value;
} }
} }
} }

12
src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs

@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp
ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column);
vector.W = target.W; vector.W = target.W;
Vector4Utils.UnPremultiply(ref vector); Vector4Utilities.UnPremultiply(ref vector);
target = vector; target = vector;
} }
@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp
out Vector4 vector); out Vector4 vector);
ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column);
Vector4Utils.UnPremultiply(ref vector); Vector4Utilities.UnPremultiply(ref vector);
target = vector; target = vector;
} }
@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp
{ {
int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn);
var currentColor = sourceRowSpan[offsetX].ToVector4(); var currentColor = sourceRowSpan[offsetX].ToVector4();
Vector4Utils.Premultiply(ref currentColor); Vector4Utilities.Premultiply(ref currentColor);
vectorX += matrixX[y, x] * currentColor; vectorX += matrixX[y, x] * currentColor;
vectorY += matrixY[y, x] * currentColor; vectorY += matrixY[y, x] * currentColor;
@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp
ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column);
vector.W = target.W; vector.W = target.W;
Vector4Utils.UnPremultiply(ref vector); Vector4Utilities.UnPremultiply(ref vector);
target = vector; target = vector;
} }
@ -238,7 +238,7 @@ namespace SixLabors.ImageSharp
ref vector); ref vector);
ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column); ref Vector4 target = ref Unsafe.Add(ref targetRowRef, column);
Vector4Utils.UnPremultiply(ref vector); Vector4Utilities.UnPremultiply(ref vector);
target = vector; target = vector;
} }
@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp
{ {
int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn);
var currentColor = sourceRowSpan[offsetX].ToVector4(); var currentColor = sourceRowSpan[offsetX].ToVector4();
Vector4Utils.Premultiply(ref currentColor); Vector4Utilities.Premultiply(ref currentColor);
vector += matrix[y, x] * currentColor; vector += matrix[y, x] * currentColor;
} }
} }

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

@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp
} }
} }
return height; return width;
} }
topLeft.Y = GetMinY(bitmap); topLeft.Y = GetMinY(bitmap);

7
src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -125,10 +125,7 @@ namespace SixLabors.ImageSharp
Vector4 s = Unsafe.Add(ref sBase, i); Vector4 s = Unsafe.Add(ref sBase, i);
s *= maxBytes; s *= maxBytes;
s += half; s += half;
s = Vector4Utilities.FastClamp(s, Vector4.Zero, maxBytes);
// I'm not sure if Vector4.Clamp() is properly implemented with intrinsics.
s = Vector4.Max(Vector4.Zero, s);
s = Vector4.Min(maxBytes, s);
ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); ref ByteVector4 d = ref Unsafe.Add(ref dBase, i);
d.X = (byte)s.X; d.X = (byte)s.X;

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

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector4 PseudoRound(this Vector4 v) internal static Vector4 PseudoRound(this Vector4 v)
{ {
var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1)); var sign = Vector4Utilities.FastClamp(v, new Vector4(-1), new Vector4(1));
return v + (sign * 0.5f); return v + (sign * 0.5f);
} }

18
src/ImageSharp/Common/Helpers/Vector4Utils.cs → src/ImageSharp/Common/Helpers/Vector4Utilities.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -11,8 +11,20 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Utility methods for the <see cref="Vector4"/> struct. /// Utility methods for the <see cref="Vector4"/> struct.
/// </summary> /// </summary>
internal static class Vector4Utils internal static class Vector4Utilities
{ {
/// <summary>
/// Restricts a vector between a minimum and a maximum value.
/// 5x Faster then <see cref="Vector4.Clamp(Vector4, Vector4, Vector4)"/>.
/// </summary>
/// <param name="x">The vector to restrict.</param>
/// <param name="min">The minimum value.</param>
/// <param name="max">The maximum value.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector4 FastClamp(Vector4 x, Vector4 min, Vector4 max)
=> Vector4.Min(Vector4.Max(x, min), max);
/// <summary> /// <summary>
/// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact.
/// </summary> /// </summary>
@ -107,4 +119,4 @@ namespace SixLabors.ImageSharp
} }
} }
} }
} }

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

@ -353,7 +353,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.ReadImageDescriptor(); this.ReadImageDescriptor();
IManagedByteBuffer localColorTable = null; IManagedByteBuffer localColorTable = null;
IManagedByteBuffer indices = null; Buffer2D<byte> indices = null;
try try
{ {
// Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table.
@ -364,11 +364,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.stream.Read(localColorTable.Array, 0, length); this.stream.Read(localColorTable.Array, 0, length);
} }
indices = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(this.imageDescriptor.Width * this.imageDescriptor.Height, AllocationOptions.Clean); indices = this.configuration.MemoryAllocator.Allocate2D<byte>(this.imageDescriptor.Width, this.imageDescriptor.Height, AllocationOptions.Clean);
this.ReadFrameIndices(this.imageDescriptor, indices.GetSpan()); this.ReadFrameIndices(indices);
ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).GetSpan()); ReadOnlySpan<Rgb24> colorTable = MemoryMarshal.Cast<byte, Rgb24>((localColorTable ?? this.globalColorTable).GetSpan());
this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor); this.ReadFrameColors(ref image, ref previousFrame, indices, colorTable, this.imageDescriptor);
// Skip any remaining blocks // Skip any remaining blocks
this.SkipBlock(); this.SkipBlock();
@ -383,16 +383,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Reads the frame indices marking the color to use for each pixel. /// Reads the frame indices marking the color to use for each pixel.
/// </summary> /// </summary>
/// <param name="imageDescriptor">The <see cref="GifImageDescriptor"/>.</param> /// <param name="indices">The 2D pixel buffer to write to.</param>
/// <param name="indices">The pixel array to write to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadFrameIndices(in GifImageDescriptor imageDescriptor, Span<byte> indices) private void ReadFrameIndices(Buffer2D<byte> indices)
{ {
int dataSize = this.stream.ReadByte(); int dataSize = this.stream.ReadByte();
using (var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream)) using var lzwDecoder = new LzwDecoder(this.configuration.MemoryAllocator, this.stream);
{ lzwDecoder.DecodePixels(dataSize, indices);
lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize, indices);
}
} }
/// <summary> /// <summary>
@ -404,10 +401,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="indices">The indexed pixels.</param> /// <param name="indices">The indexed pixels.</param>
/// <param name="colorTable">The color table containing the available colors.</param> /// <param name="colorTable">The color table containing the available colors.</param>
/// <param name="descriptor">The <see cref="GifImageDescriptor"/></param> /// <param name="descriptor">The <see cref="GifImageDescriptor"/></param>
private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame, Span<byte> indices, ReadOnlySpan<Rgb24> colorTable, in GifImageDescriptor descriptor) private void ReadFrameColors<TPixel>(ref Image<TPixel> image, ref ImageFrame<TPixel> previousFrame, Buffer2D<byte> indices, ReadOnlySpan<Rgb24> colorTable, in GifImageDescriptor descriptor)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
ref byte indicesRef = ref MemoryMarshal.GetReference(indices);
int imageWidth = this.logicalScreenDescriptor.Width; int imageWidth = this.logicalScreenDescriptor.Width;
int imageHeight = this.logicalScreenDescriptor.Height; int imageHeight = this.logicalScreenDescriptor.Height;
@ -440,13 +436,20 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.RestoreToBackground(imageFrame); this.RestoreToBackground(imageFrame);
} }
int i = 0;
int interlacePass = 0; // The interlace pass int interlacePass = 0; // The interlace pass
int interlaceIncrement = 8; // The interlacing line increment int interlaceIncrement = 8; // The interlacing line increment
int interlaceY = 0; // The current interlaced line int interlaceY = 0; // The current interlaced line
int descriptorTop = descriptor.Top;
for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) int descriptorBottom = descriptorTop + descriptor.Height;
int descriptorLeft = descriptor.Left;
int descriptorRight = descriptorLeft + descriptor.Width;
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
byte transIndex = this.graphicsControlExtension.TransparencyIndex;
for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++)
{ {
ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.GetRowSpan(y - descriptorTop));
// Check if this image is interlaced. // Check if this image is interlaced.
int writeY; // the target y offset to write to int writeY; // the target y offset to write to
if (descriptor.InterlaceFlag) if (descriptor.InterlaceFlag)
@ -482,35 +485,29 @@ namespace SixLabors.ImageSharp.Formats.Gif
} }
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
if (!transFlag) if (!transFlag)
{ {
// #403 The left + width value can be larger than the image width // #403 The left + width value can be larger than the image width
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++) for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{ {
int index = Unsafe.Add(ref indicesRef, i); int index = Unsafe.Add(ref indicesRowRef, x - descriptorLeft);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
Rgb24 rgb = colorTable[index]; Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb); pixel.FromRgb24(rgb);
i++;
} }
} }
else else
{ {
byte transIndex = this.graphicsControlExtension.TransparencyIndex; for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
{ {
int index = Unsafe.Add(ref indicesRef, i); int index = Unsafe.Add(ref indicesRowRef, x - descriptorLeft);
if (transIndex != index) if (transIndex != index)
{ {
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
Rgb24 rgb = colorTable[index]; Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb); pixel.FromRgb24(rgb);
} }
i++;
} }
} }
} }

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

@ -6,6 +6,7 @@ using System.Buffers;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -471,7 +472,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth); using var encoder = new LzwEncoder(this.memoryAllocator, (byte)this.bitDepth);
encoder.Encode(image.GetPixelBufferSpan(), stream); encoder.Encode(((IPixelSource)image).PixelBuffer, stream);
} }
} }
} }

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

@ -65,15 +65,15 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Decodes and decompresses all pixel indices from the stream. /// Decodes and decompresses all pixel indices from the stream.
/// </summary> /// </summary>
/// <param name="width">The width of the pixel index array.</param>
/// <param name="height">The height of the pixel index array.</param>
/// <param name="dataSize">Size of the data.</param> /// <param name="dataSize">Size of the data.</param>
/// <param name="pixels">The pixel array to decode to.</param> /// <param name="pixels">The pixel array to decode to.</param>
public void DecodePixels(int width, int height, int dataSize, Span<byte> pixels) public void DecodePixels(int dataSize, Buffer2D<byte> pixels)
{ {
Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize)); Guard.MustBeLessThan(dataSize, int.MaxValue, nameof(dataSize));
// The resulting index table length. // The resulting index table length.
int width = pixels.Width;
int height = pixels.Height;
int length = width * height; int length = width * height;
// Calculate the clear code. The value of the clear code is 2 ^ dataSize // Calculate the clear code. The value of the clear code is 2 ^ dataSize
@ -105,17 +105,28 @@ namespace SixLabors.ImageSharp.Formats.Gif
ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan()); ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan());
ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan()); ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan());
ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan()); ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan());
ref byte pixelsRef = ref MemoryMarshal.GetReference(pixels);
for (code = 0; code < clearCode; code++) for (code = 0; code < clearCode; code++)
{ {
Unsafe.Add(ref suffixRef, code) = (byte)code; Unsafe.Add(ref suffixRef, code) = (byte)code;
} }
Span<byte> buffer = stackalloc byte[255]; Span<byte> buffer = stackalloc byte[byte.MaxValue];
int y = 0;
int x = 0;
int rowMax = width;
ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(y));
while (xyz < length) while (xyz < length)
{ {
// Reset row reference.
if (xyz == rowMax)
{
x = 0;
pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(++y));
rowMax = (y * width) + width;
}
if (top == 0) if (top == 0)
{ {
if (bits < codeSize) if (bits < codeSize)
@ -209,7 +220,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
top--; top--;
// Clear missing pixels // Clear missing pixels
Unsafe.Add(ref pixelsRef, xyz++) = (byte)Unsafe.Add(ref pixelStackRef, top); xyz++;
Unsafe.Add(ref pixelsRowRef, x++) = (byte)Unsafe.Add(ref pixelStackRef, top);
} }
} }

179
src/ImageSharp/Formats/Gif/LzwEncoder.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -41,13 +41,33 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
private const int HashSize = 5003; private const int HashSize = 5003;
/// <summary>
/// The amount to shift each code.
/// </summary>
private const int HashShift = 4;
/// <summary> /// <summary>
/// Mask used when shifting pixel values /// Mask used when shifting pixel values
/// </summary> /// </summary>
private static readonly int[] Masks = private static readonly int[] Masks =
{ {
0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0b0,
0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF 0b1,
0b11,
0b111,
0b1111,
0b11111,
0b111111,
0b1111111,
0b11111111,
0b111111111,
0b1111111111,
0b11111111111,
0b111111111111,
0b1111111111111,
0b11111111111111,
0b111111111111111,
0b1111111111111111
}; };
/// <summary> /// <summary>
@ -80,16 +100,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
private readonly byte[] accumulators = new byte[256]; private readonly byte[] accumulators = new byte[256];
/// <summary>
/// For dynamic table sizing
/// </summary>
private readonly int hsize = HashSize;
/// <summary>
/// The current position within the pixelArray.
/// </summary>
private int position;
/// <summary> /// <summary>
/// Number of bits/code /// Number of bits/code
/// </summary> /// </summary>
@ -177,15 +187,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Encodes and compresses the indexed pixels to the stream. /// Encodes and compresses the indexed pixels to the stream.
/// </summary> /// </summary>
/// <param name="indexedPixels">The span of indexed pixels.</param> /// <param name="indexedPixels">The 2D buffer of indexed pixels.</param>
/// <param name="stream">The stream to write to.</param> /// <param name="stream">The stream to write to.</param>
public void Encode(ReadOnlySpan<byte> indexedPixels, Stream stream) public void Encode(Buffer2D<byte> indexedPixels, Stream stream)
{ {
// Write "initial code size" byte // Write "initial code size" byte
stream.WriteByte((byte)this.initialCodeSize); stream.WriteByte((byte)this.initialCodeSize);
this.position = 0;
// Compress and write the pixel data // Compress and write the pixel data
this.Compress(indexedPixels, this.initialCodeSize + 1, stream); this.Compress(indexedPixels, this.initialCodeSize + 1, stream);
@ -199,10 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="bitCount">The number of bits</param> /// <param name="bitCount">The number of bits</param>
/// <returns>See <see cref="int"/></returns> /// <returns>See <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetMaxcode(int bitCount) private static int GetMaxcode(int bitCount) => (1 << bitCount) - 1;
{
return (1 << bitCount) - 1;
}
/// <summary> /// <summary>
/// Add a character to the end of the current packet, and if it is 254 characters, /// Add a character to the end of the current packet, and if it is 254 characters,
@ -239,25 +244,16 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Reset the code table. /// Reset the code table.
/// </summary> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ResetCodeTable() private void ResetCodeTable() => this.hashTable.GetSpan().Fill(-1);
{
this.hashTable.GetSpan().Fill(-1);
}
/// <summary> /// <summary>
/// Compress the packets to the stream. /// Compress the packets to the stream.
/// </summary> /// </summary>
/// <param name="indexedPixels">The span of indexed pixels.</param> /// <param name="indexedPixels">The 2D buffer of indexed pixels.</param>
/// <param name="initialBits">The initial bits.</param> /// <param name="initialBits">The initial bits.</param>
/// <param name="stream">The stream to write to.</param> /// <param name="stream">The stream to write to.</param>
private void Compress(ReadOnlySpan<byte> indexedPixels, int initialBits, Stream stream) private void Compress(Buffer2D<byte> indexedPixels, int initialBits, Stream stream)
{ {
int fcode;
int c;
int ent;
int hsizeReg;
int hshift;
// Set up the globals: globalInitialBits - initial number of bits // Set up the globals: globalInitialBits - initial number of bits
this.globalInitialBits = initialBits; this.globalInitialBits = initialBits;
@ -265,92 +261,82 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.clearFlag = false; this.clearFlag = false;
this.bitCount = this.globalInitialBits; this.bitCount = this.globalInitialBits;
this.maxCode = GetMaxcode(this.bitCount); this.maxCode = GetMaxcode(this.bitCount);
this.clearCode = 1 << (initialBits - 1); this.clearCode = 1 << (initialBits - 1);
this.eofCode = this.clearCode + 1; this.eofCode = this.clearCode + 1;
this.freeEntry = this.clearCode + 2; this.freeEntry = this.clearCode + 2;
this.accumulatorCount = 0; // Clear packet
this.accumulatorCount = 0; // clear packet this.ResetCodeTable(); // Clear hash table
ent = this.NextPixel(indexedPixels);
// TODO: PERF: It looks like hshift could be calculated once statically.
hshift = 0;
for (fcode = this.hsize; fcode < 65536; fcode *= 2)
{
++hshift;
}
hshift = 8 - hshift; // set hash code range bound
hsizeReg = this.hsize;
this.ResetCodeTable(); // clear hash table
this.Output(this.clearCode, stream); this.Output(this.clearCode, stream);
ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.GetSpan()); ref int hashTableRef = ref MemoryMarshal.GetReference(this.hashTable.GetSpan());
ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.GetSpan()); ref int codeTableRef = ref MemoryMarshal.GetReference(this.codeTable.GetSpan());
while (this.position < indexedPixels.Length) int entry = indexedPixels[0, 0];
{
c = this.NextPixel(indexedPixels);
fcode = (c << MaxBits) + ent; for (int y = 0; y < indexedPixels.Height; y++)
int i = (c << hshift) ^ ent /* = 0 */; {
ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.GetRowSpan(y));
int offsetX = y == 0 ? 1 : 0;
if (Unsafe.Add(ref hashTableRef, i) == fcode) for (int x = offsetX; x < indexedPixels.Width; x++)
{ {
ent = Unsafe.Add(ref codeTableRef, i); int code = Unsafe.Add(ref rowSpanRef, x);
continue; int freeCode = (code << MaxBits) + entry;
} int hashIndex = (code << HashShift) ^ entry;
// Non-empty slot if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode)
if (Unsafe.Add(ref hashTableRef, i) >= 0)
{
int disp = 1;
if (i != 0)
{ {
disp = hsizeReg - i; entry = Unsafe.Add(ref codeTableRef, hashIndex);
continue;
} }
do // Non-empty slot
if (Unsafe.Add(ref hashTableRef, hashIndex) >= 0)
{ {
if ((i -= disp) < 0) int disp = 1;
if (hashIndex != 0)
{
disp = HashSize - hashIndex;
}
do
{ {
i += hsizeReg; if ((hashIndex -= disp) < 0)
{
hashIndex += HashSize;
}
if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode)
{
entry = Unsafe.Add(ref codeTableRef, hashIndex);
break;
}
} }
while (Unsafe.Add(ref hashTableRef, hashIndex) >= 0);
if (Unsafe.Add(ref hashTableRef, i) == fcode) if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode)
{ {
ent = Unsafe.Add(ref codeTableRef, i); continue;
break;
} }
} }
while (Unsafe.Add(ref hashTableRef, i) >= 0);
if (Unsafe.Add(ref hashTableRef, i) == fcode) this.Output(entry, stream);
entry = code;
if (this.freeEntry < MaxMaxCode)
{ {
continue; Unsafe.Add(ref codeTableRef, hashIndex) = this.freeEntry++; // code -> hashtable
Unsafe.Add(ref hashTableRef, hashIndex) = freeCode;
}
else
{
this.ClearBlock(stream);
} }
}
this.Output(ent, stream);
ent = c;
if (this.freeEntry < MaxMaxCode)
{
Unsafe.Add(ref codeTableRef, i) = this.freeEntry++; // code -> hashtable
Unsafe.Add(ref hashTableRef, i) = fcode;
}
else
{
this.ClearBlock(stream);
} }
} }
// Put out the final code. // Output the final code.
this.Output(ent, stream); this.Output(entry, stream);
this.Output(this.eofCode, stream); this.Output(this.eofCode, stream);
} }
@ -366,19 +352,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.accumulatorCount = 0; this.accumulatorCount = 0;
} }
/// <summary>
/// Reads the next pixel from the image.
/// </summary>
/// <param name="indexedPixels">The span of indexed pixels.</param>
/// <returns>
/// The <see cref="int"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int NextPixel(ReadOnlySpan<byte> indexedPixels)
{
return indexedPixels[this.position++] & 0xFF;
}
/// <summary> /// <summary>
/// Output the current code to the stream. /// Output the current code to the stream.
/// </summary> /// </summary>

32
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs

@ -99,22 +99,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
var CMax4 = new Vector4(maximum); var CMax4 = new Vector4(maximum);
var COff4 = new Vector4(MathF.Ceiling(maximum / 2)); var COff4 = new Vector4(MathF.Ceiling(maximum / 2));
this.V0L = Vector4.Clamp(this.V0L + COff4, CMin4, CMax4); this.V0L = Vector4Utilities.FastClamp(this.V0L + COff4, CMin4, CMax4);
this.V0R = Vector4.Clamp(this.V0R + COff4, CMin4, CMax4); this.V0R = Vector4Utilities.FastClamp(this.V0R + COff4, CMin4, CMax4);
this.V1L = Vector4.Clamp(this.V1L + COff4, CMin4, CMax4); this.V1L = Vector4Utilities.FastClamp(this.V1L + COff4, CMin4, CMax4);
this.V1R = Vector4.Clamp(this.V1R + COff4, CMin4, CMax4); this.V1R = Vector4Utilities.FastClamp(this.V1R + COff4, CMin4, CMax4);
this.V2L = Vector4.Clamp(this.V2L + COff4, CMin4, CMax4); this.V2L = Vector4Utilities.FastClamp(this.V2L + COff4, CMin4, CMax4);
this.V2R = Vector4.Clamp(this.V2R + COff4, CMin4, CMax4); this.V2R = Vector4Utilities.FastClamp(this.V2R + COff4, CMin4, CMax4);
this.V3L = Vector4.Clamp(this.V3L + COff4, CMin4, CMax4); this.V3L = Vector4Utilities.FastClamp(this.V3L + COff4, CMin4, CMax4);
this.V3R = Vector4.Clamp(this.V3R + COff4, CMin4, CMax4); this.V3R = Vector4Utilities.FastClamp(this.V3R + COff4, CMin4, CMax4);
this.V4L = Vector4.Clamp(this.V4L + COff4, CMin4, CMax4); this.V4L = Vector4Utilities.FastClamp(this.V4L + COff4, CMin4, CMax4);
this.V4R = Vector4.Clamp(this.V4R + COff4, CMin4, CMax4); this.V4R = Vector4Utilities.FastClamp(this.V4R + COff4, CMin4, CMax4);
this.V5L = Vector4.Clamp(this.V5L + COff4, CMin4, CMax4); this.V5L = Vector4Utilities.FastClamp(this.V5L + COff4, CMin4, CMax4);
this.V5R = Vector4.Clamp(this.V5R + COff4, CMin4, CMax4); this.V5R = Vector4Utilities.FastClamp(this.V5R + COff4, CMin4, CMax4);
this.V6L = Vector4.Clamp(this.V6L + COff4, CMin4, CMax4); this.V6L = Vector4Utilities.FastClamp(this.V6L + COff4, CMin4, CMax4);
this.V6R = Vector4.Clamp(this.V6R + COff4, CMin4, CMax4); this.V6R = Vector4Utilities.FastClamp(this.V6R + COff4, CMin4, CMax4);
this.V7L = Vector4.Clamp(this.V7L + COff4, CMin4, CMax4); this.V7L = Vector4Utilities.FastClamp(this.V7L + COff4, CMin4, CMax4);
this.V7R = Vector4.Clamp(this.V7R + COff4, CMin4, CMax4); this.V7R = Vector4Utilities.FastClamp(this.V7R + COff4, CMin4, CMax4);
} }
/// <summary> /// <summary>

2
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt

@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
for (int j = 0; j < 2; j++) for (int j = 0; j < 2; j++)
{ {
char side = j == 0 ? 'L' : 'R'; char side = j == 0 ? 'L' : 'R';
Write($"this.V{i}{side} = Vector4.Clamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n"); Write($"this.V{i}{side} = Vector4Utilities.FastClamp(this.V{i}{side} + COff4, CMin4, CMax4);\r\n");
} }
} }
PopIndent(); PopIndent();

2
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

@ -589,7 +589,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor) private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor)
{ {
// sign(dividend) = max(min(dividend, 1), -1) // sign(dividend) = max(min(dividend, 1), -1)
var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One); var sign = Vector4Utilities.FastClamp(dividend, NegativeOne, Vector4.One);
// AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend) // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend)
return (dividend / divisor) + (sign * Offset); return (dividend / divisor) + (sign * Offset);

4
src/ImageSharp/Formats/Png/Zlib/DeflaterConstants.cs

@ -3,15 +3,13 @@
// <auto-generated/> // <auto-generated/>
using System; using System;
using System.Collections.Generic;
using System.Text;
namespace SixLabors.ImageSharp.Formats.Png.Zlib namespace SixLabors.ImageSharp.Formats.Png.Zlib
{ {
/// <summary> /// <summary>
/// This class contains constants used for deflation. /// This class contains constants used for deflation.
/// </summary> /// </summary>
public static class DeflaterConstants internal static class DeflaterConstants
{ {
/// <summary> /// <summary>
/// Set to true to enable debugging /// Set to true to enable debugging

2
src/ImageSharp/Formats/Png/Zlib/DeflaterEngine.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
/// <summary> /// <summary>
/// Strategies for deflater /// Strategies for deflater
/// </summary> /// </summary>
public enum DeflateStrategy internal enum DeflateStrategy
{ {
/// <summary> /// <summary>
/// The default strategy /// The default strategy

36
src/ImageSharp/Formats/Tga/ImageExtensions.cs

@ -0,0 +1,36 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Tga;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="Image"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Saves the image to the given stream with the tga format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsTga(this Image source, Stream stream) => SaveAsTga(source, stream, null);
/// <summary>
/// Saves the image to the given stream with the tga format.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The options for the encoder.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder) =>
source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(TgaFormat.Instance));
}
}

1
src/ImageSharp/Formats/Tga/TgaDecoder.cs

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

555
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -12,8 +12,16 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tga namespace SixLabors.ImageSharp.Formats.Tga
{ {
/// <summary>
/// Performs the tga decoding operation.
/// </summary>
internal sealed class TgaDecoderCore internal sealed class TgaDecoderCore
{ {
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] scratchBuffer = new byte[4];
/// <summary> /// <summary>
/// The metadata. /// The metadata.
/// </summary> /// </summary>
@ -49,6 +57,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// </summary> /// </summary>
private readonly ITgaDecoderOptions options; private readonly ITgaDecoderOptions options;
/// <summary>
/// Indicates whether there is a alpha channel present.
/// </summary>
private bool hasAlpha;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="TgaDecoderCore"/> class. /// Initializes a new instance of the <see cref="TgaDecoderCore"/> class.
/// </summary> /// </summary>
@ -80,7 +93,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{ {
try try
{ {
bool inverted = this.ReadFileHeader(stream); TgaImageOrigin origin = this.ReadFileHeader(stream);
this.currentStream.Skip(this.fileHeader.IdLength); this.currentStream.Skip(this.fileHeader.IdLength);
// Parse the color map, if present. // Parse the color map, if present.
@ -97,7 +110,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
var image = Image.CreateUninitialized<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); var image = Image.CreateUninitialized<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer(); Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (this.fileHeader.ColorMapType is 1) if (this.fileHeader.ColorMapType == 1)
{ {
if (this.fileHeader.CMapLength <= 0) if (this.fileHeader.CMapLength <= 0)
{ {
@ -115,7 +128,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
{ {
this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes); this.currentStream.Read(palette.Array, this.fileHeader.CMapStart, colorMapSizeInBytes);
if (this.fileHeader.ImageType is TgaImageType.RleColorMapped) if (this.fileHeader.ImageType == TgaImageType.RleColorMapped)
{ {
this.ReadPalettedRle( this.ReadPalettedRle(
this.fileHeader.Width, this.fileHeader.Width,
@ -123,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
pixels, pixels,
palette.Array, palette.Array,
colorMapPixelSizeInBytes, colorMapPixelSizeInBytes,
inverted); origin);
} }
else else
{ {
@ -133,7 +146,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
pixels, pixels,
palette.Array, palette.Array,
colorMapPixelSizeInBytes, colorMapPixelSizeInBytes,
inverted); origin);
} }
} }
@ -152,11 +165,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 8: case 8:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) if (this.fileHeader.ImageType.IsRunLengthEncoded())
{ {
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, inverted); this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 1, origin);
} }
else else
{ {
this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); this.ReadMonoChrome(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
} }
break; break;
@ -165,11 +178,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 16: case 16:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) if (this.fileHeader.ImageType.IsRunLengthEncoded())
{ {
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, inverted); this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 2, origin);
} }
else else
{ {
this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); this.ReadBgra16(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
} }
break; break;
@ -177,11 +190,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 24: case 24:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) if (this.fileHeader.ImageType.IsRunLengthEncoded())
{ {
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, inverted); this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 3, origin);
} }
else else
{ {
this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); this.ReadBgr24(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
} }
break; break;
@ -189,17 +202,17 @@ namespace SixLabors.ImageSharp.Formats.Tga
case 32: case 32:
if (this.fileHeader.ImageType.IsRunLengthEncoded()) if (this.fileHeader.ImageType.IsRunLengthEncoded())
{ {
this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, inverted); this.ReadRle(this.fileHeader.Width, this.fileHeader.Height, pixels, 4, origin);
} }
else else
{ {
this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, inverted); this.ReadBgra32(this.fileHeader.Width, this.fileHeader.Height, pixels, origin);
} }
break; break;
default: default:
TgaThrowHelper.ThrowNotSupportedException("Does not support this kind of tga files."); TgaThrowHelper.ThrowNotSupportedException("ImageSharp does not support this kind of tga files.");
break; break;
} }
@ -220,56 +233,73 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="palette">The color palette.</param> /// <param name="palette">The color palette.</param>
/// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param> /// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">The image origin.</param>
private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted) private void ReadPaletted<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(width, AllocationOptions.Clean)) TPixel color = default;
bool invertX = InvertX(origin);
for (int y = 0; y < height; y++)
{ {
TPixel color = default; int newY = InvertY(y, height, origin);
Span<byte> rowSpan = row.GetSpan(); Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
for (int y = 0; y < height; y++) switch (colorMapPixelSizeInBytes)
{ {
this.currentStream.Read(row); case 2:
int newY = Invert(y, height, inverted); if (invertX)
Span<TPixel> pixelRow = pixels.GetRowSpan(newY); {
switch (colorMapPixelSizeInBytes) for (int x = width - 1; x >= 0; x--)
{ {
case 2: this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int colorIndex = rowSpan[x]; this.ReadPalettedBgra16Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
// Set alpha value to 1, to treat it as opaque for Bgra5551.
Bgra5551 bgra = Unsafe.As<byte, Bgra5551>(ref palette[colorIndex * colorMapPixelSizeInBytes]);
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
color.FromBgra5551(bgra);
pixelRow[x] = color;
} }
}
break; break;
case 3: case 3:
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgr24Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int colorIndex = rowSpan[x]; this.ReadPalettedBgr24Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
} }
}
break; break;
case 4: case 4:
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgra32Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
int colorIndex = rowSpan[x]; this.ReadPalettedBgra32Pixel(palette, colorMapPixelSizeInBytes, x, color, pixelRow);
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
} }
}
break; break;
}
} }
} }
} }
@ -283,8 +313,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="palette">The color palette.</param> /// <param name="palette">The color palette.</param>
/// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param> /// <param name="colorMapPixelSizeInBytes">Color map size of one entry in bytes.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">The image origin.</param>
private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, bool inverted) private void ReadPalettedRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, byte[] palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int bytesPerPixel = 1; int bytesPerPixel = 1;
@ -296,7 +326,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int newY = Invert(y, height, inverted); int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY); Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel; int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -308,10 +338,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
color.FromL8(Unsafe.As<byte, L8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); color.FromL8(Unsafe.As<byte, L8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break; break;
case 2: case 2:
// Set alpha value to 1, to treat it as opaque for Bgra5551. this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color);
Bgra5551 bgra = Unsafe.As<byte, Bgra5551>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]);
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
color.FromBgra5551(bgra);
break; break;
case 3: case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
@ -321,7 +348,8 @@ namespace SixLabors.ImageSharp.Formats.Tga
break; break;
} }
pixelRow[x] = color; int newX = InvertX(x, width, origin);
pixelRow[newX] = color;
} }
} }
} }
@ -334,22 +362,43 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param> /// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">the image origin.</param>
private void ReadMonoChrome<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted) private void ReadMonoChrome<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0)) bool invertX = InvertX(origin);
if (invertX)
{ {
TPixel color = default;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
this.currentStream.Read(row); int newY = InvertY(y, height, origin);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY); Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromL8Bytes( for (int x = width - 1; x >= 0; x--)
this.configuration, {
row.GetSpan(), this.ReadL8Pixel(color, x, pixelSpan);
pixelSpan, }
width); }
return;
}
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0))
{
bool invertY = InvertY(origin);
if (invertY)
{
for (int y = height - 1; y >= 0; y--)
{
this.ReadL8Row(width, pixels, row, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
this.ReadL8Row(width, pixels, row, y);
}
} }
} }
} }
@ -361,30 +410,64 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param> /// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">The image origin.</param>
private void ReadBgra16<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted) private void ReadBgra16<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
TPixel color = default;
bool invertX = InvertX(origin);
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0)) using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
this.currentStream.Read(row); int newY = InvertY(y, height, origin);
Span<byte> rowSpan = row.GetSpan(); Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
// We need to set each alpha component value to fully opaque. if (invertX)
for (int x = 1; x < rowSpan.Length; x += 2)
{ {
rowSpan[x] = (byte)(rowSpan[x] | (1 << 7)); for (int x = width - 1; x >= 0; x--)
{
this.currentStream.Read(this.scratchBuffer, 0, 2);
if (!this.hasAlpha)
{
this.scratchBuffer[1] |= 1 << 7;
}
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
color.FromLa16(Unsafe.As<byte, La16>(ref this.scratchBuffer[0]));
}
else
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref this.scratchBuffer[0]));
}
pixelSpan[x] = color;
}
} }
else
{
this.currentStream.Read(row);
Span<byte> rowSpan = row.GetSpan();
int newY = Invert(y, height, inverted); if (!this.hasAlpha)
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY); {
PixelOperations<TPixel>.Instance.FromBgra5551Bytes( // We need to set the alpha component value to fully opaque.
this.configuration, for (int x = 1; x < rowSpan.Length; x += 2)
rowSpan, {
pixelSpan, rowSpan[x] |= 1 << 7;
width); }
}
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
PixelOperations<TPixel>.Instance.FromLa16Bytes(this.configuration, rowSpan, pixelSpan, width);
}
else
{
PixelOperations<TPixel>.Instance.FromBgra5551Bytes(this.configuration, rowSpan, pixelSpan, width);
}
}
} }
} }
} }
@ -396,22 +479,44 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param> /// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">The image origin.</param>
private void ReadBgr24<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted) private void ReadBgr24<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0)) bool invertX = InvertX(origin);
if (invertX)
{ {
TPixel color = default;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
this.currentStream.Read(row); int newY = InvertY(y, height, origin);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY); Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgr24Bytes( for (int x = width - 1; x >= 0; x--)
this.configuration, {
row.GetSpan(), this.ReadBgr24Pixel(color, x, pixelSpan);
pixelSpan, }
width); }
return;
}
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0))
{
bool invertY = InvertY(origin);
if (invertY)
{
for (int y = height - 1; y >= 0; y--)
{
this.ReadBgr24Row(width, pixels, row, y);
}
}
else
{
for (int y = 0; y < height; y++)
{
this.ReadBgr24Row(width, pixels, row, y);
}
} }
} }
} }
@ -423,22 +528,52 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="width">The width of the image.</param> /// <param name="width">The width of the image.</param>
/// <param name="height">The height of the image.</param> /// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">The image origin.</param>
private void ReadBgra32<TPixel>(int width, int height, Buffer2D<TPixel> pixels, bool inverted) private void ReadBgra32<TPixel>(int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0)) TPixel color = default;
bool invertX = InvertX(origin);
if (this.tgaMetadata.AlphaChannelBits == 8 && !invertX)
{ {
for (int y = 0; y < height; y++) using (IManagedByteBuffer row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 4, 0))
{ {
this.currentStream.Read(row); if (InvertY(origin))
int newY = Invert(y, height, inverted); {
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY); for (int y = height - 1; y >= 0; y--)
PixelOperations<TPixel>.Instance.FromBgra32Bytes( {
this.configuration, this.ReadBgra32Row(width, pixels, row, y);
row.GetSpan(), }
pixelSpan, }
width); else
{
for (int y = 0; y < height; y++)
{
this.ReadBgra32Row(width, pixels, row, y);
}
}
}
return;
}
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
if (invertX)
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadBgra32Pixel(x, color, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
this.ReadBgra32Pixel(x, color, pixelRow);
}
} }
} }
} }
@ -451,18 +586,19 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// <param name="height">The height of the image.</param> /// <param name="height">The height of the image.</param>
/// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param> /// <param name="pixels">The <see cref="Buffer2D{TPixel}"/> to assign the palette to.</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param> /// <param name="bytesPerPixel">The bytes per pixel.</param>
/// <param name="inverted">Indicates, if the origin of the image is top left rather the bottom left (the default).</param> /// <param name="origin">The image origin.</param>
private void ReadRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, int bytesPerPixel, bool inverted) private void ReadRle<TPixel>(int width, int height, Buffer2D<TPixel> pixels, int bytesPerPixel, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
TPixel color = default; TPixel color = default;
var alphaBits = this.tgaMetadata.AlphaChannelBits;
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * bytesPerPixel, AllocationOptions.Clean)) using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * bytesPerPixel, AllocationOptions.Clean))
{ {
Span<byte> bufferSpan = buffer.GetSpan(); Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle(width, height, bufferSpan, bytesPerPixel); this.UncompressRle(width, height, bufferSpan, bytesPerPixel);
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int newY = Invert(y, height, inverted); int newY = InvertY(y, height, origin);
Span<TPixel> pixelRow = pixels.GetRowSpan(newY); Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
int rowStartIdx = y * width * bytesPerPixel; int rowStartIdx = y * width * bytesPerPixel;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -474,19 +610,41 @@ namespace SixLabors.ImageSharp.Formats.Tga
color.FromL8(Unsafe.As<byte, L8>(ref bufferSpan[idx])); color.FromL8(Unsafe.As<byte, L8>(ref bufferSpan[idx]));
break; break;
case 2: case 2:
// Set alpha value to 1, to treat it as opaque for Bgra5551. if (!this.hasAlpha)
bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128); {
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx])); // Set alpha value to 1, to treat it as opaque for Bgra5551.
bufferSpan[idx + 1] = (byte)(bufferSpan[idx + 1] | 128);
}
if (this.fileHeader.ImageType == TgaImageType.RleBlackAndWhite)
{
color.FromLa16(Unsafe.As<byte, La16>(ref bufferSpan[idx]));
}
else
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx]));
}
break; break;
case 3: case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx])); color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
break; break;
case 4: case 4:
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx])); if (this.hasAlpha)
{
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx]));
}
else
{
var alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3];
color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], (byte)alpha));
}
break; break;
} }
pixelRow[x] = color; int newX = InvertX(x, width, origin);
pixelRow[newX] = color;
} }
} }
} }
@ -506,6 +664,104 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.metadata); this.metadata);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadL8Row<TPixel>(int width, Buffer2D<TPixel> pixels, IManagedByteBuffer row, int y)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromL8Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadL8Pixel<TPixel>(TPixel color, int x, Span<TPixel> pixelSpan)
where TPixel : unmanaged, IPixel<TPixel>
{
var pixelValue = (byte)this.currentStream.ReadByte();
color.FromL8(Unsafe.As<byte, L8>(ref pixelValue));
pixelSpan[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgr24Pixel<TPixel>(TPixel color, int x, Span<TPixel> pixelSpan)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(this.scratchBuffer, 0, 3);
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref this.scratchBuffer[0]));
pixelSpan[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgr24Row<TPixel>(int width, Buffer2D<TPixel> pixels, IManagedByteBuffer row, int y)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgra32Pixel<TPixel>(int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(this.scratchBuffer, 0, 4);
var alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : this.scratchBuffer[3];
color.FromBgra32(new Bgra32(this.scratchBuffer[2], this.scratchBuffer[1], this.scratchBuffer[0], alpha));
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgra32Row<TPixel>(int width, Buffer2D<TPixel> pixels, IManagedByteBuffer row, int y)
where TPixel : unmanaged, IPixel<TPixel>
{
this.currentStream.Read(row);
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(this.configuration, row.GetSpan(), pixelSpan, width);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes, ref color);
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(byte[] palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Bgra5551 bgra = default;
bgra.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[index * colorMapPixelSizeInBytes]));
if (!this.hasAlpha)
{
// Set alpha value to 1, to treat it as opaque.
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
}
color.FromBgra5551(bgra);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgr24Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra32Pixel<TPixel>(byte[] palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = this.currentStream.ReadByte();
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
}
/// <summary> /// <summary>
/// Produce uncompressed tga data from a run length encoded stream. /// Produce uncompressed tga data from a run length encoded stream.
/// </summary> /// </summary>
@ -554,18 +810,80 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// Returns the y- value based on the given height. /// Returns the y- value based on the given height.
/// </summary> /// </summary>
/// <param name="y">The y- value representing the current row.</param> /// <param name="y">The y- value representing the current row.</param>
/// <param name="height">The height of the bitmap.</param> /// <param name="height">The height of the image.</param>
/// <param name="inverted">Whether the bitmap is inverted.</param> /// <param name="origin">The image origin.</param>
/// <returns>The <see cref="int"/> representing the inverted value.</returns> /// <returns>The <see cref="int"/> representing the inverted value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int Invert(int y, int height, bool inverted) => (!inverted) ? height - y - 1 : y; private static int InvertY(int y, int height, TgaImageOrigin origin)
{
if (InvertY(origin))
{
return height - y - 1;
}
return y;
}
/// <summary>
/// Indicates whether the y coordinates needs to be inverted, to keep a top left origin.
/// </summary>
/// <param name="origin">The image origin.</param>
/// <returns>True, if y coordinate needs to be inverted.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool InvertY(TgaImageOrigin origin)
{
switch (origin)
{
case TgaImageOrigin.BottomLeft:
case TgaImageOrigin.BottomRight:
return true;
default:
return false;
}
}
/// <summary>
/// Returns the x- value based on the given width.
/// </summary>
/// <param name="x">The x- value representing the current column.</param>
/// <param name="width">The width of the image.</param>
/// <param name="origin">The image origin.</param>
/// <returns>The <see cref="int"/> representing the inverted value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int InvertX(int x, int width, TgaImageOrigin origin)
{
if (InvertX(origin))
{
return width - x - 1;
}
return x;
}
/// <summary>
/// Indicates whether the x coordinates needs to be inverted, to keep a top left origin.
/// </summary>
/// <param name="origin">The image origin.</param>
/// <returns>True, if x coordinate needs to be inverted.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool InvertX(TgaImageOrigin origin)
{
switch (origin)
{
case TgaImageOrigin.TopRight:
case TgaImageOrigin.BottomRight:
return true;
default:
return false;
}
}
/// <summary> /// <summary>
/// Reads the tga file header from the stream. /// Reads the tga file header from the stream.
/// </summary> /// </summary>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param> /// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>true, if the image origin is top left.</returns> /// <returns>The image origin.</returns>
private bool ReadFileHeader(Stream stream) private TgaImageOrigin ReadFileHeader(Stream stream)
{ {
this.currentStream = stream; this.currentStream = stream;
@ -577,13 +895,18 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.tgaMetadata = this.metadata.GetTgaMetadata(); this.tgaMetadata = this.metadata.GetTgaMetadata();
this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth; this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth;
// Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom right. var alphaBits = this.fileHeader.ImageDescriptor & 0xf;
if ((this.fileHeader.ImageDescriptor & (1 << 5)) != 0) if (alphaBits != 0 && alphaBits != 1 && alphaBits != 8)
{ {
return true; TgaThrowHelper.ThrowImageFormatException("Invalid alpha channel bits");
} }
return false; this.tgaMetadata.AlphaChannelBits = (byte)alphaBits;
this.hasAlpha = alphaBits > 0;
// Bits 4 and 5 describe the image origin.
var origin = (TgaImageOrigin)((this.fileHeader.ImageDescriptor & 0x30) >> 4);
return origin;
} }
} }
} }

20
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -78,8 +78,24 @@ namespace SixLabors.ImageSharp.Formats.Tga
imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleBlackAndWhite : TgaImageType.BlackAndWhite; imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleBlackAndWhite : TgaImageType.BlackAndWhite;
} }
// If compression is used, set bit 5 of the image descriptor to indicate an left top origin. byte imageDescriptor = 0;
byte imageDescriptor = (byte)(this.compression is TgaCompression.RunLength ? 32 : 0); if (this.compression is TgaCompression.RunLength)
{
// If compression is used, set bit 5 of the image descriptor to indicate a left top origin.
imageDescriptor |= 0x20;
}
if (this.bitsPerPixel is TgaBitsPerPixel.Pixel32)
{
// Indicate, that 8 bit are used for the alpha channel.
imageDescriptor |= 0x8;
}
if (this.bitsPerPixel is TgaBitsPerPixel.Pixel16)
{
// Indicate, that 1 bit is used for the alpha channel.
imageDescriptor |= 0x1;
}
var fileHeader = new TgaFileHeader( var fileHeader = new TgaFileHeader(
idLength: 0, idLength: 0,

28
src/ImageSharp/Formats/Tga/TgaImageOrigin.cs

@ -0,0 +1,28 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tga
{
internal enum TgaImageOrigin
{
/// <summary>
/// Bottom left origin.
/// </summary>
BottomLeft = 0,
/// <summary>
/// Bottom right origin.
/// </summary>
BottomRight = 1,
/// <summary>
/// Top left origin.
/// </summary>
TopLeft = 2,
/// <summary>
/// Top right origin.
/// </summary>
TopRight = 3,
}
}

5
src/ImageSharp/Formats/Tga/TgaMetadata.cs

@ -29,6 +29,11 @@ namespace SixLabors.ImageSharp.Formats.Tga
/// </summary> /// </summary>
public TgaBitsPerPixel BitsPerPixel { get; set; } = TgaBitsPerPixel.Pixel24; public TgaBitsPerPixel BitsPerPixel { get; set; } = TgaBitsPerPixel.Pixel24;
/// <summary>
/// Gets or sets the the number of alpha bits per pixel.
/// </summary>
public byte AlphaChannelBits { get; set; } = 0;
/// <inheritdoc/> /// <inheritdoc/>
public IDeepCloneable DeepClone() => new TgaMetadata(this); public IDeepCloneable DeepClone() => new TgaMetadata(this);
} }

6
src/ImageSharp/GeometryUtilities.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors namespace SixLabors.ImageSharp
{ {
/// <summary> /// <summary>
/// Utility class for common geometric functions. /// Utility class for common geometric functions.
@ -31,4 +31,4 @@ namespace SixLabors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float RadianToDegree(float radian) => radian / (MathF.PI / 180F); public static float RadianToDegree(float radian) => radian / (MathF.PI / 180F);
} }
} }

125
src/ImageSharp/Image.FromBytes.cs

@ -26,14 +26,55 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// By reading the header on the provided byte array this calculates the images format. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="configuration">The configuration.</param>
/// <param name="data">The byte array containing encoded image data to read the header from.</param> /// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration config, byte[] data) public static IImageFormat DetectFormat(Configuration configuration, byte[] data)
{ {
using (var stream = new MemoryStream(data)) Guard.NotNull(configuration, nameof(configuration));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return DetectFormat(configuration, stream);
}
}
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(byte[] data) => Identify(data, out IImageFormat _);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(byte[] data, out IImageFormat format) => Identify(Configuration.Default, data, out format);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Configuration configuration, byte[] data, out IImageFormat format)
{
Guard.NotNull(configuration, nameof(configuration));
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{ {
return DetectFormat(config, stream); return Identify(configuration, stream, out format);
} }
} }
@ -68,33 +109,33 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte array containing encoded image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data) public static Image<TPixel> Load<TPixel>(Configuration configuration, byte[] data)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (var stream = new MemoryStream(data, 0, data.Length, false, true)) using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{ {
return Load<TPixel>(config, stream); return Load<TPixel>(configuration, stream);
} }
} }
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte array containing encoded image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param> /// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, out IImageFormat format) public static Image<TPixel> Load<TPixel>(Configuration configuration, byte[] data, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (var stream = new MemoryStream(data, 0, data.Length, false, true)) using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{ {
return Load<TPixel>(config, stream, out format); return Load<TPixel>(configuration, stream, out format);
} }
} }
@ -117,17 +158,17 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="configuration">The Configuration.</param>
/// <param name="data">The byte array containing encoded image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, IImageDecoder decoder) public static Image<TPixel> Load<TPixel>(Configuration configuration, byte[] data, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (var stream = new MemoryStream(data, 0, data.Length, false, true)) using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{ {
return Load<TPixel>(config, stream, decoder); return Load<TPixel>(configuration, stream, decoder);
} }
} }
@ -144,18 +185,18 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// By reading the header on the provided byte array this calculates the images format. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="configuration">The configuration.</param>
/// <param name="data">The byte array containing encoded image data to read the header from.</param> /// <param name="data">The byte array containing encoded image data to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration config, ReadOnlySpan<byte> data) public static IImageFormat DetectFormat(Configuration configuration, ReadOnlySpan<byte> data)
{ {
int maxHeaderSize = config.MaxHeaderSize; int maxHeaderSize = configuration.MaxHeaderSize;
if (maxHeaderSize <= 0) if (maxHeaderSize <= 0)
{ {
return null; return null;
} }
foreach (IImageFormatDetector detector in config.ImageFormatsManager.FormatDetectors) foreach (IImageFormatDetector detector in configuration.ImageFormatsManager.FormatDetectors)
{ {
IImageFormat f = detector.DetectFormat(data); IImageFormat f = detector.DetectFormat(data);
@ -203,18 +244,18 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte span containing encoded image data.</param> /// <param name="data">The byte span containing encoded image data.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>(Configuration config, ReadOnlySpan<byte> data) public static unsafe Image<TPixel> Load<TPixel>(Configuration configuration, ReadOnlySpan<byte> data)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
fixed (byte* ptr = &data.GetPinnableReference()) fixed (byte* ptr = &data.GetPinnableReference())
{ {
using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{ {
return Load<TPixel>(config, stream); return Load<TPixel>(configuration, stream);
} }
} }
} }
@ -222,13 +263,13 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="configuration">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param> /// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>( public static unsafe Image<TPixel> Load<TPixel>(
Configuration config, Configuration configuration,
ReadOnlySpan<byte> data, ReadOnlySpan<byte> data,
IImageDecoder decoder) IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -237,7 +278,7 @@ namespace SixLabors.ImageSharp
{ {
using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{ {
return Load<TPixel>(config, stream, decoder); return Load<TPixel>(configuration, stream, decoder);
} }
} }
} }
@ -245,13 +286,13 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span. /// Load a new instance of <see cref="Image{TPixel}"/> from the given encoded byte span.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param> /// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param> /// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static unsafe Image<TPixel> Load<TPixel>( public static unsafe Image<TPixel> Load<TPixel>(
Configuration config, Configuration configuration,
ReadOnlySpan<byte> data, ReadOnlySpan<byte> data,
out IImageFormat format) out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -260,7 +301,7 @@ namespace SixLabors.ImageSharp
{ {
using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{ {
return Load<TPixel>(config, stream, out format); return Load<TPixel>(configuration, stream, out format);
} }
} }
} }
@ -285,38 +326,38 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array. /// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing encoded image data.</param> /// <param name="data">The byte array containing encoded image data.</param>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, byte[] data) => Load(config, data, out _); public static Image Load(Configuration configuration, byte[] data) => Load(configuration, data, out _);
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array. /// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) public static Image Load(Configuration configuration, byte[] data, IImageDecoder decoder)
{ {
using (var stream = new MemoryStream(data, 0, data.Length, false, true)) using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{ {
return Load(config, stream, decoder); return Load(configuration, stream, decoder);
} }
} }
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte array. /// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="configuration">The configuration for the decoder.</param>
/// <param name="data">The byte array containing image data.</param> /// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, byte[] data, out IImageFormat format) public static Image Load(Configuration configuration, byte[] data, out IImageFormat format)
{ {
using (var stream = new MemoryStream(data, 0, data.Length, false, true)) using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{ {
return Load(config, stream, out format); return Load(configuration, stream, out format);
} }
} }
@ -348,20 +389,20 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Decodes a new instance of <see cref="Image"/> from the given encoded byte span. /// Decodes a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param> /// <param name="data">The byte span containing image data.</param>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, ReadOnlySpan<byte> data) => Load(config, data, out _); public static Image Load(Configuration configuration, ReadOnlySpan<byte> data) => Load(configuration, data, out _);
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span. /// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="configuration">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param> /// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static unsafe Image Load( public static unsafe Image Load(
Configuration config, Configuration configuration,
ReadOnlySpan<byte> data, ReadOnlySpan<byte> data,
IImageDecoder decoder) IImageDecoder decoder)
{ {
@ -369,7 +410,7 @@ namespace SixLabors.ImageSharp
{ {
using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{ {
return Load(config, stream, decoder); return Load(configuration, stream, decoder);
} }
} }
} }
@ -377,12 +418,12 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Load a new instance of <see cref="Image"/> from the given encoded byte span. /// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param> /// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>> /// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static unsafe Image Load( public static unsafe Image Load(
Configuration config, Configuration configuration,
ReadOnlySpan<byte> data, ReadOnlySpan<byte> data,
out IImageFormat format) out IImageFormat format)
{ {
@ -390,7 +431,7 @@ namespace SixLabors.ImageSharp
{ {
using (var stream = new UnmanagedMemoryStream(ptr, data.Length)) using (var stream = new UnmanagedMemoryStream(ptr, data.Length))
{ {
return Load(config, stream, out format); return Load(configuration, stream, out format);
} }
} }
} }

99
src/ImageSharp/Image.FromFile.cs

@ -26,15 +26,55 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// By reading the header on the provided file this calculates the images mime type. /// By reading the header on the provided file this calculates the images mime type.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="configuration">The configuration.</param>
/// <param name="filePath">The image file to open and to read the header from.</param> /// <param name="filePath">The image file to open and to read the header from.</param>
/// <returns>The mime type or null if none found.</returns> /// <returns>The mime type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration config, string filePath) public static IImageFormat DetectFormat(Configuration configuration, string filePath)
{ {
config = config ?? Configuration.Default; Guard.NotNull(configuration, nameof(configuration));
using (Stream file = config.FileSystem.OpenRead(filePath)) using (Stream file = configuration.FileSystem.OpenRead(filePath))
{ {
return DetectFormat(config, file); return DetectFormat(configuration, file);
}
}
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(string filePath) => Identify(filePath, out IImageFormat _);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector not found.
/// </returns>
public static IImageInfo Identify(string filePath, out IImageFormat format) => Identify(Configuration.Default, filePath, out format);
/// <summary>
/// Reads the raw image information from the specified stream without fully decoding it.
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="filePath">The image file to open and to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector is not found.
/// </returns>
public static IImageInfo Identify(Configuration configuration, string filePath, out IImageFormat format)
{
Guard.NotNull(configuration, nameof(configuration));
using (Stream file = configuration.FileSystem.OpenRead(filePath))
{
return Identify(configuration, file, out format);
} }
} }
@ -62,29 +102,30 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="configuration">The configuration for the decoder.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, string path) => Load(config, path, out _); public static Image Load(Configuration configuration, string path) => Load(configuration, path, out _);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="configuration">The Configuration.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>The <see cref="Image"/>.</returns> /// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, string path, IImageDecoder decoder) public static Image Load(Configuration configuration, string path, IImageDecoder decoder)
{ {
using (Stream stream = config.FileSystem.OpenRead(path)) Guard.NotNull(configuration, nameof(configuration));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{ {
return Load(config, stream, decoder); return Load(configuration, stream, decoder);
} }
} }
@ -133,26 +174,27 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, string path) public static Image<TPixel> Load<TPixel>(Configuration configuration, string path)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Stream stream = config.FileSystem.OpenRead(path)) Guard.NotNull(configuration, nameof(configuration));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{ {
return Load<TPixel>(config, stream); return Load<TPixel>(configuration, stream);
} }
} }
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
@ -160,12 +202,13 @@ namespace SixLabors.ImageSharp
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, string path, out IImageFormat format) public static Image<TPixel> Load<TPixel>(Configuration configuration, string path, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Stream stream = config.FileSystem.OpenRead(path)) Guard.NotNull(configuration, nameof(configuration));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{ {
return Load<TPixel>(config, stream, out format); return Load<TPixel>(configuration, stream, out format);
} }
} }
@ -173,18 +216,19 @@ namespace SixLabors.ImageSharp
/// Create a new instance of the <see cref="Image"/> class from the given file. /// Create a new instance of the <see cref="Image"/> class from the given file.
/// The pixel type is selected by the decoder. /// The pixel type is selected by the decoder.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param> /// <param name="format">The mime type of the decoded image.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable. /// Thrown if the stream is not readable nor seekable.
/// </exception> /// </exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(Configuration config, string path, out IImageFormat format) public static Image Load(Configuration configuration, string path, out IImageFormat format)
{ {
using (Stream stream = config.FileSystem.OpenRead(path)) Guard.NotNull(configuration, nameof(configuration));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{ {
return Load(config, stream, out format); return Load(configuration, stream, out format);
} }
} }
@ -207,7 +251,7 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given file.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="configuration">The Configuration.</param>
/// <param name="path">The file path to the image.</param> /// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
@ -215,12 +259,13 @@ namespace SixLabors.ImageSharp
/// </exception> /// </exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, string path, IImageDecoder decoder) public static Image<TPixel> Load<TPixel>(Configuration configuration, string path, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (Stream stream = config.FileSystem.OpenRead(path)) Guard.NotNull(configuration, nameof(configuration));
using (Stream stream = configuration.FileSystem.OpenRead(path))
{ {
return Load<TPixel>(config, stream, decoder); return Load<TPixel>(configuration, stream, decoder);
} }
} }
} }

68
src/ImageSharp/Image.FromStream.cs

@ -26,15 +26,15 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// By reading the header on the provided stream this calculates the images format type. /// By reading the header on the provided stream this calculates the images format type.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="configuration">The configuration.</param>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns>The format type or null if none found.</returns> /// <returns>The format type or null if none found.</returns>
public static IImageFormat DetectFormat(Configuration config, Stream stream) public static IImageFormat DetectFormat(Configuration configuration, Stream stream)
=> WithSeekableStream(config, stream, s => InternalDetectFormat(s, config)); => WithSeekableStream(configuration, stream, s => InternalDetectFormat(s, configuration));
/// <summary> /// <summary>
/// By reading the header on the provided stream this reads the raw image information. /// Reads the raw image information from the specified stream without fully decoding it.
/// </summary> /// </summary>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp
public static IImageInfo Identify(Stream stream) => Identify(stream, out IImageFormat _); public static IImageInfo Identify(Stream stream) => Identify(stream, out IImageFormat _);
/// <summary> /// <summary>
/// By reading the header on the provided stream this reads the raw image information. /// Reads the raw image information from the specified stream without fully decoding it.
/// </summary> /// </summary>
/// <param name="stream">The image stream to read the header from.</param> /// <param name="stream">The image stream to read the header from.</param>
/// <param name="format">The format type of the decoded image.</param> /// <param name="format">The format type of the decoded image.</param>
@ -57,16 +57,16 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Reads the raw image information from the specified stream without fully decoding it. /// Reads the raw image information from the specified stream without fully decoding it.
/// </summary> /// </summary>
/// <param name="config">The configuration.</param> /// <param name="configuration">The configuration.</param>
/// <param name="stream">The image stream to read the information from.</param> /// <param name="stream">The image stream to read the information from.</param>
/// <param name="format">The format type of the decoded image.</param> /// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <returns> /// <returns>
/// The <see cref="IImageInfo"/> or null if suitable info detector is not found. /// The <see cref="IImageInfo"/> or null if suitable info detector is not found.
/// </returns> /// </returns>
public static IImageInfo Identify(Configuration config, Stream stream, out IImageFormat format) public static IImageInfo Identify(Configuration configuration, Stream stream, out IImageFormat format)
{ {
(IImageInfo info, IImageFormat format) data = WithSeekableStream(config, stream, s => InternalIdentity(s, config ?? Configuration.Default)); (IImageInfo info, IImageFormat format) data = WithSeekableStream(configuration, stream, s => InternalIdentity(s, configuration ?? Configuration.Default));
format = data.format; format = data.format;
return data.info; return data.info;
@ -108,24 +108,24 @@ namespace SixLabors.ImageSharp
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder. /// The pixel format is selected by the decoder.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="configuration">The configuration for the decoder.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception> /// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <returns>A new <see cref="Image"/>.</returns>> /// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Configuration config, Stream stream, IImageDecoder decoder) => public static Image Load(Configuration configuration, Stream stream, IImageDecoder decoder) =>
WithSeekableStream(config, stream, s => decoder.Decode(config, s)); WithSeekableStream(configuration, stream, s => decoder.Decode(configuration, s));
/// <summary> /// <summary>
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="config">The config for the decoder.</param> /// <param name="configuration">The configuration for the decoder.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception> /// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <returns>A new <see cref="Image"/>.</returns>> /// <returns>A new <see cref="Image"/>.</returns>>
public static Image Load(Configuration config, Stream stream) => Load(config, stream, out _); public static Image Load(Configuration configuration, Stream stream) => Load(configuration, stream, out _);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream) public static Image<TPixel> Load<TPixel>(Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(null, stream); => Load<TPixel>(Configuration.Default, stream);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Stream stream, out IImageFormat format) public static Image<TPixel> Load<TPixel>(Stream stream, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(null, stream, out format); => Load<TPixel>(Configuration.Default, stream, out format);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
@ -168,45 +168,45 @@ namespace SixLabors.ImageSharp
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="config">The Configuration.</param> /// <param name="configuration">The Configuration.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="decoder">The decoder.</param> /// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception> /// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream, IImageDecoder decoder) public static Image<TPixel> Load<TPixel>(Configuration configuration, Stream stream, IImageDecoder decoder)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> WithSeekableStream(config, stream, s => decoder.Decode<TPixel>(config, s)); => WithSeekableStream(configuration, stream, s => decoder.Decode<TPixel>(configuration, s));
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception> /// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>>
public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream) public static Image<TPixel> Load<TPixel>(Configuration configuration, Stream stream)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
=> Load<TPixel>(config, stream, out IImageFormat _); => Load<TPixel>(configuration, stream, out IImageFormat _);
/// <summary> /// <summary>
/// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream. /// Create a new instance of the <see cref="Image{TPixel}"/> class from the given stream.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param> /// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception> /// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns>> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image<TPixel> Load<TPixel>(Configuration config, Stream stream, out IImageFormat format) public static Image<TPixel> Load<TPixel>(Configuration configuration, Stream stream, out IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
config = config ?? Configuration.Default; Guard.NotNull(configuration, nameof(configuration));
(Image<TPixel> img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode<TPixel>(s, config)); (Image<TPixel> img, IImageFormat format) data = WithSeekableStream(configuration, stream, s => Decode<TPixel>(s, configuration));
format = data.format; format = data.format;
@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:"); sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in config.ImageFormatsManager.ImageDecoders) foreach (KeyValuePair<IImageFormat, IImageDecoder> val in configuration.ImageFormatsManager.ImageDecoders)
{ {
sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
} }
@ -230,16 +230,16 @@ namespace SixLabors.ImageSharp
/// Decode a new instance of the <see cref="Image"/> class from the given stream. /// Decode a new instance of the <see cref="Image"/> class from the given stream.
/// The pixel format is selected by the decoder. /// The pixel format is selected by the decoder.
/// </summary> /// </summary>
/// <param name="config">The configuration options.</param> /// <param name="configuration">The configuration options.</param>
/// <param name="stream">The stream containing image information.</param> /// <param name="stream">The stream containing image information.</param>
/// <param name="format">The format type of the decoded image.</param> /// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception> /// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception> /// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <returns>A new <see cref="Image{TPixel}"/>.</returns> /// <returns>A new <see cref="Image{TPixel}"/>.</returns>
public static Image Load(Configuration config, Stream stream, out IImageFormat format) public static Image Load(Configuration configuration, Stream stream, out IImageFormat format)
{ {
config = config ?? Configuration.Default; Guard.NotNull(configuration, nameof(configuration));
(Image img, IImageFormat format) data = WithSeekableStream(config, stream, s => Decode(s, config)); (Image img, IImageFormat format) data = WithSeekableStream(configuration, stream, s => Decode(s, configuration));
format = data.format; format = data.format;
@ -251,7 +251,7 @@ namespace SixLabors.ImageSharp
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("Image cannot be loaded. Available decoders:"); sb.AppendLine("Image cannot be loaded. Available decoders:");
foreach (KeyValuePair<IImageFormat, IImageDecoder> val in config.ImageFormatsManager.ImageDecoders) foreach (KeyValuePair<IImageFormat, IImageDecoder> val in configuration.ImageFormatsManager.ImageDecoders)
{ {
sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); sb.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
} }
@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp
throw new UnknownImageFormatException(sb.ToString()); throw new UnknownImageFormatException(sb.ToString());
} }
private static T WithSeekableStream<T>(Configuration config, Stream stream, Func<Stream, T> action) private static T WithSeekableStream<T>(Configuration configuration, Stream stream, Func<Stream, T> action)
{ {
if (!stream.CanRead) if (!stream.CanRead)
{ {
@ -268,7 +268,7 @@ namespace SixLabors.ImageSharp
if (stream.CanSeek) if (stream.CanSeek)
{ {
if (config.ReadOrigin == ReadOrigin.Begin) if (configuration.ReadOrigin == ReadOrigin.Begin)
{ {
stream.Position = 0; stream.Position = 0;
} }

12
src/ImageSharp/ImageExtensions.cs

@ -112,12 +112,12 @@ namespace SixLabors.ImageSharp
public static string ToBase64String<TPixel>(this Image<TPixel> source, IImageFormat format) public static string ToBase64String<TPixel>(this Image<TPixel> source, IImageFormat format)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
using (var stream = new MemoryStream()) using var stream = new MemoryStream();
{ source.Save(stream, format);
source.Save(stream, format);
stream.Flush(); // Always available.
return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(stream.ToArray())}"; stream.TryGetBuffer(out ArraySegment<byte> buffer);
} return $"data:{format.DefaultMimeType};base64,{Convert.ToBase64String(buffer.Array, 0, (int)stream.Length)}";
} }
} }
} }

28
src/ImageSharp/Processing/Processors/Quantization/IndexedImageFrame{TPixel}.cs → src/ImageSharp/IndexedImageFrame{TPixel}.cs

@ -4,19 +4,21 @@
using System; using System;
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Quantization;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization namespace SixLabors.ImageSharp
{ {
/// <summary> /// <summary>
/// A pixel-specific image frame where each pixel buffer value represents an index in a color palette. /// A pixel-specific image frame where each pixel buffer value represents an index in a color palette.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
public sealed class IndexedImageFrame<TPixel> : IDisposable public sealed class IndexedImageFrame<TPixel> : IPixelSource, IDisposable
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
private IMemoryOwner<byte> pixelsOwner; private Buffer2D<byte> pixelBuffer;
private IMemoryOwner<TPixel> paletteOwner; private IMemoryOwner<TPixel> paletteOwner;
private bool isDisposed; private bool isDisposed;
@ -39,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
this.Configuration = configuration; this.Configuration = configuration;
this.Width = width; this.Width = width;
this.Height = height; this.Height = height;
this.pixelsOwner = configuration.MemoryAllocator.AllocateManagedByteBuffer(width * height); this.pixelBuffer = configuration.MemoryAllocator.Allocate2D<byte>(width, height);
// Copy the palette over. We want the lifetime of this frame to be independant of any palette source. // Copy the palette over. We want the lifetime of this frame to be independant of any palette source.
this.paletteOwner = configuration.MemoryAllocator.Allocate<TPixel>(palette.Length); this.paletteOwner = configuration.MemoryAllocator.Allocate<TPixel>(palette.Length);
@ -67,16 +69,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary> /// </summary>
public ReadOnlyMemory<TPixel> Palette { get; } public ReadOnlyMemory<TPixel> Palette { get; }
/// <summary> /// <inheritdoc/>
/// Gets the pixels of this <see cref="IndexedImageFrame{TPixel}"/>. Buffer2D<byte> IPixelSource.PixelBuffer => this.pixelBuffer;
/// </summary>
/// <returns>The <see cref="ReadOnlySpan{T}"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public ReadOnlySpan<byte> GetPixelBufferSpan() => this.pixelsOwner.GetSpan(); // TODO: Buffer2D<byte>
/// <summary> /// <summary>
/// Gets the representation of the pixels as a <see cref="ReadOnlySpan{T}"/> of contiguous memory /// Gets the representation of the pixels as a <see cref="ReadOnlySpan{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row. /// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </summary> /// </summary>
/// <param name="rowIndex">The row index in the pixel buffer.</param> /// <param name="rowIndex">The row index in the pixel buffer.</param>
/// <returns>The pixel row as a <see cref="ReadOnlySpan{T}"/>.</returns> /// <returns>The pixel row as a <see cref="ReadOnlySpan{T}"/>.</returns>
@ -87,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary> /// <summary>
/// <para> /// <para>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory /// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the the first pixel on that row. /// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// </para> /// </para>
/// <para> /// <para>
/// Note: Values written to this span are not sanitized against the palette length. /// Note: Values written to this span are not sanitized against the palette length.
@ -98,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <returns>The pixel row as a <see cref="Span{T}"/>.</returns> /// <returns>The pixel row as a <see cref="Span{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Span<byte> GetWritablePixelRowSpanUnsafe(int rowIndex) public Span<byte> GetWritablePixelRowSpanUnsafe(int rowIndex)
=> this.pixelsOwner.GetSpan().Slice(rowIndex * this.Width, this.Width); => this.pixelBuffer.GetRowSpan(rowIndex);
/// <inheritdoc/> /// <inheritdoc/>
public void Dispose() public void Dispose()
@ -106,9 +104,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
if (!this.isDisposed) if (!this.isDisposed)
{ {
this.isDisposed = true; this.isDisposed = true;
this.pixelsOwner.Dispose(); this.pixelBuffer.Dispose();
this.paletteOwner.Dispose(); this.paletteOwner.Dispose();
this.pixelsOwner = null; this.pixelBuffer = null;
this.paletteOwner = null; this.paletteOwner = null;
} }
} }

2
src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs

@ -373,7 +373,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X; this.R = (byte)vector.X;
this.G = (byte)vector.Y; this.G = (byte)vector.Y;

2
src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs

@ -296,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X; this.R = (byte)vector.X;
this.G = (byte)vector.Y; this.G = (byte)vector.Y;

2
src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs

@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector4 vector) private static ushort Pack(ref Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One);
return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12)
| (((int)Math.Round(vector.X * 15F) & 0x0F) << 8) | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8)
| (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4) | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4)

2
src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs

@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector4 vector) private static ushort Pack(ref Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One);
return (ushort)( return (ushort)(
(((int)Math.Round(vector.X * 31F) & 0x1F) << 10) (((int)Math.Round(vector.X * 31F) & 0x1F) << 10)
| (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5) | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5)

2
src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs

@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats
const float Max = 255F; const float Max = 255F;
// Clamp the value between min and max values // Clamp the value between min and max values
vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max)); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, new Vector4(Max));
uint byte4 = (uint)Math.Round(vector.X) & 0xFF; uint byte4 = (uint)Math.Round(vector.X) & 0xFF;
uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8;

2
src/ImageSharp/PixelFormats/PixelImplementations/L16.cs

@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector) internal void ConvertFromRgbaScaledVector4(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max;
this.PackedValue = ImageMaths.Get16BitBT709Luminance( this.PackedValue = ImageMaths.Get16BitBT709Luminance(
vector.X, vector.X,
vector.Y, vector.Y,

2
src/ImageSharp/PixelFormats/PixelImplementations/L8.cs

@ -156,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z);
} }
} }

2
src/ImageSharp/PixelFormats/PixelImplementations/La16.cs

@ -219,7 +219,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
this.L = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); this.L = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z);
this.A = (byte)vector.W; this.A = (byte)vector.W;
} }

2
src/ImageSharp/PixelFormats/PixelImplementations/La32.cs

@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector) internal void ConvertFromRgbaScaledVector4(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max;
this.L = ImageMaths.Get16BitBT709Luminance( this.L = ImageMaths.Get16BitBT709Luminance(
vector.X, vector.X,
vector.Y, vector.Y,

2
src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs

@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector) private static uint Pack(ref Vector4 vector)
{ {
vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half; vector = Vector4Utilities.FastClamp(vector, MinusOne, Vector4.One) * Half;
uint byte4 = ((uint)MathF.Round(vector.X) & 0xFF) << 0; uint byte4 = ((uint)MathF.Round(vector.X) & 0xFF) << 0;
uint byte3 = ((uint)MathF.Round(vector.Y) & 0xFF) << 8; uint byte3 = ((uint)MathF.Round(vector.Y) & 0xFF) << 8;

2
src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs

@ -177,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats
private static ulong Pack(ref Vector4 vector) private static ulong Pack(ref Vector4 vector)
{ {
vector *= Max; vector *= Max;
vector = Vector4.Clamp(vector, Min, Max); vector = Vector4Utilities.FastClamp(vector, Min, Max);
// Round rather than truncate. // Round rather than truncate.
ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00; ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00;

2
src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs

@ -254,7 +254,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X; this.R = (byte)vector.X;
this.G = (byte)vector.Y; this.G = (byte)vector.Y;

2
src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs

@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) public void FromVector4(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max;
this.R = (ushort)MathF.Round(vector.X); this.R = (ushort)MathF.Round(vector.X);
this.G = (ushort)MathF.Round(vector.Y); this.G = (ushort)MathF.Round(vector.Y);
this.B = (ushort)MathF.Round(vector.Z); this.B = (ushort)MathF.Round(vector.Z);

2
src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs

@ -163,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector) private static uint Pack(ref Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Multiplier;
return (uint)( return (uint)(
(((int)Math.Round(vector.X) & 0x03FF) << 0) (((int)Math.Round(vector.X) & 0x03FF) << 0)

4
src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs

@ -452,7 +452,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
return new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W); return new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W);
} }
@ -491,7 +491,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X; this.R = (byte)vector.X;
this.G = (byte)vector.Y; this.G = (byte)vector.Y;

4
src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs

@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Vector4 vector) public Rgba64(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max;
this.R = (ushort)MathF.Round(vector.X); this.R = (ushort)MathF.Round(vector.X);
this.G = (ushort)MathF.Round(vector.Y); this.G = (ushort)MathF.Round(vector.Y);
this.B = (ushort)MathF.Round(vector.Z); this.B = (ushort)MathF.Round(vector.Z);
@ -209,7 +209,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) public void FromVector4(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One) * Max;
this.R = (ushort)MathF.Round(vector.X); this.R = (ushort)MathF.Round(vector.X);
this.G = (ushort)MathF.Round(vector.Y); this.G = (ushort)MathF.Round(vector.Y);
this.B = (ushort)MathF.Round(vector.Z); this.B = (ushort)MathF.Round(vector.Z);

2
src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs

@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) public void FromVector4(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); vector = Vector4Utilities.FastClamp(vector, Vector4.Zero, Vector4.One);
this.R = vector.X; this.R = vector.X;
this.G = vector.Y; this.G = vector.Y;
this.B = vector.Z; this.B = vector.Z;

2
src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs

@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static ulong Pack(ref Vector4 vector) private static ulong Pack(ref Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Min, Max); vector = Vector4Utilities.FastClamp(vector, Min, Max);
// Clamp the value between min and max values // Clamp the value between min and max values
ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00; ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00;

4
src/ImageSharp/PixelFormats/Utils/Vector4Converters.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) if (modifiers.IsDefined(PixelConversionModifiers.Premultiply))
{ {
Vector4Utils.Premultiply(vectors); Vector4Utilities.Premultiply(vectors);
} }
} }
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
{ {
if (modifiers.IsDefined(PixelConversionModifiers.Premultiply)) if (modifiers.IsDefined(PixelConversionModifiers.Premultiply))
{ {
Vector4Utils.UnPremultiply(vectors); Vector4Utilities.UnPremultiply(vectors);
} }
if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand)) if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand))

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

Loading…
Cancel
Save