Browse Source

Allow skipping Tiff metadata

pull/2269/head
James Jackson-South 4 years ago
parent
commit
37d4ed23b5
  1. 8
      src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs
  2. 153
      src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs

8
src/ImageSharp/Formats/Tiff/TiffEncoderCore.cs

@ -73,6 +73,11 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
/// </summary> /// </summary>
private const TiffPhotometricInterpretation DefaultPhotometricInterpretation = TiffPhotometricInterpretation.Rgb; private const TiffPhotometricInterpretation DefaultPhotometricInterpretation = TiffPhotometricInterpretation.Rgb;
/// <summary>
/// Whether to skip metadata during encoding.
/// </summary>
private readonly bool skipMetadata;
private readonly List<(long, uint)> frameMarkers = new(); private readonly List<(long, uint)> frameMarkers = new();
/// <summary> /// <summary>
@ -90,6 +95,7 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
this.HorizontalPredictor = options.HorizontalPredictor; this.HorizontalPredictor = options.HorizontalPredictor;
this.CompressionType = options.Compression; this.CompressionType = options.Compression;
this.compressionLevel = options.CompressionLevel ?? DeflateCompressionLevel.DefaultCompression; this.compressionLevel = options.CompressionLevel ?? DeflateCompressionLevel.DefaultCompression;
this.skipMetadata = options.SkipMetadata;
} }
/// <summary> /// <summary>
@ -232,7 +238,7 @@ internal sealed class TiffEncoderCore : IImageEncoderInternals
if (image != null) if (image != null)
{ {
entriesCollector.ProcessMetadata(image); entriesCollector.ProcessMetadata(image, this.skipMetadata);
} }
entriesCollector.ProcessFrameInfo(frame, imageMetadata); entriesCollector.ProcessFrameInfo(frame, imageMetadata);

153
src/ImageSharp/Formats/Tiff/TiffEncoderEntriesCollector.cs

@ -15,8 +15,8 @@ internal class TiffEncoderEntriesCollector
public List<IExifValue> Entries { get; } = new List<IExifValue>(); public List<IExifValue> Entries { get; } = new List<IExifValue>();
public void ProcessMetadata(Image image) public void ProcessMetadata(Image image, bool skipMetadata)
=> new MetadataProcessor(this).Process(image); => new MetadataProcessor(this).Process(image, skipMetadata);
public void ProcessFrameInfo(ImageFrame frame, ImageMetadata imageMetadata) public void ProcessFrameInfo(ImageFrame frame, ImageMetadata imageMetadata)
=> new FrameInfoProcessor(this).Process(frame, imageMetadata); => new FrameInfoProcessor(this).Process(frame, imageMetadata);
@ -41,7 +41,7 @@ internal class TiffEncoderEntriesCollector
private abstract class BaseProcessor private abstract class BaseProcessor
{ {
public BaseProcessor(TiffEncoderEntriesCollector collector) => this.Collector = collector; protected BaseProcessor(TiffEncoderEntriesCollector collector) => this.Collector = collector;
protected TiffEncoderEntriesCollector Collector { get; } protected TiffEncoderEntriesCollector Collector { get; }
} }
@ -53,14 +53,18 @@ internal class TiffEncoderEntriesCollector
{ {
} }
public void Process(Image image) public void Process(Image image, bool skipMetadata)
{ {
ImageFrame rootFrame = image.Frames.RootFrame; ImageFrame rootFrame = image.Frames.RootFrame;
ExifProfile rootFrameExifProfile = rootFrame.Metadata.ExifProfile ?? new ExifProfile(); ExifProfile rootFrameExifProfile = rootFrame.Metadata.ExifProfile;
XmpProfile rootFrameXmpProfile = rootFrame.Metadata.XmpProfile; XmpProfile rootFrameXmpProfile = rootFrame.Metadata.XmpProfile;
this.ProcessProfiles(image.Metadata, rootFrameExifProfile, rootFrameXmpProfile); this.ProcessProfiles(image.Metadata, skipMetadata, rootFrameExifProfile, rootFrameXmpProfile);
this.ProcessMetadata(rootFrameExifProfile);
if (!skipMetadata)
{
this.ProcessMetadata(rootFrameExifProfile ?? new ExifProfile());
}
if (!this.Collector.Entries.Exists(t => t.Tag == ExifTag.Software)) if (!this.Collector.Entries.Exists(t => t.Tag == ExifTag.Software))
{ {
@ -72,39 +76,35 @@ internal class TiffEncoderEntriesCollector
} }
private static bool IsPureMetadata(ExifTag tag) private static bool IsPureMetadata(ExifTag tag)
{ => (ExifTagValue)(ushort)tag switch
switch ((ExifTagValue)(ushort)tag)
{ {
case ExifTagValue.DocumentName: ExifTagValue.DocumentName or
case ExifTagValue.ImageDescription: ExifTagValue.ImageDescription or
case ExifTagValue.Make: ExifTagValue.Make or
case ExifTagValue.Model: ExifTagValue.Model or
case ExifTagValue.Software: ExifTagValue.Software or
case ExifTagValue.DateTime: ExifTagValue.DateTime or
case ExifTagValue.Artist: ExifTagValue.Artist or
case ExifTagValue.HostComputer: ExifTagValue.HostComputer or
case ExifTagValue.TargetPrinter: ExifTagValue.TargetPrinter or
case ExifTagValue.XMP: ExifTagValue.XMP or
case ExifTagValue.Rating: ExifTagValue.Rating or
case ExifTagValue.RatingPercent: ExifTagValue.RatingPercent or
case ExifTagValue.ImageID: ExifTagValue.ImageID or
case ExifTagValue.Copyright: ExifTagValue.Copyright or
case ExifTagValue.MDLabName: ExifTagValue.MDLabName or
case ExifTagValue.MDSampleInfo: ExifTagValue.MDSampleInfo or
case ExifTagValue.MDPrepDate: ExifTagValue.MDPrepDate or
case ExifTagValue.MDPrepTime: ExifTagValue.MDPrepTime or
case ExifTagValue.MDFileUnits: ExifTagValue.MDFileUnits or
case ExifTagValue.SEMInfo: ExifTagValue.SEMInfo or
case ExifTagValue.XPTitle: ExifTagValue.XPTitle or
case ExifTagValue.XPComment: ExifTagValue.XPComment or
case ExifTagValue.XPAuthor: ExifTagValue.XPAuthor or
case ExifTagValue.XPKeywords: ExifTagValue.XPKeywords or
case ExifTagValue.XPSubject: ExifTagValue.XPSubject => true,
return true; _ => false,
default: };
return false;
}
}
private void ProcessMetadata(ExifProfile exifProfile) private void ProcessMetadata(ExifProfile exifProfile)
{ {
@ -149,9 +149,9 @@ internal class TiffEncoderEntriesCollector
} }
} }
private void ProcessProfiles(ImageMetadata imageMetadata, ExifProfile exifProfile, XmpProfile xmpProfile) private void ProcessProfiles(ImageMetadata imageMetadata, bool skipMetadata, ExifProfile exifProfile, XmpProfile xmpProfile)
{ {
if (exifProfile != null && exifProfile.Parts != ExifParts.None) if (!skipMetadata && (exifProfile != null && exifProfile.Parts != ExifParts.None))
{ {
foreach (IExifValue entry in exifProfile.Values) foreach (IExifValue entry in exifProfile.Values)
{ {
@ -167,13 +167,13 @@ internal class TiffEncoderEntriesCollector
} }
else else
{ {
exifProfile.RemoveValue(ExifTag.SubIFDOffset); exifProfile?.RemoveValue(ExifTag.SubIFDOffset);
} }
if (imageMetadata.IptcProfile != null) if (!skipMetadata && imageMetadata.IptcProfile != null)
{ {
imageMetadata.IptcProfile.UpdateData(); imageMetadata.IptcProfile.UpdateData();
var iptc = new ExifByteArray(ExifTagValue.IPTC, ExifDataType.Byte) ExifByteArray iptc = new(ExifTagValue.IPTC, ExifDataType.Byte)
{ {
Value = imageMetadata.IptcProfile.Data Value = imageMetadata.IptcProfile.Data
}; };
@ -182,12 +182,12 @@ internal class TiffEncoderEntriesCollector
} }
else else
{ {
exifProfile.RemoveValue(ExifTag.IPTC); exifProfile?.RemoveValue(ExifTag.IPTC);
} }
if (imageMetadata.IccProfile != null) if (imageMetadata.IccProfile != null)
{ {
var icc = new ExifByteArray(ExifTagValue.IccProfile, ExifDataType.Undefined) ExifByteArray icc = new(ExifTagValue.IccProfile, ExifDataType.Undefined)
{ {
Value = imageMetadata.IccProfile.ToByteArray() Value = imageMetadata.IccProfile.ToByteArray()
}; };
@ -196,12 +196,12 @@ internal class TiffEncoderEntriesCollector
} }
else else
{ {
exifProfile.RemoveValue(ExifTag.IccProfile); exifProfile?.RemoveValue(ExifTag.IccProfile);
} }
if (xmpProfile != null) if (!skipMetadata && xmpProfile != null)
{ {
var xmp = new ExifByteArray(ExifTagValue.XMP, ExifDataType.Byte) ExifByteArray xmp = new(ExifTagValue.XMP, ExifDataType.Byte)
{ {
Value = xmpProfile.Data Value = xmpProfile.Data
}; };
@ -210,7 +210,7 @@ internal class TiffEncoderEntriesCollector
} }
else else
{ {
exifProfile.RemoveValue(ExifTag.XMP); exifProfile?.RemoveValue(ExifTag.XMP);
} }
} }
} }
@ -273,29 +273,29 @@ internal class TiffEncoderEntriesCollector
public void Process(TiffEncoderCore encoder) public void Process(TiffEncoderCore encoder)
{ {
var planarConfig = new ExifShort(ExifTagValue.PlanarConfiguration) ExifShort planarConfig = new(ExifTagValue.PlanarConfiguration)
{ {
Value = (ushort)TiffPlanarConfiguration.Chunky Value = (ushort)TiffPlanarConfiguration.Chunky
}; };
var samplesPerPixel = new ExifLong(ExifTagValue.SamplesPerPixel) ExifLong samplesPerPixel = new(ExifTagValue.SamplesPerPixel)
{ {
Value = GetSamplesPerPixel(encoder) Value = GetSamplesPerPixel(encoder)
}; };
ushort[] bitsPerSampleValue = GetBitsPerSampleValue(encoder); ushort[] bitsPerSampleValue = GetBitsPerSampleValue(encoder);
var bitPerSample = new ExifShortArray(ExifTagValue.BitsPerSample) ExifShortArray bitPerSample = new(ExifTagValue.BitsPerSample)
{ {
Value = bitsPerSampleValue Value = bitsPerSampleValue
}; };
ushort compressionType = GetCompressionType(encoder); ushort compressionType = GetCompressionType(encoder);
var compression = new ExifShort(ExifTagValue.Compression) ExifShort compression = new(ExifTagValue.Compression)
{ {
Value = compressionType Value = compressionType
}; };
var photometricInterpretation = new ExifShort(ExifTagValue.PhotometricInterpretation) ExifShort photometricInterpretation = new(ExifTagValue.PhotometricInterpretation)
{ {
Value = (ushort)encoder.PhotometricInterpretation Value = (ushort)encoder.PhotometricInterpretation
}; };
@ -306,32 +306,25 @@ internal class TiffEncoderEntriesCollector
this.Collector.AddOrReplace(compression); this.Collector.AddOrReplace(compression);
this.Collector.AddOrReplace(photometricInterpretation); this.Collector.AddOrReplace(photometricInterpretation);
if (encoder.HorizontalPredictor == TiffPredictor.Horizontal) if (encoder.HorizontalPredictor == TiffPredictor.Horizontal &&
(encoder.PhotometricInterpretation is TiffPhotometricInterpretation.Rgb or
TiffPhotometricInterpretation.PaletteColor or
TiffPhotometricInterpretation.BlackIsZero))
{ {
if (encoder.PhotometricInterpretation == TiffPhotometricInterpretation.Rgb || ExifShort predictor = new(ExifTagValue.Predictor) { Value = (ushort)TiffPredictor.Horizontal };
encoder.PhotometricInterpretation == TiffPhotometricInterpretation.PaletteColor ||
encoder.PhotometricInterpretation == TiffPhotometricInterpretation.BlackIsZero)
{
var predictor = new ExifShort(ExifTagValue.Predictor) { Value = (ushort)TiffPredictor.Horizontal };
this.Collector.AddOrReplace(predictor); this.Collector.AddOrReplace(predictor);
}
} }
} }
private static uint GetSamplesPerPixel(TiffEncoderCore encoder) private static uint GetSamplesPerPixel(TiffEncoderCore encoder)
{ => encoder.PhotometricInterpretation switch
switch (encoder.PhotometricInterpretation)
{ {
case TiffPhotometricInterpretation.PaletteColor: TiffPhotometricInterpretation.PaletteColor or
case TiffPhotometricInterpretation.BlackIsZero: TiffPhotometricInterpretation.BlackIsZero or
case TiffPhotometricInterpretation.WhiteIsZero: TiffPhotometricInterpretation.WhiteIsZero => 1,
return 1; _ => 3,
case TiffPhotometricInterpretation.Rgb: };
default:
return 3;
}
}
private static ushort[] GetBitsPerSampleValue(TiffEncoderCore encoder) private static ushort[] GetBitsPerSampleValue(TiffEncoderCore encoder)
{ {
@ -342,10 +335,8 @@ internal class TiffEncoderEntriesCollector
{ {
return TiffConstants.BitsPerSample4Bit.ToArray(); return TiffConstants.BitsPerSample4Bit.ToArray();
} }
else
{ return TiffConstants.BitsPerSample8Bit.ToArray();
return TiffConstants.BitsPerSample8Bit.ToArray();
}
case TiffPhotometricInterpretation.Rgb: case TiffPhotometricInterpretation.Rgb:
return TiffConstants.BitsPerSampleRgb8Bit.ToArray(); return TiffConstants.BitsPerSampleRgb8Bit.ToArray();
@ -382,9 +373,9 @@ internal class TiffEncoderEntriesCollector
// PackBits is allowed for all modes. // PackBits is allowed for all modes.
return (ushort)TiffCompression.PackBits; return (ushort)TiffCompression.PackBits;
case TiffCompression.Lzw: case TiffCompression.Lzw:
if (encoder.PhotometricInterpretation == TiffPhotometricInterpretation.Rgb || if (encoder.PhotometricInterpretation is TiffPhotometricInterpretation.Rgb or
encoder.PhotometricInterpretation == TiffPhotometricInterpretation.PaletteColor || TiffPhotometricInterpretation.PaletteColor or
encoder.PhotometricInterpretation == TiffPhotometricInterpretation.BlackIsZero) TiffPhotometricInterpretation.BlackIsZero)
{ {
return (ushort)TiffCompression.Lzw; return (ushort)TiffCompression.Lzw;
} }

Loading…
Cancel
Save