Browse Source

Merge branch 'main' into js/encoder-normalization

pull/2269/head
James Jackson-South 3 years ago
parent
commit
e58f29213f
  1. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs
  2. 37
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs
  3. 10
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
  4. 5
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
  5. 2
      src/ImageSharp/Formats/Tiff/README.md
  6. 17
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  7. 12
      tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs
  8. 2
      tests/ImageSharp.Tests/TestImages.cs
  9. 3
      tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_Cmyk_Rgba32_Cmyk.png
  10. 3
      tests/Images/Input/Tiff/Cmyk.tiff

6
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs

@ -22,7 +22,7 @@ internal class CieLabTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
TPixel color = default;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -31,8 +31,8 @@ internal class CieLabTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
float l = (data[offset] & 0xFF) * 100f * Inv255;
var lab = new CieLab(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]);
var rgb = ColorSpaceConverter.ToRgb(lab);
CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]);
Rgb rgb = ColorSpaceConverter.ToRgb(lab);
color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;

37
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs

@ -0,0 +1,37 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
internal class CmykTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private const float Inv255 = 1 / 255.0f;
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
TPixel color = default;
int offset = 0;
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
for (int x = 0; x < pixelRow.Length; x++)
{
Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255);
Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk);
color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;
offset += 4;
}
}
}
}

10
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs

@ -402,6 +402,16 @@ internal static class TiffColorDecoderFactory<TPixel>
"bitsPerSample");
return new CieLabTiffColor<TPixel>();
case TiffColorType.Cmyk:
DebugGuard.IsTrue(
bitsPerSample.Channels == 4
&& bitsPerSample.Channel3 == 8
&& bitsPerSample.Channel2 == 8
&& bitsPerSample.Channel1 == 8
&& bitsPerSample.Channel0 == 8,
"bitsPerSample");
return new CmykTiffColor<TPixel>();
default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString());
}

5
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs

@ -287,4 +287,9 @@ internal enum TiffColorType
/// The pixels are stored in CieLab format as planar.
/// </summary>
CieLabPlanar,
/// <summary>
/// The pixels are stored as CMYK.
/// </summary>
Cmyk,
}

2
src/ImageSharp/Formats/Tiff/README.md

@ -54,7 +54,7 @@
|Rgb (Planar) | | Y | General implementation only. |
|PaletteColor | Y | Y | General implementation only. |
|TransparencyMask | | | |
|Separated (TIFF Extension) | | | |
|Separated (TIFF Extension) | | Y | |
|YCbCr (TIFF Extension) | | Y | |
|CieLab (TIFF Extension) | | Y | |
|IccLab (TechNote 1) | | | |

17
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

@ -413,6 +413,23 @@ internal static class TiffDecoderOptionsParser
break;
}
case TiffPhotometricInterpretation.Separated:
{
if (options.BitsPerSample.Channels != 4)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported for CMYK images.");
}
ushort bitsPerChannel = options.BitsPerSample.Channel0;
if (bitsPerChannel != 8)
{
TiffThrowHelper.ThrowNotSupported("Only 8 bits per channel is supported for CMYK images.");
}
options.ColorType = TiffColorType.Cmyk;
break;
}
default:
{
TiffThrowHelper.ThrowNotSupported($"The specified TIFF photometric interpretation is not supported: {options.PhotometricInterpretation}");

12
tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs

@ -330,6 +330,18 @@ public class TiffDecoderTests : TiffDecoderBaseTester
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
[Theory]
[WithFile(Cmyk, PixelTypes.Rgba32)]
public void TiffDecoder_CanDecode_Cmyk<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
// Note: The image from MagickReferenceDecoder does not look right, maybe we are doing something wrong
// converting the pixel data from Magick.NET to our format with CMYK?
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider);
image.CompareToReferenceOutput(ImageComparer.Exact, provider);
}
[Theory]
[WithFile(FlowerRgb101010Contiguous, PixelTypes.Rgba32)]
[WithFile(FlowerRgb101010Planar, PixelTypes.Rgba32)]

2
tests/ImageSharp.Tests/TestImages.cs

@ -936,6 +936,8 @@ public static class TestImages
public const string CieLabPlanar = "Tiff/CieLabPlanar.tiff";
public const string CieLabLzwPredictor = "Tiff/CieLab_lzwcompressed_predictor.tiff";
public const string Cmyk = "Tiff/Cmyk.tiff";
public const string Issues1716Rgb161616BitLittleEndian = "Tiff/Issues/Issue1716.tiff";
public const string Issues1891 = "Tiff/Issues/Issue1891.tiff";
public const string Issues2123 = "Tiff/Issues/Issue2123.tiff";

3
tests/Images/External/ReferenceOutput/TiffDecoderTests/TiffDecoder_CanDecode_Cmyk_Rgba32_Cmyk.png

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

3
tests/Images/Input/Tiff/Cmyk.tiff

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