Browse Source

Add support for decoding tiff images with CieLab color space

pull/2127/head
Brian Popow 4 years ago
parent
commit
0b7705c60f
  1. 46
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs
  2. 15
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorDecoderFactory{TPixel}.cs
  3. 7
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/TiffColorType.cs
  4. 3
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs
  5. 20
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

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

@ -0,0 +1,46 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
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
{
/// <summary>
/// Implements decoding pixel data with photometric interpretation of type 'CieLab'.
/// </summary>
internal class CieLabTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly ColorSpaceConverter colorSpaceConverter = new();
private const float Inv255 = 1.0f / 255.0f;
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
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++)
{
float l = (data[offset] & 0xFF) * 100f * Inv255;
var lab = new CieLab(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]);
var rgb = this.colorSpaceConverter.ToRgb(lab);
color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;
offset += 3;
}
}
}
}
}

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

@ -385,8 +385,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
return new PaletteTiffColor<TPixel>(bitsPerSample, colorMap); return new PaletteTiffColor<TPixel>(bitsPerSample, colorMap);
case TiffColorType.YCbCr: case TiffColorType.YCbCr:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
&& bitsPerSample.Channel2 == 8
&& bitsPerSample.Channel1 == 8
&& bitsPerSample.Channel0 == 8,
"bitsPerSample");
return new YCbCrTiffColor<TPixel>(memoryAllocator, referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling); return new YCbCrTiffColor<TPixel>(memoryAllocator, referenceBlackAndWhite, ycbcrCoefficients, ycbcrSubSampling);
case TiffColorType.CieLab:
DebugGuard.IsTrue(
bitsPerSample.Channels == 3
&& bitsPerSample.Channel2 == 8
&& bitsPerSample.Channel1 == 8
&& bitsPerSample.Channel0 == 8,
"bitsPerSample");
return new CieLabTiffColor<TPixel>();
default: default:
throw TiffThrowHelper.InvalidColorType(colorType.ToString()); throw TiffThrowHelper.InvalidColorType(colorType.ToString());
} }

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

@ -276,6 +276,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
/// <summary> /// <summary>
/// The pixels are stored in YCbCr format as planar. /// The pixels are stored in YCbCr format as planar.
/// </summary> /// </summary>
YCbCrPlanar YCbCrPlanar,
/// <summary>
/// The pixels are stored in CieLab format.
/// </summary>
CieLab,
} }
} }

3
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs

@ -9,6 +9,9 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation
{ {
/// <summary>
/// Implements decoding pixel data with photometric interpretation of type 'YCbCr'.
/// </summary>
internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel> internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {

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

@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
options.ColorMap = exifProfile.GetValue(ExifTag.ColorMap)?.Value; options.ColorMap = exifProfile.GetValue(ExifTag.ColorMap)?.Value;
if (options.BitsPerSample.Channels != 3) if (options.BitsPerSample.Channels != 3)
{ {
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported."); TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported for YCbCr images.");
} }
ushort bitsPerChannel = options.BitsPerSample.Channel0; ushort bitsPerChannel = options.BitsPerSample.Channel0;
@ -395,6 +395,24 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break; break;
} }
case TiffPhotometricInterpretation.CieLab:
{
options.ColorType = TiffColorType.CieLab;
if (options.BitsPerSample.Channels != 3)
{
TiffThrowHelper.ThrowNotSupported("The number of samples in the TIFF BitsPerSample entry is not supported for CieLab images.");
}
ushort bitsPerChannel = options.BitsPerSample.Channel0;
if (bitsPerChannel != 8)
{
TiffThrowHelper.ThrowNotSupported("Only 8 bits per channel is supported for CieLab images.");
}
break;
}
default: default:
{ {
TiffThrowHelper.ThrowNotSupported($"The specified TIFF photometric interpretation is not supported: {options.PhotometricInterpretation}"); TiffThrowHelper.ThrowNotSupported($"The specified TIFF photometric interpretation is not supported: {options.PhotometricInterpretation}");

Loading…
Cancel
Save