Browse Source

Add support for undoing horizontal prediction: Works with deflate, still some issue with lzw

pull/1457/head
Brian Popow 5 years ago
parent
commit
52d30c24cd
  1. 10
      src/ImageSharp/Formats/Tiff/Constants/TiffPlanarConfiguration.cs
  2. 9
      src/ImageSharp/Formats/Tiff/README.md
  3. 30
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  4. 6
      src/ImageSharp/Formats/Tiff/TiffDecoderHelpers.cs
  5. 10
      tests/ImageSharp.Tests/TestImages.cs
  6. 0
      tests/Images/Input/Tiff/rgb_lzw_predictor.tiff

10
src/ImageSharp/Formats/Tiff/Constants/TiffPlanarConfiguration.cs

@ -10,11 +10,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
{
/// <summary>
/// Chunky format.
/// The component values for each pixel are stored contiguously.
/// The order of the components within the pixel is specified by
/// PhotometricInterpretation. For example, for RGB data, the data is stored as RGBRGBRGB.
/// </summary>
Chunky = 1,
/// <summary>
/// Planar format.
/// The components are stored in separate “component planes.” The
/// values in StripOffsets and StripByteCounts are then arranged as a 2-dimensional
/// array, with SamplesPerPixel rows and StripsPerImage columns. (All of the columns
/// for row 0 are stored first, followed by the columns of row 1, and so on.)
/// PhotometricInterpretation describes the type of data stored in each component
/// plane. For example, RGB data is stored with the Red components in one component
/// plane, the Green in another, and the Blue in another.
/// </summary>
Planar = 2
}

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

@ -25,6 +25,15 @@
## Implementation Status
### Know issue which need to be fixed
Decoder:
- Decoding HUffman RLE for `Calliphora_huffman_rle.tiff` has 4 pixels difference to the reference decoder. Al those are at the very edge of the image (reason unknown so far).
- Decoding compressed images with HorizontalPrediction: Works for deflate, but not for lzw.
Encoder:
- Encoding image with a palette have a difference of 0.0043% to the ReferenceDecoder (ImageMagick)
### Deviations from the TIFF spec (to be fixed)
- Decoder

30
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -240,6 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
var coreMetadata = new ImageFrameMetadata();
frameMetaData = coreMetadata.GetTiffMetadata();
frameMetaData.Tags = tags;
TiffFrameMetadata tiffFormatMetaData = coreMetadata.GetFormatMetadata(TiffFormat.Instance);
this.VerifyAndParseOptions(frameMetaData);
@ -260,9 +261,38 @@ namespace SixLabors.ImageSharp.Formats.Tiff
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, width);
}
if (tiffFormatMetaData.Predictor == TiffPredictor.Horizontal)
{
this.UndoHorizontalPredictor(width, height, frame);
}
return frame;
}
private void UndoHorizontalPredictor<TPixel>(int width, int height, ImageFrame<TPixel> frame)
where TPixel : unmanaged, IPixel<TPixel>
{
using System.Buffers.IMemoryOwner<Rgb24> rowRgbBuffer = this.memoryAllocator.Allocate<Rgb24>(width);
System.Span<Rgb24> rowRgb = rowRgbBuffer.GetSpan();
for (int y = 0; y < height; y++)
{
System.Span<TPixel> pixelRow = frame.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.ToRgb24(this.configuration, pixelRow, rowRgb);
byte r = rowRgb[0].R;
byte g = rowRgb[0].G;
byte b = rowRgb[0].B;
for (int x = 1; x < width; x++)
{
ref TPixel pixel = ref pixelRow[x];
r += rowRgb[x].R;
g += rowRgb[x].G;
b += rowRgb[x].B;
var rgb = new Rgb24(r, g, b);
pixel.FromRgb24(rgb);
}
}
}
/// <summary>
/// Calculates the size (in bytes) for a pixel buffer using the determined color format.
/// </summary>

6
src/ImageSharp/Formats/Tiff/TiffDecoderHelpers.cs

@ -106,9 +106,9 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowNotSupported("The Tile images is not supported.");
}
if (entries.Predictor != TiffPredictor.None)
if (entries.Predictor == TiffPredictor.FloatingPoint)
{
TiffThrowHelper.ThrowNotSupported("At the moment we support only None Predictor images.");
TiffThrowHelper.ThrowNotSupported("ImageSharp does not support FloatingPoint Predictor images.");
}
if (entries.SampleFormat != null)
@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
if (format != TiffSampleFormat.UnsignedInteger)
{
TiffThrowHelper.ThrowNotSupported("At the moment support only UnsignedInteger SampleFormat.");
TiffThrowHelper.ThrowNotSupported("ImageSharp only supports the UnsignedInteger SampleFormat.");
}
}
}

10
tests/ImageSharp.Tests/TestImages.cs

@ -529,7 +529,7 @@ namespace SixLabors.ImageSharp.Tests
public const string RgbDeflate_Predictor = "Tiff/rgb_deflate.tiff";
public const string RgbDeflateMultistrip = "Tiff/rgb_deflate_multistrip.tiff";
public const string RgbJpeg = "Tiff/rgb_jpeg.tiff";
public const string RgbLzw_Predictor = "Tiff/rgb_lzw.tiff";
public const string RgbLzw_Predictor = "Tiff/rgb_lzw_predictor.tiff";
public const string RgbLzw_NoPredictor_Multistrip = "Tiff/rgb_lzw_noPredictor_multistrip.tiff";
public const string RgbLzw_NoPredictor_Multistrip_Motorola = "Tiff/rgb_lzw_noPredictor_multistrip_Motorola.tiff";
public const string RgbLzw_NoPredictor_Singlestrip_Motorola = "Tiff/rgb_lzw_noPredictor_singlestrip_Motorola.tiff";
@ -553,10 +553,12 @@ namespace SixLabors.ImageSharp.Tests
public static readonly string[] All =
{
Calliphora_PaletteUncompressed, /*Calliphora_RgbDeflate_Predictor, Calliphora_RgbLzwe_Predictor, */ Calliphora_RgbPackbits,
Calliphora_PaletteUncompressed, Calliphora_RgbPackbits,
Calliphora_GrayscaleDeflate_Predictor, Calliphora_RgbDeflate_Predictor, RgbDeflate_Predictor,
Calliphora_RgbLzw_Predictor, RgbLzw_Predictor, // TODO: Undoing the horizontal prediction seems to fail for lzw. Do we need to do something different for lzw?
Calliphora_BiColor, Calliphora_RgbUncompressed, Calliphora_HuffmanCompressed, Calliphora_Fax3Compressed, CcittFax3AllTermCodes, CcittFax3AllMakeupCodes,
HuffmanRleAllTermCodes, HuffmanRleAllMakeupCodes, GrayscaleDeflateMultistrip, Calliphora_GrayscaleDeflate, Calliphora_GrayscaleUncompressed,
GrayscaleUncompressed, PaletteDeflateMultistrip, PaletteUncompressed, /*RgbDeflate_Predictor,*/ RgbDeflateMultistrip, /*RgbJpeg,*/ /*RgbLzw_Predictor, RgbLzwMultistrip_Predictor,*/
GrayscaleUncompressed, PaletteDeflateMultistrip, PaletteUncompressed, RgbDeflateMultistrip, /*RgbJpeg,*/ /* RgbLzwMultistrip_Predictor,*/
RgbLzw_NoPredictor_Multistrip, RgbLzw_NoPredictor_Multistrip_Motorola, RgbLzw_NoPredictor_Singlestrip_Motorola, RgbPackbits, RgbPackbitsMultistrip, RgbUncompressed,
/* MultiframeLzw_Predictor, MultiFrameDifferentVariants, SampleMetadata,*/ SmallRgbDeflate, SmallRgbLzw,
};
@ -565,7 +567,7 @@ namespace SixLabors.ImageSharp.Tests
public static readonly string[] Metadata = { SampleMetadata };
public static readonly string[] NotSupported = { Calliphora_GrayscaleDeflate_Predictor, Calliphora_RgbJpeg, Calliphora_RgbDeflate_Predictor, Calliphora_RgbLzw_Predictor, RgbDeflate_Predictor, RgbLzw_Predictor, RgbLzwMultistrip_Predictor, RgbJpeg, RgbUncompressedTiled, MultiframeLzw_Predictor, MultiframeDifferentSize, MultiframeDifferentVariants };
public static readonly string[] NotSupported = { Calliphora_RgbJpeg, RgbLzwMultistrip_Predictor, RgbJpeg, RgbUncompressedTiled, MultiframeLzw_Predictor, MultiframeDifferentSize, MultiframeDifferentVariants };
}
}
}

0
tests/Images/Input/Tiff/rgb_lzw.tiff → tests/Images/Input/Tiff/rgb_lzw_predictor.tiff

Loading…
Cancel
Save