Browse Source

Allow skipping Tiff metadata

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

Loading…
Cancel
Save