Browse Source

Correct read Long8 tags

pull/1760/head
Ildar Khayrutdinov 5 years ago
parent
commit
c6383861d2
  1. 18
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  2. 28
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  3. 128
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs

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

@ -211,16 +211,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff
var frame = new ImageFrame<TPixel>(this.Configuration, width, height, imageFrameMetaData);
int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;
Number[] stripOffsets = tags.GetValue(ExifTag.StripOffsets)?.Value;
Number[] stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value;
ExifLong8Array stripOffsets = tags.GetValueInternal(ExifTag.StripOffsets) as ExifLong8Array;
ExifLong8Array stripByteCounts = tags.GetValueInternal(ExifTag.StripByteCounts) as ExifLong8Array;
if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
{
this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken);
this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets.Value, stripByteCounts.Value, cancellationToken);
}
else
{
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken);
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets.Value, stripByteCounts.Value, cancellationToken);
}
return frame;
@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param>
/// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken)
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, ulong[] stripOffsets, ulong[] stripByteCounts, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
int stripsPerPixel = this.BitsPerSample.Channels;
@ -329,8 +329,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
decompressor.Decompress(
this.inputStream,
(uint)stripOffsets[stripIndex],
(uint)stripByteCounts[stripIndex],
stripOffsets[stripIndex],
stripByteCounts[stripIndex],
stripHeight,
stripBuffers[planeIndex].GetSpan());
stripIndex += stripsPerPlane;
@ -357,7 +357,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="stripOffsets">The strip offsets.</param>
/// <param name="stripByteCounts">The strip byte counts.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken)
private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, ulong[] stripOffsets, ulong[] stripByteCounts, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
// If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip.
@ -413,7 +413,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break;
}
decompressor.Decompress(this.inputStream, (uint)stripOffsets[stripIndex], (uint)stripByteCounts[stripIndex], stripHeight, stripBufferSpan);
decompressor.Decompress(this.inputStream, stripOffsets[stripIndex], stripByteCounts[stripIndex], stripHeight, stripBufferSpan);
colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight);
}

28
src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs

@ -420,8 +420,34 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
// The StripOffsets, StripByteCounts, TileOffsets, and TileByteCounts tags are allowed to have the datatype TIFF_LONG8 in BigTIFF.
// Old datatypes TIFF_LONG, and TIFF_SHORT where allowed in the TIFF 6.0 specification, are still valid in BigTIFF, too.
// Likewise, tags that point to other IFDs, like e.g. the SubIFDs tag, are now allowed to have the datatype TIFF_IFD8 in BigTIFF.
// Again, the old datatypes TIFF_IFD, and the hardly recommendable TIFF_LONG, are still valid, too.
// https://www.awaresystems.be/imaging/tiff/bigtiff.html
ExifValue exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents);
ExifValue exifValue = null;
switch (tag)
{
case ExifTagValue.StripOffsets:
exifValue = new ExifLong8Array(ExifTagValue.StripOffsets);
break;
case ExifTagValue.StripByteCounts:
exifValue = new ExifLong8Array(ExifTagValue.StripByteCounts);
break;
case ExifTagValue.TileOffsets:
exifValue = new ExifLong8Array(ExifTagValue.TileOffsets);
break;
case ExifTagValue.TileByteCounts:
exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts);
break;
//case ExifTagValue.SubIFDOffset:
// exifValue = new ExifLong8Array(ExifTagValue.SubIFDOffset);
// break;
//case ExifTagValue.GPSIFDOffset:
// exifValue = new ExifLong8Array(ExifTagValue.GPSIFDOffset);
// break;
default:
exifValue = exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents);
break;
}
if (exifValue is null)
{

128
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs

@ -20,8 +20,134 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
}
public override ExifDataType DataType => ExifDataType.Long8;
public override ExifDataType DataType
{
get
{
if (this.Value is null)
{
return ExifDataType.Long;
}
for (int i = 0; i < this.Value.Length; i++)
{
if (this.Value[i] > uint.MaxValue)
{
return ExifDataType.Long8;
}
}
return ExifDataType.Long;
}
}
public override bool TrySetValue(object value)
{
if (base.TrySetValue(value))
{
return true;
}
switch (value)
{
case int val:
return this.SetSingle((ulong)val);
case uint val:
return this.SetSingle((ulong)val);
case short val:
return this.SetSingle((ulong)val);
case ushort val:
return this.SetSingle((ulong)val);
case long[] array:
return this.SetArray(array);
case ulong[] array:
return this.SetArray(array);
case int[] array:
return this.SetArray(array);
case uint[] array:
return this.SetArray(array);
case short[] array:
return this.SetArray(array);
case ushort[] array:
return this.SetArray(array);
}
return false;
}
public override IExifValue DeepClone() => new ExifLong8Array(this);
private bool SetSingle(ulong value)
{
this.Value = new[] { value };
return true;
}
private bool SetArray(long[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
private bool SetArray(ulong[] values)
{
this.Value = values;
return true;
}
private bool SetArray(int[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
private bool SetArray(uint[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
private bool SetArray(short[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
private bool SetArray(ushort[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
}
}

Loading…
Cancel
Save