diff --git a/Directory.Build.targets b/Directory.Build.targets index 01c1f1039..f6523fee0 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -22,18 +22,19 @@ - - + + + - + diff --git a/README.md b/README.md index 28c377037..a1c9bca99 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Core Team - [Dirk Lemstra](https://github.com/dlemstra) - [Anton Firsov](https://github.com/antonfirsov) - [Scott Williams](https://github.com/tocsoft) +- [Brian Popow](https://github.com/brianpopow) ### Backers diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index e217fd9a6..e1dbefdb6 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -60,10 +60,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing public float Opacity { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixelBg : struct, IPixel { - var visitor = new ProcessorFactoryVisitor(this, source, sourceRectangle); + var visitor = new ProcessorFactoryVisitor(configuration, this, source, sourceRectangle); this.Image.AcceptVisitor(visitor); return visitor.Result; } @@ -71,12 +71,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing private class ProcessorFactoryVisitor : IImageVisitor where TPixelBg : struct, IPixel { + private readonly Configuration configuration; private readonly DrawImageProcessor definition; private readonly Image source; private readonly Rectangle sourceRectangle; - public ProcessorFactoryVisitor(DrawImageProcessor definition, Image source, Rectangle sourceRectangle) + public ProcessorFactoryVisitor(Configuration configuration, DrawImageProcessor definition, Image source, Rectangle sourceRectangle) { + this.configuration = configuration; this.definition = definition; this.source = source; this.sourceRectangle = sourceRectangle; @@ -88,6 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing where TPixelFg : struct, IPixel { this.Result = new DrawImageProcessor( + this.configuration, image, this.source, this.sourceRectangle, diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index eab6b2f4a..55f72c7fc 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -22,6 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The foreground to blend with the currently processing image. /// The source for the current processor instance. /// The source area to process for the current processor instance. @@ -30,6 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// The Alpha blending mode to use when drawing the image. /// The opacity of the image to blend. Must be between 0 and 1. public DrawImageProcessor( + Configuration configuration, Image image, Image source, Rectangle sourceRectangle, @@ -37,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) - : base(source, sourceRectangle) + : base(configuration, source, sourceRectangle) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 3963f99a5..c94e0c179 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -34,10 +34,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing public GraphicsOptions Options { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new FillProcessor(this, source, sourceRectangle); - } + => new FillProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs index fc9482618..524b66e05 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs @@ -6,7 +6,6 @@ using System.Buffers; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced.ParallelUtils; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -21,8 +20,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { private readonly FillProcessor definition; - public FillProcessor(FillProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public FillProcessor(Configuration configuration, FillProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } @@ -112,7 +111,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { solidBrush = this.definition.Brush as SolidBrush; - if (solidBrush == null) + if (solidBrush is null) { return false; } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 7d51be1c5..6cfeb785c 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -42,10 +42,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing public GraphicsOptions Options { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new FillRegionProcessor(this, source, sourceRectangle); - } + => new FillRegionProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs index 4744a4e92..7d632ad23 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs @@ -23,8 +23,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { private readonly FillRegionProcessor definition; - public FillRegionProcessor(FillRegionProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public FillRegionProcessor(Configuration configuration, FillRegionProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 775cf55ab..75774a628 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -72,10 +72,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text public PointF Location { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new DrawTextProcessor(this, source, sourceRectangle); - } + => new DrawTextProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs index 64d32efb8..c47f764a2 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs @@ -27,8 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text private readonly DrawTextProcessor definition; - public DrawTextProcessor(DrawTextProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public DrawTextProcessor(Configuration configuration, DrawTextProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Common/Helpers/EnumUtils.cs b/src/ImageSharp/Common/Helpers/EnumUtils.cs new file mode 100644 index 000000000..a98b7f84c --- /dev/null +++ b/src/ImageSharp/Common/Helpers/EnumUtils.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp +{ + /// + /// Common utility methods for working with enums. + /// + internal static class EnumUtils + { + /// + /// Converts the numeric representation of the enumerated constants to an equivalent enumerated object. + /// + /// The type of enum + /// The value to parse + /// The default value to return. + /// The . + public static TEnum Parse(int value, TEnum defaultValue) + where TEnum : Enum + { + foreach (TEnum enumValue in Enum.GetValues(typeof(TEnum))) + { + TEnum current = enumValue; + if (value == Unsafe.As(ref current)) + { + return enumValue; + } + } + + return defaultValue; + } + + /// + /// Returns a value indicating whether the given enum has a flag of the given value. + /// + /// The type of enum. + /// The value. + /// The flag. + /// The . + public static bool HasFlag(TEnum value, TEnum flag) + where TEnum : Enum + { + uint flagValue = Unsafe.As(ref flag); + return (Unsafe.As(ref value) & flagValue) == flagValue; + } + } +} diff --git a/src/ImageSharp/Common/Helpers/TolerantMath.cs b/src/ImageSharp/Common/Helpers/TolerantMath.cs index bef7eb161..62b564472 100644 --- a/src/ImageSharp/Common/Helpers/TolerantMath.cs +++ b/src/ImageSharp/Common/Helpers/TolerantMath.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -103,4 +103,4 @@ namespace SixLabors.ImageSharp return Math.Floor(a); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Common/Helpers/UnitConverter.cs b/src/ImageSharp/Common/Helpers/UnitConverter.cs index 75dbb032c..9e4306170 100644 --- a/src/ImageSharp/Common/Helpers/UnitConverter.cs +++ b/src/ImageSharp/Common/Helpers/UnitConverter.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; @@ -86,9 +86,10 @@ namespace SixLabors.ImageSharp.Common.Helpers [MethodImpl(InliningOptions.ShortMethod)] public static PixelResolutionUnit ExifProfileToResolutionUnit(ExifProfile profile) { - return profile.TryGetValue(ExifTag.ResolutionUnit, out ExifValue resolution) - ? (PixelResolutionUnit)(byte)(((ushort)resolution.Value) - 1) // EXIF is 1, 2, 3 - : default; + IExifValue resolution = profile.GetValue(ExifTag.ResolutionUnit); + + // EXIF is 1, 2, 3 so we minus "1" off the result. + return resolution is null ? default : (PixelResolutionUnit)(byte)(resolution.Value - 1); } } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 60709ed00..ec9cca8c8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -465,24 +465,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } - private double GetExifResolutionValue(ExifTag tag) + private double GetExifResolutionValue(ExifTag tag) { - if (!this.Metadata.ExifProfile.TryGetValue(tag, out ExifValue exifValue)) - { - return 0; - } + IExifValue resolution = this.Metadata.ExifProfile.GetValue(tag); - switch (exifValue.DataType) - { - case ExifDataType.Rational: - return ((Rational)exifValue.Value).ToDouble(); - case ExifDataType.Long: - return (uint)exifValue.Value; - case ExifDataType.DoubleFloat: - return (double)exifValue.Value; - default: - return 0; - } + return resolution is null ? 0 : resolution.Value.ToDouble(); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index bc9bb9543..cd3c19aa3 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -647,7 +647,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// private void WriteExifProfile(ExifProfile exifProfile) { - if (exifProfile is null) + if (exifProfile is null || exifProfile.Values.Count == 0) { return; } @@ -655,9 +655,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg const int MaxBytesApp1 = 65533; // 64k - 2 padding bytes const int MaxBytesWithExifId = 65527; // Max - 6 bytes for EXIF header. - byte[] data = exifProfile?.ToByteArray(); + byte[] data = exifProfile.ToByteArray(); - if (data is null || data.Length == 0) + if (data.Length == 0) { return; } @@ -998,4 +998,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.outputStream.Write(this.buffer, 0, 4); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 82796c570..22e3f252d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -622,11 +622,13 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image metadata. private void WriteExifChunk(Stream stream, ImageMetadata meta) { - if (meta.ExifProfile?.Values.Count > 0) + if (meta.ExifProfile is null || meta.ExifProfile.Values.Count == 0) { - meta.SyncProfiles(); - this.WriteChunk(stream, PngChunkType.Exif, meta.ExifProfile.ToByteArray()); + return; } + + meta.SyncProfiles(); + this.WriteChunk(stream, PngChunkType.Exif, meta.ExifProfile.ToByteArray()); } /// diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index bfc69d1c8..1ff3bb599 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Formats.Tga throw new UnknownImageFormatException("Width or height cannot be 0"); } - var image = new Image(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); + var image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.fileHeader.ColorMapType is 1) diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 178098b7f..389fbba6d 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data) where TPixel : struct, IPixel { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data, out IImageFormat format) where TPixel : struct, IPixel { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream, out format); } @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp public static Image Load(byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(stream, decoder); } @@ -125,9 +125,9 @@ namespace SixLabors.ImageSharp public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) where TPixel : struct, IPixel { - using (var memoryStream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { - return Load(config, memoryStream, decoder); + return Load(config, stream, decoder); } } @@ -299,7 +299,7 @@ namespace SixLabors.ImageSharp /// The . public static Image Load(Configuration config, byte[] data, IImageDecoder decoder) { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream, decoder); } @@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp /// The . public static Image Load(Configuration config, byte[] data, out IImageFormat format) { - using (var stream = new MemoryStream(data)) + using (var stream = new MemoryStream(data, 0, data.Length, false, true)) { return Load(config, stream, out format); } diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index c5bd02c79..c584d2d19 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp public IEnumerator GetEnumerator() => this.NonGenericGetEnumerator(); /// - IEnumerator IEnumerable.GetEnumerator() => this.NonGenericGetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); /// /// Implements . diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 3f733479d..29184522f 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp protected override ImageFrameCollection NonGenericFrameCollection => this.Frames; /// - /// Gets the frames. + /// Gets the collection of image frames. /// public new ImageFrameCollection Frames { get; } @@ -166,8 +166,12 @@ namespace SixLabors.ImageSharp { this.EnsureNotDisposed(); - IEnumerable> clonedFrames = - this.Frames.Select, ImageFrame>(x => x.Clone(configuration)); + var clonedFrames = new ImageFrame[this.Frames.Count]; + for (int i = 0; i < clonedFrames.Length; i++) + { + clonedFrames[i] = this.Frames[i].Clone(configuration); + } + return new Image(configuration, this.Metadata.DeepClone(), clonedFrames); } @@ -181,8 +185,12 @@ namespace SixLabors.ImageSharp { this.EnsureNotDisposed(); - IEnumerable> clonedFrames = - this.Frames.Select, ImageFrame>(x => x.CloneAs(configuration)); + var clonedFrames = new ImageFrame[this.Frames.Count]; + for (int i = 0; i < clonedFrames.Length; i++) + { + clonedFrames[i] = this.Frames[i].CloneAs(configuration); + } + return new Image(configuration, this.Metadata.DeepClone(), clonedFrames); } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/DC-008-Translation-2019-E.pdf b/src/ImageSharp/Metadata/Profiles/Exif/DC-008-Translation-2019-E.pdf new file mode 100644 index 000000000..9be0c8402 Binary files /dev/null and b/src/ImageSharp/Metadata/Profiles/Exif/DC-008-Translation-2019-E.pdf differ diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs index 83e7f7fe8..74c86f721 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif @@ -20,6 +20,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL. + /// + /// Although the standard defines ASCII this has commonly been ignored as + /// ASCII cannot properly encode text in many languages. + /// /// Ascii = 2, @@ -64,13 +68,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif SignedRational = 10, /// - /// A 32-bit floating point value. + /// A 32-bit single precision floating point value. /// SingleFloat = 11, /// - /// A 64-bit floating point value. + /// A 64-bit double precision floating point value. /// DoubleFloat = 12 } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs new file mode 100644 index 000000000..d94dc5640 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs @@ -0,0 +1,45 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal static class ExifDataTypes + { + /// + /// Gets the size in bytes of the given data type. + /// + /// The data type. + /// + /// The . + /// + /// + /// Thrown if the type is unsupported. + /// + public static uint GetSize(ExifDataType dataType) + { + switch (dataType) + { + case ExifDataType.Ascii: + case ExifDataType.Byte: + case ExifDataType.SignedByte: + case ExifDataType.Undefined: + return 1; + case ExifDataType.Short: + case ExifDataType.SignedShort: + return 2; + case ExifDataType.Long: + case ExifDataType.SignedLong: + case ExifDataType.SingleFloat: + return 4; + case ExifDataType.DoubleFloat: + case ExifDataType.Rational: + case ExifDataType.SignedRational: + return 8; + default: + throw new NotSupportedException(dataType.ToString()); + } + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs index d22dc730f..6405a7ff2 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -29,11 +29,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// GPSTags /// - GPSTags = 8, + GpsTags = 8, /// /// All /// - All = IfdTags | ExifTags | GPSTags + All = IfdTags | ExifTags | GpsTags } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs index 3d90cb3a9..f98a1f3c7 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// The collection of EXIF values /// - private List values; + private List values; /// /// The thumbnail offset position in the byte stream @@ -70,9 +70,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (other.values != null) { - this.values = new List(other.Values.Count); + this.values = new List(other.Values.Count); - foreach (ExifValue value in other.Values) + foreach (IExifValue value in other.Values) { this.values.Add(value.DeepClone()); } @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// Gets the values of this EXIF profile. /// - public IReadOnlyList Values + public IReadOnlyList Values { get { @@ -138,46 +138,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// Returns the value with the specified tag. /// - /// The tag of the EXIF value. - /// - /// The . - /// - public ExifValue GetValue(ExifTag tag) - { - foreach (ExifValue exifValue in this.Values) - { - if (exifValue.Tag == tag) - { - return exifValue; - } - } - - return null; - } - - /// - /// Conditionally returns the value of the tag if it exists. - /// - /// The tag of the EXIF value. - /// The value of the tag, if found. - /// - /// The . - /// - public bool TryGetValue(ExifTag tag, out ExifValue value) + /// The tag of the exif value. + /// The value with the specified tag. + /// The data type of the tag. + public IExifValue GetValue(ExifTag tag) { - foreach (ExifValue exifValue in this.Values) - { - if (exifValue.Tag == tag) - { - value = exifValue; - - return true; - } - } - - value = default; - - return false; + IExifValue value = this.GetValueInternal(tag); + return value is null ? null : (IExifValue)value; } /// @@ -206,24 +173,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// Sets the value of the specified tag. /// - /// The tag of the EXIF value. + /// The tag of the exif value. /// The value. - public void SetValue(ExifTag tag, object value) - { - for (int i = 0; i < this.Values.Count; i++) - { - if (this.values[i].Tag == tag) - { - this.values[i] = this.values[i].WithValue(value); - - return; - } - } - - var newExifValue = ExifValue.Create(tag, value); - - this.values.Add(newExifValue); - } + /// The data type of the tag. + public void SetValue(ExifTag tag, TValueType value) + => this.SetValueInternal(tag, value); /// /// Converts this instance to a byte array. @@ -238,7 +192,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (this.values.Count == 0) { - return null; + return Array.Empty(); } var writer = new ExifWriter(this.values, this.Parts); @@ -248,6 +202,50 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// public ExifProfile DeepClone() => new ExifProfile(this); + /// + /// Returns the value with the specified tag. + /// + /// The tag of the exif value. + /// The value with the specified tag. + internal IExifValue GetValueInternal(ExifTag tag) + { + foreach (IExifValue exifValue in this.Values) + { + if (exifValue.Tag == tag) + { + return exifValue; + } + } + + return null; + } + + /// + /// Sets the value of the specified tag. + /// + /// The tag of the exif value. + /// The value. + internal void SetValueInternal(ExifTag tag, object value) + { + foreach (IExifValue exifValue in this.Values) + { + if (exifValue.Tag == tag) + { + exifValue.TrySetValue(value); + return; + } + } + + ExifValue newExifValue = ExifValues.Create(tag); + if (newExifValue is null) + { + throw new NotSupportedException(); + } + + newExifValue.TrySetValue(value); + this.values.Add(newExifValue); + } + /// /// Synchronizes the profiles with the specified metadata. /// @@ -258,9 +256,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.SyncResolution(ExifTag.YResolution, metadata.VerticalResolution); } - private void SyncResolution(ExifTag tag, double resolution) + private void SyncResolution(ExifTag tag, double resolution) { - ExifValue value = this.GetValue(tag); + IExifValue value = this.GetValue(tag); if (value is null) { @@ -285,7 +283,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (this.data is null) { - this.values = new List(); + this.values = new List(); return; } @@ -301,4 +299,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif this.thumbnailLength = (int)reader.ThumbnailLength; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 77c1cf2ea..00410fb59 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -5,7 +5,6 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.Linq; using System.Runtime.CompilerServices; using System.Text; using SixLabors.ImageSharp.Primitives; @@ -68,12 +67,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// The . /// - public List ReadValues() + public List ReadValues() { - var values = new List(); + var values = new List(); // II == 0x4949 - this.isBigEndian = !(this.ReadUInt16() == 0x4949); + this.isBigEndian = this.ReadUInt16() != 0x4949; if (this.ReadUInt16() != 0x002A) { @@ -101,7 +100,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private static TDataType[] ToArray(ExifDataType dataType, ReadOnlySpan data, ConverterMethod converter) { - int dataTypeSize = (int)ExifValue.GetSize(dataType); + int dataTypeSize = (int)ExifDataTypes.GetSize(dataType); int length = data.Length / dataTypeSize; var result = new TDataType[length]; @@ -135,7 +134,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// The values. /// The index. - private void AddValues(List values, uint index) + private void AddValues(List values, uint index) { if (index > (uint)this.exifData.Length) { @@ -153,9 +152,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } bool duplicate = false; - foreach (ExifValue val in values) + foreach (IExifValue val in values) { - if (val.Tag == value.Tag) + if (val == value) { duplicate = true; break; @@ -167,19 +166,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif continue; } - if (value.Tag == ExifTag.SubIFDOffset) + if (value == ExifTag.SubIFDOffset) { - if (value.DataType == ExifDataType.Long) - { - this.exifOffset = (uint)value.Value; - } + this.exifOffset = ((ExifLong)value).Value; } - else if (value.Tag == ExifTag.GPSIFDOffset) + else if (value == ExifTag.GPSIFDOffset) { - if (value.DataType == ExifDataType.Long) - { - this.gpsOffset = (uint)value.Value; - } + this.gpsOffset = ((ExifLong)value).Value; } else { @@ -285,30 +278,24 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private bool TryReadValue(out ExifValue exifValue) { + exifValue = default; + // 2 | 2 | 4 | 4 // tag | type | count | value offset if (this.RemainingLength < 12) { - exifValue = default; - return false; } - ExifTag tag = this.ToEnum(this.ReadUInt16(), ExifTag.Unknown); - uint type = this.ReadUInt16(); + var tag = (ExifTagValue)this.ReadUInt16(); + ExifDataType dataType = EnumUtils.Parse(this.ReadUInt16(), ExifDataType.Unknown); // Ensure that the data type is valid - if (type == 0 || type > 12) + if (dataType == ExifDataType.Unknown) { - exifValue = new ExifValue(tag, ExifDataType.Unknown, null, false); - - return true; + return false; } - var dataType = (ExifDataType)type; - - object value; - uint numberOfComponents = this.ReadUInt32(); // Issue #132: ExifDataType == Undefined is treated like a byte array. @@ -318,23 +305,20 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif numberOfComponents = 4; } - uint size = numberOfComponents * ExifValue.GetSize(dataType); + uint size = numberOfComponents * ExifDataTypes.GetSize(dataType); this.TryReadSpan(4, out ReadOnlySpan offsetBuffer); + object value; if (size > 4) { int oldIndex = this.position; - uint newIndex = this.ConvertToUInt32(offsetBuffer); // Ensure that the new index does not overrun the data if (newIndex > int.MaxValue) { - this.AddInvalidTag(tag); - - exifValue = default; - + this.AddInvalidTag(new UnkownExifTag(tag)); return false; } @@ -342,12 +326,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif if (this.RemainingLength < size) { - this.AddInvalidTag(tag); + this.AddInvalidTag(new UnkownExifTag(tag)); this.position = oldIndex; - - exifValue = default; - return false; } @@ -361,33 +342,25 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif value = this.ConvertValue(dataType, offsetBuffer, numberOfComponents); } - exifValue = new ExifValue(tag, dataType, value, isArray: value != null && numberOfComponents != 1); - - return true; - } + exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); - private void AddInvalidTag(ExifTag tag) - { - if (this.invalidTags is null) + if (exifValue is null) { - this.invalidTags = new List(); + this.AddInvalidTag(new UnkownExifTag(tag)); + return false; } - this.invalidTags.Add(tag); - } - - [MethodImpl(InliningOptions.ShortMethod)] - private TEnum ToEnum(int value, TEnum defaultValue) - where TEnum : struct, Enum - { - if (EnumHelper.IsDefined(value)) + if (!exifValue.TrySetValue(value)) { - return Unsafe.As(ref value); + return false; } - return defaultValue; + return true; } + private void AddInvalidTag(ExifTag tag) + => (this.invalidTags ?? (this.invalidTags = new List())).Add(tag); + private bool TryReadSpan(int length, out ReadOnlySpan span) { if (this.RemainingLength < length) @@ -421,18 +394,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif private void GetThumbnail(uint offset) { - var values = new List(); + var values = new List(); this.AddValues(values, offset); foreach (ExifValue value in values) { - if (value.Tag == ExifTag.JPEGInterchangeFormat && (value.DataType == ExifDataType.Long)) + if (value == ExifTag.JPEGInterchangeFormat) { - this.ThumbnailOffset = (uint)value.Value; + this.ThumbnailOffset = ((ExifLong)value).Value; } - else if (value.Tag == ExifTag.JPEGInterchangeFormatLength && value.DataType == ExifDataType.Long) + else if (value == ExifTag.JPEGInterchangeFormatLength) { - this.ThumbnailLength = (uint)value.Value; + this.ThumbnailLength = ((ExifLong)value).Value; } } } @@ -541,18 +514,5 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif ? BinaryPrimitives.ReadInt16BigEndian(buffer) : BinaryPrimitives.ReadInt16LittleEndian(buffer); } - - private sealed class EnumHelper - where TEnum : struct, Enum - { - private static readonly int[] Values = Enum.GetValues(typeof(TEnum)).Cast() - .Select(e => Convert.ToInt32(e)).OrderBy(e => e).ToArray(); - - [MethodImpl(InliningOptions.ShortMethod)] - public static bool IsDefined(int value) - { - return Array.BinarySearch(Values, value) >= 0; - } - } } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs index 845e4ee73..b9bb2ee05 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -31,7 +31,8 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// public static string GetDescription(ExifTag tag, object value) { - FieldInfo field = tag.GetType().GetTypeInfo().GetDeclaredField(tag.ToString()); + var tagValue = (ExifTagValue)(ushort)tag; + FieldInfo field = tagValue.GetType().GetTypeInfo().GetDeclaredField(tagValue.ToString()); if (field is null) { @@ -42,7 +43,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { object attributeValue = customAttribute.ConstructorArguments[0].Value; - if (object.Equals(attributeValue, value)) + if (Equals(attributeValue, value)) { return (string)customAttribute.ConstructorArguments[1].Value; } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs index 0ed3a43b7..13fff5b6a 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs @@ -1,281 +1,275 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using static SixLabors.ImageSharp.Metadata.Profiles.Exif.ExifTag; - namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { internal static class ExifTags { - /// - /// The collection if Image File Directory tags - /// - public static readonly ExifTag[] Ifd = + public static ExifParts GetPart(ExifTag tag) { - SubfileType, - OldSubfileType, - ImageWidth, - ImageLength, - BitsPerSample, - Compression, - PhotometricInterpretation, - Thresholding, - CellWidth, - CellLength, - FillOrder, - DocumentName, - ImageDescription, - Make, - Model, - StripOffsets, - Orientation, - SamplesPerPixel, - RowsPerStrip, - StripByteCounts, - MinSampleValue, - MaxSampleValue, - XResolution, - YResolution, - PlanarConfiguration, - PageName, - XPosition, - YPosition, - FreeOffsets, - FreeByteCounts, - GrayResponseUnit, - GrayResponseCurve, - T4Options, - T6Options, - ResolutionUnit, - PageNumber, - ColorResponseUnit, - TransferFunction, - Software, - DateTime, - Artist, - HostComputer, - Predictor, - WhitePoint, - PrimaryChromaticities, - ColorMap, - HalftoneHints, - TileWidth, - TileLength, - TileOffsets, - TileByteCounts, - BadFaxLines, - CleanFaxData, - ConsecutiveBadFaxLines, - InkSet, - InkNames, - NumberOfInks, - DotRange, - TargetPrinter, - ExtraSamples, - SampleFormat, - SMinSampleValue, - SMaxSampleValue, - TransferRange, - ClipPath, - XClipPathUnits, - YClipPathUnits, - Indexed, - JPEGTables, - OPIProxy, - ProfileType, - FaxProfile, - CodingMethods, - VersionYear, - ModeNumber, - Decode, - DefaultImageColor, - T82ptions, - JPEGProc, - JPEGInterchangeFormat, - JPEGInterchangeFormatLength, - JPEGRestartInterval, - JPEGLosslessPredictors, - JPEGPointTransforms, - JPEGQTables, - JPEGDCTables, - JPEGACTables, - YCbCrCoefficients, - YCbCrSubsampling, - YCbCrSubsampling, - YCbCrPositioning, - ReferenceBlackWhite, - StripRowCounts, - XMP, - Rating, - RatingPercent, - ImageID, - CFARepeatPatternDim, - CFAPattern2, - BatteryLevel, - Copyright, - MDFileTag, - MDScalePixel, - MDLabName, - MDSampleInfo, - MDPrepDate, - MDPrepTime, - MDFileUnits, - PixelScale, - IntergraphPacketData, - IntergraphRegisters, - IntergraphMatrix, - ModelTiePoint, - SEMInfo, - ModelTransform, - ImageLayer, - FaxRecvParams, - FaxSubaddress, - FaxRecvTime, - ImageSourceData, - XPTitle, - XPComment, - XPAuthor, - XPKeywords, - XPSubject, - GDALMetadata, - GDALNoData - }; + switch ((ExifTagValue)(ushort)tag) + { + case ExifTagValue.SubfileType: + case ExifTagValue.OldSubfileType: + case ExifTagValue.ImageWidth: + case ExifTagValue.ImageLength: + case ExifTagValue.BitsPerSample: + case ExifTagValue.Compression: + case ExifTagValue.PhotometricInterpretation: + case ExifTagValue.Thresholding: + case ExifTagValue.CellWidth: + case ExifTagValue.CellLength: + case ExifTagValue.FillOrder: + case ExifTagValue.DocumentName: + case ExifTagValue.ImageDescription: + case ExifTagValue.Make: + case ExifTagValue.Model: + case ExifTagValue.StripOffsets: + case ExifTagValue.Orientation: + case ExifTagValue.SamplesPerPixel: + case ExifTagValue.RowsPerStrip: + case ExifTagValue.StripByteCounts: + case ExifTagValue.MinSampleValue: + case ExifTagValue.MaxSampleValue: + case ExifTagValue.XResolution: + case ExifTagValue.YResolution: + case ExifTagValue.PlanarConfiguration: + case ExifTagValue.PageName: + case ExifTagValue.XPosition: + case ExifTagValue.YPosition: + case ExifTagValue.FreeOffsets: + case ExifTagValue.FreeByteCounts: + case ExifTagValue.GrayResponseUnit: + case ExifTagValue.GrayResponseCurve: + case ExifTagValue.T4Options: + case ExifTagValue.T6Options: + case ExifTagValue.ResolutionUnit: + case ExifTagValue.PageNumber: + case ExifTagValue.ColorResponseUnit: + case ExifTagValue.TransferFunction: + case ExifTagValue.Software: + case ExifTagValue.DateTime: + case ExifTagValue.Artist: + case ExifTagValue.HostComputer: + case ExifTagValue.Predictor: + case ExifTagValue.WhitePoint: + case ExifTagValue.PrimaryChromaticities: + case ExifTagValue.ColorMap: + case ExifTagValue.HalftoneHints: + case ExifTagValue.TileWidth: + case ExifTagValue.TileLength: + case ExifTagValue.TileOffsets: + case ExifTagValue.TileByteCounts: + case ExifTagValue.BadFaxLines: + case ExifTagValue.CleanFaxData: + case ExifTagValue.ConsecutiveBadFaxLines: + case ExifTagValue.InkSet: + case ExifTagValue.InkNames: + case ExifTagValue.NumberOfInks: + case ExifTagValue.DotRange: + case ExifTagValue.TargetPrinter: + case ExifTagValue.ExtraSamples: + case ExifTagValue.SampleFormat: + case ExifTagValue.SMinSampleValue: + case ExifTagValue.SMaxSampleValue: + case ExifTagValue.TransferRange: + case ExifTagValue.ClipPath: + case ExifTagValue.XClipPathUnits: + case ExifTagValue.YClipPathUnits: + case ExifTagValue.Indexed: + case ExifTagValue.JPEGTables: + case ExifTagValue.OPIProxy: + case ExifTagValue.ProfileType: + case ExifTagValue.FaxProfile: + case ExifTagValue.CodingMethods: + case ExifTagValue.VersionYear: + case ExifTagValue.ModeNumber: + case ExifTagValue.Decode: + case ExifTagValue.DefaultImageColor: + case ExifTagValue.T82ptions: + case ExifTagValue.JPEGProc: + case ExifTagValue.JPEGInterchangeFormat: + case ExifTagValue.JPEGInterchangeFormatLength: + case ExifTagValue.JPEGRestartInterval: + case ExifTagValue.JPEGLosslessPredictors: + case ExifTagValue.JPEGPointTransforms: + case ExifTagValue.JPEGQTables: + case ExifTagValue.JPEGDCTables: + case ExifTagValue.JPEGACTables: + case ExifTagValue.YCbCrCoefficients: + case ExifTagValue.YCbCrPositioning: + case ExifTagValue.YCbCrSubsampling: + case ExifTagValue.ReferenceBlackWhite: + case ExifTagValue.StripRowCounts: + case ExifTagValue.XMP: + case ExifTagValue.Rating: + case ExifTagValue.RatingPercent: + case ExifTagValue.ImageID: + case ExifTagValue.CFARepeatPatternDim: + case ExifTagValue.CFAPattern2: + case ExifTagValue.BatteryLevel: + case ExifTagValue.Copyright: + case ExifTagValue.MDFileTag: + case ExifTagValue.MDScalePixel: + case ExifTagValue.MDLabName: + case ExifTagValue.MDSampleInfo: + case ExifTagValue.MDPrepDate: + case ExifTagValue.MDPrepTime: + case ExifTagValue.MDFileUnits: + case ExifTagValue.PixelScale: + case ExifTagValue.IntergraphPacketData: + case ExifTagValue.IntergraphRegisters: + case ExifTagValue.IntergraphMatrix: + case ExifTagValue.ModelTiePoint: + case ExifTagValue.SEMInfo: + case ExifTagValue.ModelTransform: + case ExifTagValue.ImageLayer: + case ExifTagValue.FaxRecvParams: + case ExifTagValue.FaxSubaddress: + case ExifTagValue.FaxRecvTime: + case ExifTagValue.ImageSourceData: + case ExifTagValue.XPTitle: + case ExifTagValue.XPComment: + case ExifTagValue.XPAuthor: + case ExifTagValue.XPKeywords: + case ExifTagValue.XPSubject: + case ExifTagValue.GDALMetadata: + case ExifTagValue.GDALNoData: + return ExifParts.IfdTags; - /// - /// The collection of Exif tags - /// - public static readonly ExifTag[] Exif = - { - ExposureTime, - FNumber, - ExposureProgram, - SpectralSensitivity, - ISOSpeedRatings, - OECF, - Interlace, - TimeZoneOffset, - SelfTimerMode, - SensitivityType, - StandardOutputSensitivity, - RecommendedExposureIndex, - ISOSpeed, - ISOSpeedLatitudeyyy, - ISOSpeedLatitudezzz, - ExifVersion, - DateTimeOriginal, - DateTimeDigitized, - OffsetTime, - OffsetTimeOriginal, - OffsetTimeDigitized, - ComponentsConfiguration, - CompressedBitsPerPixel, - ShutterSpeedValue, - ApertureValue, - BrightnessValue, - ExposureBiasValue, - MaxApertureValue, - SubjectDistance, - MeteringMode, - LightSource, - Flash, - FocalLength, - FlashEnergy2, - SpatialFrequencyResponse2, - Noise, - FocalPlaneXResolution2, - FocalPlaneYResolution2, - FocalPlaneResolutionUnit2, - ImageNumber, - SecurityClassification, - ImageHistory, - SubjectArea, - ExposureIndex2, - TIFFEPStandardID, - SensingMethod2, - MakerNote, - UserComment, - SubsecTime, - SubsecTimeOriginal, - SubsecTimeDigitized, - AmbientTemperature, - Humidity, - Pressure, - WaterDepth, - Acceleration, - CameraElevationAngle, - FlashpixVersion, - ColorSpace, - PixelXDimension, - PixelYDimension, - RelatedSoundFile, - FlashEnergy, - SpatialFrequencyResponse, - FocalPlaneXResolution, - FocalPlaneYResolution, - FocalPlaneResolutionUnit, - SubjectLocation, - ExposureIndex, - SensingMethod, - FileSource, - SceneType, - CFAPattern, - CustomRendered, - ExposureMode, - WhiteBalance, - DigitalZoomRatio, - FocalLengthIn35mmFilm, - SceneCaptureType, - GainControl, - Contrast, - Saturation, - Sharpness, - DeviceSettingDescription, - SubjectDistanceRange, - ImageUniqueID, - OwnerName, - SerialNumber, - LensInfo, - LensMake, - LensModel, - LensSerialNumber - }; + case ExifTagValue.ExposureTime: + case ExifTagValue.FNumber: + case ExifTagValue.ExposureProgram: + case ExifTagValue.SpectralSensitivity: + case ExifTagValue.ISOSpeedRatings: + case ExifTagValue.OECF: + case ExifTagValue.Interlace: + case ExifTagValue.TimeZoneOffset: + case ExifTagValue.SelfTimerMode: + case ExifTagValue.SensitivityType: + case ExifTagValue.StandardOutputSensitivity: + case ExifTagValue.RecommendedExposureIndex: + case ExifTagValue.ISOSpeed: + case ExifTagValue.ISOSpeedLatitudeyyy: + case ExifTagValue.ISOSpeedLatitudezzz: + case ExifTagValue.ExifVersion: + case ExifTagValue.DateTimeOriginal: + case ExifTagValue.DateTimeDigitized: + case ExifTagValue.OffsetTime: + case ExifTagValue.OffsetTimeOriginal: + case ExifTagValue.OffsetTimeDigitized: + case ExifTagValue.ComponentsConfiguration: + case ExifTagValue.CompressedBitsPerPixel: + case ExifTagValue.ShutterSpeedValue: + case ExifTagValue.ApertureValue: + case ExifTagValue.BrightnessValue: + case ExifTagValue.ExposureBiasValue: + case ExifTagValue.MaxApertureValue: + case ExifTagValue.SubjectDistance: + case ExifTagValue.MeteringMode: + case ExifTagValue.LightSource: + case ExifTagValue.Flash: + case ExifTagValue.FocalLength: + case ExifTagValue.FlashEnergy2: + case ExifTagValue.SpatialFrequencyResponse2: + case ExifTagValue.Noise: + case ExifTagValue.FocalPlaneXResolution2: + case ExifTagValue.FocalPlaneYResolution2: + case ExifTagValue.FocalPlaneResolutionUnit2: + case ExifTagValue.ImageNumber: + case ExifTagValue.SecurityClassification: + case ExifTagValue.ImageHistory: + case ExifTagValue.SubjectArea: + case ExifTagValue.ExposureIndex2: + case ExifTagValue.TIFFEPStandardID: + case ExifTagValue.SensingMethod2: + case ExifTagValue.MakerNote: + case ExifTagValue.UserComment: + case ExifTagValue.SubsecTime: + case ExifTagValue.SubsecTimeOriginal: + case ExifTagValue.SubsecTimeDigitized: + case ExifTagValue.AmbientTemperature: + case ExifTagValue.Humidity: + case ExifTagValue.Pressure: + case ExifTagValue.WaterDepth: + case ExifTagValue.Acceleration: + case ExifTagValue.CameraElevationAngle: + case ExifTagValue.FlashpixVersion: + case ExifTagValue.ColorSpace: + case ExifTagValue.PixelXDimension: + case ExifTagValue.PixelYDimension: + case ExifTagValue.RelatedSoundFile: + case ExifTagValue.FlashEnergy: + case ExifTagValue.SpatialFrequencyResponse: + case ExifTagValue.FocalPlaneXResolution: + case ExifTagValue.FocalPlaneYResolution: + case ExifTagValue.FocalPlaneResolutionUnit: + case ExifTagValue.SubjectLocation: + case ExifTagValue.ExposureIndex: + case ExifTagValue.SensingMethod: + case ExifTagValue.FileSource: + case ExifTagValue.SceneType: + case ExifTagValue.CFAPattern: + case ExifTagValue.CustomRendered: + case ExifTagValue.ExposureMode: + case ExifTagValue.WhiteBalance: + case ExifTagValue.DigitalZoomRatio: + case ExifTagValue.FocalLengthIn35mmFilm: + case ExifTagValue.SceneCaptureType: + case ExifTagValue.GainControl: + case ExifTagValue.Contrast: + case ExifTagValue.Saturation: + case ExifTagValue.Sharpness: + case ExifTagValue.DeviceSettingDescription: + case ExifTagValue.SubjectDistanceRange: + case ExifTagValue.ImageUniqueID: + case ExifTagValue.OwnerName: + case ExifTagValue.SerialNumber: + case ExifTagValue.LensInfo: + case ExifTagValue.LensMake: + case ExifTagValue.LensModel: + case ExifTagValue.LensSerialNumber: + return ExifParts.ExifTags; - /// - /// The collection of GPS tags - /// - public static readonly ExifTag[] Gps = - { - GPSVersionID, - GPSLatitudeRef, - GPSLatitude, - GPSLongitudeRef, - GPSLongitude, - GPSAltitudeRef, - GPSAltitude, - GPSTimestamp, - GPSSatellites, - GPSStatus, - GPSMeasureMode, - GPSDOP, - GPSSpeedRef, - GPSSpeed, - GPSTrackRef, - GPSTrack, - GPSImgDirectionRef, - GPSImgDirection, - GPSMapDatum, - GPSDestLatitudeRef, - GPSDestLatitude, - GPSDestLongitudeRef, - GPSDestLongitude, - GPSDestBearingRef, - GPSDestBearing, - GPSDestDistanceRef, - GPSDestDistance, - GPSProcessingMethod, - GPSAreaInformation, - GPSDateStamp, - GPSDifferential - }; + case ExifTagValue.GPSVersionID: + case ExifTagValue.GPSLatitudeRef: + case ExifTagValue.GPSLatitude: + case ExifTagValue.GPSLongitudeRef: + case ExifTagValue.GPSLongitude: + case ExifTagValue.GPSAltitudeRef: + case ExifTagValue.GPSAltitude: + case ExifTagValue.GPSTimestamp: + case ExifTagValue.GPSSatellites: + case ExifTagValue.GPSStatus: + case ExifTagValue.GPSMeasureMode: + case ExifTagValue.GPSDOP: + case ExifTagValue.GPSSpeedRef: + case ExifTagValue.GPSSpeed: + case ExifTagValue.GPSTrackRef: + case ExifTagValue.GPSTrack: + case ExifTagValue.GPSImgDirectionRef: + case ExifTagValue.GPSImgDirection: + case ExifTagValue.GPSMapDatum: + case ExifTagValue.GPSDestLatitudeRef: + case ExifTagValue.GPSDestLatitude: + case ExifTagValue.GPSDestLongitudeRef: + case ExifTagValue.GPSDestLongitude: + case ExifTagValue.GPSDestBearingRef: + case ExifTagValue.GPSDestBearing: + case ExifTagValue.GPSDestDistanceRef: + case ExifTagValue.GPSDestDistance: + case ExifTagValue.GPSProcessingMethod: + case ExifTagValue.GPSAreaInformation: + case ExifTagValue.GPSDateStamp: + case ExifTagValue.GPSDifferential: + return ExifParts.GpsTags; + + case ExifTagValue.Unknown: + case ExifTagValue.SubIFDOffset: + case ExifTagValue.GPSIFDOffset: + default: + return ExifParts.None; + } + } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs deleted file mode 100644 index 05a9f35c9..000000000 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs +++ /dev/null @@ -1,721 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Globalization; -using System.Text; -using SixLabors.ImageSharp.Primitives; - -namespace SixLabors.ImageSharp.Metadata.Profiles.Exif -{ - /// - /// Represent the value of the EXIF profile. - /// - public sealed class ExifValue : IEquatable, IDeepCloneable - { - /// - /// Initializes a new instance of the class. - /// - /// The tag. - /// The data type. - /// The value. - /// Whether the value is an array. - internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) - { - this.Tag = tag; - this.DataType = dataType; - this.IsArray = isArray && dataType != ExifDataType.Ascii; - this.Value = value; - } - - /// - /// Initializes a new instance of the class - /// by making a copy from another exif value. - /// - /// The other exif value, where the clone should be made from. - /// is null. - private ExifValue(ExifValue other) - { - Guard.NotNull(other, nameof(other)); - - this.DataType = other.DataType; - this.IsArray = other.IsArray; - this.Tag = other.Tag; - - if (!other.IsArray) - { - // All types are value types except for string which is immutable so safe to simply assign. - this.Value = other.Value; - } - else - { - // All array types are value types so Clone() is sufficient here. - var array = (Array)other.Value; - this.Value = array.Clone(); - } - } - - /// - /// Gets the data type of the exif value. - /// - public ExifDataType DataType { get; } - - /// - /// Gets a value indicating whether the value is an array. - /// - public bool IsArray { get; } - - /// - /// Gets the tag of the exif value. - /// - public ExifTag Tag { get; } - - /// - /// Gets the value. - /// - public object Value { get; } - - /// - /// Gets a value indicating whether the EXIF value has a value. - /// - internal bool HasValue - { - get - { - if (this.Value is null) - { - return false; - } - - if (this.DataType == ExifDataType.Ascii) - { - return ((string)this.Value).Length > 0; - } - - return true; - } - } - - /// - /// Gets the length of the EXIF value - /// - internal int Length - { - get - { - if (this.Value is null) - { - return 4; - } - - int size = (int)(GetSize(this.DataType) * this.NumberOfComponents); - - return size < 4 ? 4 : size; - } - } - - /// - /// Gets the number of components. - /// - internal int NumberOfComponents - { - get - { - if (this.DataType == ExifDataType.Ascii) - { - return Encoding.UTF8.GetBytes((string)this.Value).Length; - } - - if (this.IsArray) - { - return ((Array)this.Value).Length; - } - - return 1; - } - } - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is equal to the parameter; otherwise, false. - /// - public static bool operator ==(ExifValue left, ExifValue right) => ReferenceEquals(left, right) || left.Equals(right); - - /// - /// Compares two objects for equality. - /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// - /// - /// True if the parameter is not equal to the parameter; otherwise, false. - /// - public static bool operator !=(ExifValue left, ExifValue right) => !(left == right); - - /// - public override bool Equals(object obj) => obj is ExifValue other && this.Equals(other); - - /// - public bool Equals(ExifValue other) - { - if (other is null) - { - return false; - } - - if (ReferenceEquals(this, other)) - { - return true; - } - - return - this.Tag == other.Tag - && this.DataType == other.DataType - && object.Equals(this.Value, other.Value); - } - - /// - /// Clones the current value, overwriting the value. - /// - /// The value to overwrite. - /// - public ExifValue WithValue(object value) - { - this.CheckValue(value); - - return new ExifValue(this.Tag, this.DataType, value, this.IsArray); - } - - /// - public override int GetHashCode() - { - return HashCode.Combine(this.Tag, this.DataType, this.Value); - } - - /// - public override string ToString() - { - if (this.Value is null) - { - return null; - } - - if (this.DataType == ExifDataType.Ascii) - { - return (string)this.Value; - } - - if (!this.IsArray) - { - return this.ToString(this.Value); - } - - var sb = new StringBuilder(); - foreach (object value in (Array)this.Value) - { - sb.Append(this.ToString(value)); - sb.Append(' '); - } - - return sb.ToString(); - } - - /// - public ExifValue DeepClone() => new ExifValue(this); - - /// - /// Creates a new - /// - /// The tag. - /// The value. - /// - /// The . - /// - /// - /// Thrown if the tag is not supported. - /// - internal static ExifValue Create(ExifTag tag, object value) - { - Guard.IsFalse(tag == ExifTag.Unknown, nameof(tag), "Invalid Tag"); - - switch (tag) - { - case ExifTag.ImageDescription: - case ExifTag.Make: - case ExifTag.Model: - case ExifTag.Software: - case ExifTag.DateTime: - case ExifTag.Artist: - case ExifTag.HostComputer: - case ExifTag.Copyright: - case ExifTag.DocumentName: - case ExifTag.PageName: - case ExifTag.InkNames: - case ExifTag.TargetPrinter: - case ExifTag.ImageID: - case ExifTag.MDLabName: - case ExifTag.MDSampleInfo: - case ExifTag.MDPrepDate: - case ExifTag.MDPrepTime: - case ExifTag.MDFileUnits: - case ExifTag.SEMInfo: - case ExifTag.SpectralSensitivity: - case ExifTag.DateTimeOriginal: - case ExifTag.DateTimeDigitized: - case ExifTag.SubsecTime: - case ExifTag.SubsecTimeOriginal: - case ExifTag.SubsecTimeDigitized: - case ExifTag.FaxSubaddress: - case ExifTag.OffsetTime: - case ExifTag.OffsetTimeOriginal: - case ExifTag.OffsetTimeDigitized: - case ExifTag.SecurityClassification: - case ExifTag.ImageHistory: - case ExifTag.ImageUniqueID: - case ExifTag.OwnerName: - case ExifTag.SerialNumber: - case ExifTag.LensMake: - case ExifTag.LensModel: - case ExifTag.LensSerialNumber: - case ExifTag.GDALMetadata: - case ExifTag.GDALNoData: - case ExifTag.GPSLatitudeRef: - case ExifTag.GPSLongitudeRef: - case ExifTag.GPSSatellites: - case ExifTag.GPSStatus: - case ExifTag.GPSMeasureMode: - case ExifTag.GPSSpeedRef: - case ExifTag.GPSTrackRef: - case ExifTag.GPSImgDirectionRef: - case ExifTag.GPSMapDatum: - case ExifTag.GPSDestLatitudeRef: - case ExifTag.GPSDestLongitudeRef: - case ExifTag.GPSDestBearingRef: - case ExifTag.GPSDestDistanceRef: - case ExifTag.GPSDateStamp: - return new ExifValue(tag, ExifDataType.Ascii, value, true); - - case ExifTag.ClipPath: - case ExifTag.VersionYear: - case ExifTag.XMP: - case ExifTag.CFAPattern2: - case ExifTag.TIFFEPStandardID: - case ExifTag.XPTitle: - case ExifTag.XPComment: - case ExifTag.XPAuthor: - case ExifTag.XPKeywords: - case ExifTag.XPSubject: - case ExifTag.GPSVersionID: - return new ExifValue(tag, ExifDataType.Byte, value, true); - - case ExifTag.FaxProfile: - case ExifTag.ModeNumber: - case ExifTag.GPSAltitudeRef: - return new ExifValue(tag, ExifDataType.Byte, value, false); - - case ExifTag.FreeOffsets: - case ExifTag.FreeByteCounts: - case ExifTag.ColorResponseUnit: - case ExifTag.TileOffsets: - case ExifTag.SMinSampleValue: - case ExifTag.SMaxSampleValue: - case ExifTag.JPEGQTables: - case ExifTag.JPEGDCTables: - case ExifTag.JPEGACTables: - case ExifTag.StripRowCounts: - case ExifTag.IntergraphRegisters: - case ExifTag.TimeZoneOffset: - return new ExifValue(tag, ExifDataType.Long, value, true); - case ExifTag.SubfileType: - case ExifTag.SubIFDOffset: - case ExifTag.GPSIFDOffset: - case ExifTag.T4Options: - case ExifTag.T6Options: - case ExifTag.XClipPathUnits: - case ExifTag.YClipPathUnits: - case ExifTag.ProfileType: - case ExifTag.CodingMethods: - case ExifTag.T82ptions: - case ExifTag.JPEGInterchangeFormat: - case ExifTag.JPEGInterchangeFormatLength: - case ExifTag.MDFileTag: - case ExifTag.StandardOutputSensitivity: - case ExifTag.RecommendedExposureIndex: - case ExifTag.ISOSpeed: - case ExifTag.ISOSpeedLatitudeyyy: - case ExifTag.ISOSpeedLatitudezzz: - case ExifTag.FaxRecvParams: - case ExifTag.FaxRecvTime: - case ExifTag.ImageNumber: - return new ExifValue(tag, ExifDataType.Long, value, false); - - case ExifTag.WhitePoint: - case ExifTag.PrimaryChromaticities: - case ExifTag.YCbCrCoefficients: - case ExifTag.ReferenceBlackWhite: - case ExifTag.PixelScale: - case ExifTag.IntergraphMatrix: - case ExifTag.ModelTiePoint: - case ExifTag.ModelTransform: - case ExifTag.GPSLatitude: - case ExifTag.GPSLongitude: - case ExifTag.GPSTimestamp: - case ExifTag.GPSDestLatitude: - case ExifTag.GPSDestLongitude: - return new ExifValue(tag, ExifDataType.Rational, value, true); - - case ExifTag.XPosition: - case ExifTag.YPosition: - case ExifTag.XResolution: - case ExifTag.YResolution: - case ExifTag.BatteryLevel: - case ExifTag.ExposureTime: - case ExifTag.FNumber: - case ExifTag.MDScalePixel: - case ExifTag.CompressedBitsPerPixel: - case ExifTag.ApertureValue: - case ExifTag.MaxApertureValue: - case ExifTag.SubjectDistance: - case ExifTag.FocalLength: - case ExifTag.FlashEnergy2: - case ExifTag.FocalPlaneXResolution2: - case ExifTag.FocalPlaneYResolution2: - case ExifTag.ExposureIndex2: - case ExifTag.Humidity: - case ExifTag.Pressure: - case ExifTag.Acceleration: - case ExifTag.FlashEnergy: - case ExifTag.FocalPlaneXResolution: - case ExifTag.FocalPlaneYResolution: - case ExifTag.ExposureIndex: - case ExifTag.DigitalZoomRatio: - case ExifTag.LensInfo: - case ExifTag.GPSAltitude: - case ExifTag.GPSDOP: - case ExifTag.GPSSpeed: - case ExifTag.GPSTrack: - case ExifTag.GPSImgDirection: - case ExifTag.GPSDestBearing: - case ExifTag.GPSDestDistance: - return new ExifValue(tag, ExifDataType.Rational, value, false); - - case ExifTag.BitsPerSample: - case ExifTag.MinSampleValue: - case ExifTag.MaxSampleValue: - case ExifTag.GrayResponseCurve: - case ExifTag.ColorMap: - case ExifTag.ExtraSamples: - case ExifTag.PageNumber: - case ExifTag.TransferFunction: - case ExifTag.Predictor: - case ExifTag.HalftoneHints: - case ExifTag.SampleFormat: - case ExifTag.TransferRange: - case ExifTag.DefaultImageColor: - case ExifTag.JPEGLosslessPredictors: - case ExifTag.JPEGPointTransforms: - case ExifTag.YCbCrSubsampling: - case ExifTag.CFARepeatPatternDim: - case ExifTag.IntergraphPacketData: - case ExifTag.ISOSpeedRatings: - case ExifTag.SubjectArea: - case ExifTag.SubjectLocation: - return new ExifValue(tag, ExifDataType.Short, value, true); - - case ExifTag.OldSubfileType: - case ExifTag.Compression: - case ExifTag.PhotometricInterpretation: - case ExifTag.Thresholding: - case ExifTag.CellWidth: - case ExifTag.CellLength: - case ExifTag.FillOrder: - case ExifTag.Orientation: - case ExifTag.SamplesPerPixel: - case ExifTag.PlanarConfiguration: - case ExifTag.GrayResponseUnit: - case ExifTag.ResolutionUnit: - case ExifTag.CleanFaxData: - case ExifTag.InkSet: - case ExifTag.NumberOfInks: - case ExifTag.DotRange: - case ExifTag.Indexed: - case ExifTag.OPIProxy: - case ExifTag.JPEGProc: - case ExifTag.JPEGRestartInterval: - case ExifTag.YCbCrPositioning: - case ExifTag.Rating: - case ExifTag.RatingPercent: - case ExifTag.ExposureProgram: - case ExifTag.Interlace: - case ExifTag.SelfTimerMode: - case ExifTag.SensitivityType: - case ExifTag.MeteringMode: - case ExifTag.LightSource: - case ExifTag.FocalPlaneResolutionUnit2: - case ExifTag.SensingMethod2: - case ExifTag.Flash: - case ExifTag.ColorSpace: - case ExifTag.FocalPlaneResolutionUnit: - case ExifTag.SensingMethod: - case ExifTag.CustomRendered: - case ExifTag.ExposureMode: - case ExifTag.WhiteBalance: - case ExifTag.FocalLengthIn35mmFilm: - case ExifTag.SceneCaptureType: - case ExifTag.GainControl: - case ExifTag.Contrast: - case ExifTag.Saturation: - case ExifTag.Sharpness: - case ExifTag.SubjectDistanceRange: - case ExifTag.GPSDifferential: - return new ExifValue(tag, ExifDataType.Short, value, false); - - case ExifTag.Decode: - return new ExifValue(tag, ExifDataType.SignedRational, value, true); - - case ExifTag.ShutterSpeedValue: - case ExifTag.BrightnessValue: - case ExifTag.ExposureBiasValue: - case ExifTag.AmbientTemperature: - case ExifTag.WaterDepth: - case ExifTag.CameraElevationAngle: - return new ExifValue(tag, ExifDataType.SignedRational, value, false); - - case ExifTag.JPEGTables: - case ExifTag.OECF: - case ExifTag.ExifVersion: - case ExifTag.ComponentsConfiguration: - case ExifTag.MakerNote: - case ExifTag.UserComment: - case ExifTag.FlashpixVersion: - case ExifTag.SpatialFrequencyResponse: - case ExifTag.SpatialFrequencyResponse2: - case ExifTag.Noise: - case ExifTag.CFAPattern: - case ExifTag.DeviceSettingDescription: - case ExifTag.ImageSourceData: - case ExifTag.GPSProcessingMethod: - case ExifTag.GPSAreaInformation: - return new ExifValue(tag, ExifDataType.Undefined, value, true); - - case ExifTag.FileSource: - case ExifTag.SceneType: - return new ExifValue(tag, ExifDataType.Undefined, value, false); - - case ExifTag.StripOffsets: - case ExifTag.TileByteCounts: - case ExifTag.ImageLayer: - return CreateNumber(tag, value, true); - - case ExifTag.ImageWidth: - case ExifTag.ImageLength: - case ExifTag.TileWidth: - case ExifTag.TileLength: - case ExifTag.BadFaxLines: - case ExifTag.ConsecutiveBadFaxLines: - case ExifTag.PixelXDimension: - case ExifTag.PixelYDimension: - return CreateNumber(tag, value, false); - - default: - throw new NotSupportedException(); - } - } - - /// - /// Gets the size in bytes of the given data type. - /// - /// The data type. - /// - /// The . - /// - /// - /// Thrown if the type is unsupported. - /// - internal static uint GetSize(ExifDataType dataType) - { - switch (dataType) - { - case ExifDataType.Ascii: - case ExifDataType.Byte: - case ExifDataType.SignedByte: - case ExifDataType.Undefined: - return 1; - case ExifDataType.Short: - case ExifDataType.SignedShort: - return 2; - case ExifDataType.Long: - case ExifDataType.SignedLong: - case ExifDataType.SingleFloat: - return 4; - case ExifDataType.DoubleFloat: - case ExifDataType.Rational: - case ExifDataType.SignedRational: - return 8; - default: - throw new NotSupportedException(dataType.ToString()); - } - } - - /// - /// Returns an EXIF value with a numeric type for the given tag. - /// - /// The tag. - /// The value. - /// Whether the value is an array. - /// - /// The . - /// - private static ExifValue CreateNumber(ExifTag tag, object value, bool isArray) - { - Type type = value?.GetType(); - if (type?.IsArray == true) - { - type = type.GetElementType(); - } - - if (type is null || type == typeof(ushort)) - { - return new ExifValue(tag, ExifDataType.Short, value, isArray); - } - - if (type == typeof(short)) - { - return new ExifValue(tag, ExifDataType.SignedShort, value, isArray); - } - - if (type == typeof(uint)) - { - return new ExifValue(tag, ExifDataType.Long, value, isArray); - } - - return new ExifValue(tag, ExifDataType.SignedLong, value, isArray); - } - - /// - /// Checks the value type of the given object. - /// - /// The value to check. - /// - /// Thrown if the object type is not supported. - /// - private void CheckValue(object value) - { - if (value is null) - { - return; - } - - Type type = value.GetType(); - - if (this.DataType == ExifDataType.Ascii) - { - Guard.IsTrue(type == typeof(string), nameof(value), "Value should be a string."); - return; - } - - if (type.IsArray) - { - Guard.IsTrue(this.IsArray, nameof(value), "Value should not be an array."); - type = type.GetElementType(); - } - else - { - Guard.IsFalse(this.IsArray, nameof(value), "Value should not be an array."); - } - - switch (this.DataType) - { - case ExifDataType.Byte: - Guard.IsTrue(type == typeof(byte), nameof(value), $"Value should be a byte{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.DoubleFloat: - Guard.IsTrue(type == typeof(double), nameof(value), $"Value should be a double{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.Long: - Guard.IsTrue(type == typeof(uint), nameof(value), $"Value should be an unsigned int{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.Rational: - Guard.IsTrue(type == typeof(Rational), nameof(value), $"Value should be a Rational{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.Short: - Guard.IsTrue(type == typeof(ushort), nameof(value), $"Value should be an unsigned short{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.SignedByte: - Guard.IsTrue(type == typeof(sbyte), nameof(value), $"Value should be a signed byte{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.SignedLong: - Guard.IsTrue(type == typeof(int), nameof(value), $"Value should be an int{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.SignedRational: - Guard.IsTrue(type == typeof(SignedRational), nameof(value), $"Value should be a SignedRational{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.SignedShort: - Guard.IsTrue(type == typeof(short), nameof(value), $"Value should be a short{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.SingleFloat: - Guard.IsTrue(type == typeof(float), nameof(value), $"Value should be a float{(this.IsArray ? " array." : ".")}"); - break; - case ExifDataType.Undefined: - Guard.IsTrue(type == typeof(byte), nameof(value), "Value should be a byte array."); - break; - default: - throw new NotSupportedException(); - } - } - - /// - /// Converts the object value of this instance to its equivalent string representation - /// - /// The value - /// The - private string ToString(object value) - { - if (ExifTagDescriptionAttribute.GetDescription(this.Tag, value) is string description) - { - return description; - } - - switch (this.DataType) - { - case ExifDataType.Ascii: - return (string)value; - case ExifDataType.Byte: - return ((byte)value).ToString("X2", CultureInfo.InvariantCulture); - case ExifDataType.DoubleFloat: - return ((double)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.Long: - return ((uint)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.Rational: - return ((Rational)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.Short: - return ((ushort)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.SignedByte: - return ((sbyte)value).ToString("X2", CultureInfo.InvariantCulture); - case ExifDataType.SignedLong: - return ((int)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.SignedRational: - return ((Rational)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.SignedShort: - return ((short)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.SingleFloat: - return ((float)value).ToString(CultureInfo.InvariantCulture); - case ExifDataType.Undefined: - return ((byte)value).ToString("X2", CultureInfo.InvariantCulture); - default: - throw new NotSupportedException(); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs index 67c1b2b65..48b0fddca 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs @@ -18,24 +18,24 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// Which parts will be written. /// private readonly ExifParts allowedParts; - private readonly IList values; + private readonly IList values; private List dataOffsets; - private readonly List ifdIndexes; - private readonly List exifIndexes; - private readonly List gpsIndexes; + private readonly List ifdValues; + private readonly List exifValues; + private readonly List gpsValues; /// /// Initializes a new instance of the class. /// /// The values. /// The allowed parts. - public ExifWriter(IList values, ExifParts allowedParts) + public ExifWriter(IList values, ExifParts allowedParts) { this.values = values; this.allowedParts = allowedParts; - this.ifdIndexes = this.GetIndexes(ExifParts.IfdTags, ExifTags.Ifd); - this.exifIndexes = this.GetIndexes(ExifParts.ExifTags, ExifTags.Exif); - this.gpsIndexes = this.GetIndexes(ExifParts.GPSTags, ExifTags.Gps); + this.ifdValues = this.GetPartValues(ExifParts.IfdTags); + this.exifValues = this.GetPartValues(ExifParts.ExifTags); + this.gpsValues = this.GetPartValues(ExifParts.GpsTags); } /// @@ -46,43 +46,29 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// public byte[] GetData() { - uint startIndex = 0; + const uint startIndex = 0; uint length; - int exifIndex = -1; - int gpsIndex = -1; - if (this.exifIndexes.Count > 0) - { - exifIndex = this.GetIndex(this.ifdIndexes, ExifTag.SubIFDOffset); - } - - if (this.gpsIndexes.Count > 0) - { - gpsIndex = this.GetIndex(this.ifdIndexes, ExifTag.GPSIFDOffset); - } - - uint ifdLength = 2 + this.GetLength(this.ifdIndexes) + 4; - uint exifLength = this.GetLength(this.exifIndexes); - uint gpsLength = this.GetLength(this.gpsIndexes); + IExifValue exifOffset = GetOffsetValue(this.ifdValues, this.exifValues, ExifTag.SubIFDOffset); + IExifValue gpsOffset = GetOffsetValue(this.ifdValues, this.gpsValues, ExifTag.GPSIFDOffset); - if (exifLength > 0) + if (this.ifdValues.Count == 0 && this.exifValues.Count == 0 && this.gpsValues.Count == 0) { - exifLength += 2; + return Array.Empty(); } - if (gpsLength > 0) - { - gpsLength += 2; - } + uint ifdLength = this.GetLength(this.ifdValues) + 4U; + uint exifLength = this.GetLength(this.exifValues); + uint gpsLength = this.GetLength(this.gpsValues); length = ifdLength + exifLength + gpsLength; - if (length == 6) + if (length == 4U) { - return null; + return Array.Empty(); } - // two bytes for the byte Order marker 'II', followed by the number 42 (0x2A) and a 0, making 4 bytes total + // two bytes for the byte Order marker 'II' or 'MM', followed by the number 42 (0x2A) and a 0, making 4 bytes total length += (uint)ExifConstants.LittleEndianByteOrderMarker.Length; length += 4 + 2; @@ -91,38 +77,31 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif int i = 0; - // the byte order marker for little-endian, followed by the number 42 and a 0 + // The byte order marker for little-endian, followed by the number 42 and a 0 ExifConstants.LittleEndianByteOrderMarker.AsSpan().CopyTo(result.AsSpan(start: i)); i += ExifConstants.LittleEndianByteOrderMarker.Length; - uint ifdOffset = ((uint)i - startIndex) + 4; + uint ifdOffset = ((uint)i - startIndex) + 4U; uint thumbnailOffset = ifdOffset + ifdLength + exifLength + gpsLength; - if (exifLength > 0) - { - this.values[exifIndex] = this.values[exifIndex].WithValue(ifdOffset + ifdLength); - } - - if (gpsLength > 0) - { - this.values[gpsIndex] = this.values[gpsIndex].WithValue(ifdOffset + ifdLength + exifLength); - } + exifOffset?.TrySetValue(ifdOffset + ifdLength); + gpsOffset?.TrySetValue(ifdOffset + ifdLength + exifLength); i = WriteUInt32(ifdOffset, result, i); - i = this.WriteHeaders(this.ifdIndexes, result, i); + i = this.WriteHeaders(this.ifdValues, result, i); i = WriteUInt32(thumbnailOffset, result, i); - i = this.WriteData(startIndex, this.ifdIndexes, result, i); + i = this.WriteData(startIndex, this.ifdValues, result, i); if (exifLength > 0) { - i = this.WriteHeaders(this.exifIndexes, result, i); - i = this.WriteData(startIndex, this.exifIndexes, result, i); + i = this.WriteHeaders(this.exifValues, result, i); + i = this.WriteData(startIndex, this.exifValues, result, i); } if (gpsLength > 0) { - i = this.WriteHeaders(this.gpsIndexes, result, i); - i = this.WriteData(startIndex, this.gpsIndexes, result, i); + i = this.WriteHeaders(this.gpsValues, result, i); + i = this.WriteData(startIndex, this.gpsValues, result, i); } WriteUInt16(0, result, i); @@ -179,79 +158,137 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return offset + 4; } - private int GetIndex(IList indexes, ExifTag tag) + private static IExifValue GetOffsetValue(List ifdValues, List values, ExifTag offset) { - foreach (int index in indexes) + int index = -1; + + for (int i = 0; i < ifdValues.Count; i++) { - if (this.values[index].Tag == tag) + if (ifdValues[i].Tag == offset) { - return index; + index = i; } } - int newIndex = this.values.Count; - indexes.Add(newIndex); - this.values.Add(ExifValue.Create(tag, null)); - return newIndex; + if (values.Count > 0) + { + if (index != -1) + { + return ifdValues[index]; + } + + ExifValue result = ExifValues.Create(offset); + ifdValues.Add(result); + + return result; + } + else if (index != -1) + { + ifdValues.RemoveAt(index); + } + + return null; } - private List GetIndexes(ExifParts part, ExifTag[] tags) + private List GetPartValues(ExifParts part) { - if (((int)this.allowedParts & (int)part) == 0) + var result = new List(); + + if (!EnumUtils.HasFlag(this.allowedParts, part)) { - return new List(); + return result; } - var result = new List(); - for (int i = 0; i < this.values.Count; i++) + foreach (IExifValue value in this.values) { - ExifValue value = this.values[i]; - - if (!value.HasValue) + if (!HasValue(value)) { continue; } - int index = Array.IndexOf(tags, value.Tag); - if (index > -1) + if (ExifTags.GetPart(value.Tag) == part) { - result.Add(i); + result.Add(value); } } return result; } - private uint GetLength(IList indexes) + private static bool HasValue(IExifValue exifValue) + { + object value = exifValue.GetValue(); + if (value is null) + { + return false; + } + + if (exifValue.DataType == ExifDataType.Ascii) + { + string stringValue = (string)value; + return stringValue.Length > 0; + } + + if (value is Array arrayValue) + { + return arrayValue.Length > 0; + } + + return true; + } + + private uint GetLength(IList values) { - uint length = 0; + if (values.Count == 0) + { + return 0; + } - foreach (int index in indexes) + uint length = 2; + + foreach (IExifValue value in values) { - uint valueLength = (uint)this.values[index].Length; + uint valueLength = GetLength(value); + + length += 2 + 2 + 4 + 4; if (valueLength > 4) { - length += 12 + valueLength; - } - else - { - length += 12; + length += valueLength; } } return length; } - private int WriteArray(ExifValue value, Span destination, int offset) + private static uint GetLength(IExifValue value) => GetNumberOfComponents(value) * ExifDataTypes.GetSize(value.DataType); + + private static uint GetNumberOfComponents(IExifValue exifValue) + { + object value = exifValue.GetValue(); + + if (exifValue.DataType == ExifDataType.Ascii) + { + return (uint)Encoding.UTF8.GetBytes((string)value).Length + 1; + } + + if (value is Array arrayValue) + { + return (uint)arrayValue.Length; + } + + return 1; + } + + private int WriteArray(IExifValue value, Span destination, int offset) { if (value.DataType == ExifDataType.Ascii) { - return this.WriteValue(ExifDataType.Ascii, value.Value, destination, offset); + return this.WriteValue(ExifDataType.Ascii, value.GetValue(), destination, offset); } int newOffset = offset; - foreach (object obj in (Array)value.Value) + foreach (object obj in (Array)value.GetValue()) { newOffset = this.WriteValue(value.DataType, obj, destination, newOffset); } @@ -259,7 +296,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return newOffset; } - private int WriteData(uint startIndex, List indexes, Span destination, int offset) + private int WriteData(uint startIndex, List values, Span destination, int offset) { if (this.dataOffsets.Count == 0) { @@ -269,10 +306,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif int newOffset = offset; int i = 0; - foreach (int index in indexes) + foreach (IExifValue value in values) { - ExifValue value = this.values[index]; - if (value.Length > 4) + if (GetLength(value) > 4) { WriteUInt32((uint)(newOffset - startIndex), destination, this.dataOffsets[i++]); newOffset = this.WriteValue(value, destination, newOffset); @@ -282,25 +318,25 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif return newOffset; } - private int WriteHeaders(List indexes, Span destination, int offset) + private int WriteHeaders(List values, Span destination, int offset) { this.dataOffsets = new List(); - int newOffset = WriteUInt16((ushort)indexes.Count, destination, offset); + int newOffset = WriteUInt16((ushort)values.Count, destination, offset); - if (indexes.Count == 0) + if (values.Count == 0) { return newOffset; } - foreach (int index in indexes) + foreach (IExifValue value in values) { - ExifValue value = this.values[index]; newOffset = WriteUInt16((ushort)value.Tag, destination, newOffset); newOffset = WriteUInt16((ushort)value.DataType, destination, newOffset); - newOffset = WriteUInt32((uint)value.NumberOfComponents, destination, newOffset); + newOffset = WriteUInt32(GetNumberOfComponents(value), destination, newOffset); - if (value.Length > 4) + uint length = GetLength(value); + if (length > 4) { this.dataOffsets.Add(newOffset); } @@ -332,7 +368,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif switch (dataType) { case ExifDataType.Ascii: - return Write(Encoding.UTF8.GetBytes((string)value), destination, offset); + offset = Write(Encoding.UTF8.GetBytes((string)value), destination, offset); + destination[offset] = 0; + return offset + 1; case ExifDataType.Byte: case ExifDataType.Undefined: destination[offset] = (byte)value; @@ -340,8 +378,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif case ExifDataType.DoubleFloat: return WriteDouble((double)value, destination, offset); case ExifDataType.Short: + if (value is Number shortNumber) + { + return WriteUInt16((ushort)shortNumber, destination, offset); + } + return WriteUInt16((ushort)value, destination, offset); case ExifDataType.Long: + if (value is Number longNumber) + { + return WriteUInt32((uint)longNumber, destination, offset); + } + return WriteUInt32((uint)value, destination, offset); case ExifDataType.Rational: WriteRational(destination.Slice(offset, 8), (Rational)value); @@ -363,14 +411,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif } } - private int WriteValue(ExifValue value, Span destination, int offset) + private int WriteValue(IExifValue value, Span destination, int offset) { if (value.IsArray && value.DataType != ExifDataType.Ascii) { return this.WriteArray(value, destination, offset); } - return this.WriteValue(value.DataType, value.Value, destination, offset); + return this.WriteValue(value.DataType, value.GetValue(), destination, offset); } } } diff --git a/src/ImageSharp/Metadata/Profiles/Exif/README.md b/src/ImageSharp/Metadata/Profiles/Exif/README.md index b6e27b70c..7901527e1 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/README.md +++ b/src/ImageSharp/Metadata/Profiles/Exif/README.md @@ -1,3 +1,3 @@ -Adapted from Magick.NET: +Adapted from Magick.NET: -https://github.com/dlemstra/Magick.NET/tree/784e23b1f5c824fc03d4b95d3387b3efe1ed510b/Magick.NET/Core/Profiles/Exif \ No newline at end of file +https://github.com/dlemstra/Magick.NET diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs new file mode 100644 index 000000000..dc33fd8b0 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the FaxProfile exif tag. + /// + public static ExifTag FaxProfile { get; } = new ExifTag(ExifTagValue.FaxProfile); + + /// + /// Gets the ModeNumber exif tag. + /// + public static ExifTag ModeNumber { get; } = new ExifTag(ExifTagValue.ModeNumber); + + /// + /// Gets the GPSAltitudeRef exif tag. + /// + public static ExifTag GPSAltitudeRef { get; } = new ExifTag(ExifTagValue.GPSAltitudeRef); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs new file mode 100644 index 000000000..2bfa8ff21 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs @@ -0,0 +1,64 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the ClipPath exif tag. + /// + public static ExifTag ClipPath => new ExifTag(ExifTagValue.ClipPath); + + /// + /// Gets the VersionYear exif tag. + /// + public static ExifTag VersionYear => new ExifTag(ExifTagValue.VersionYear); + + /// + /// Gets the XMP exif tag. + /// + public static ExifTag XMP => new ExifTag(ExifTagValue.XMP); + + /// + /// Gets the CFAPattern2 exif tag. + /// + public static ExifTag CFAPattern2 => new ExifTag(ExifTagValue.CFAPattern2); + + /// + /// Gets the TIFFEPStandardID exif tag. + /// + public static ExifTag TIFFEPStandardID => new ExifTag(ExifTagValue.TIFFEPStandardID); + + /// + /// Gets the XPTitle exif tag. + /// + public static ExifTag XPTitle => new ExifTag(ExifTagValue.XPTitle); + + /// + /// Gets the XPComment exif tag. + /// + public static ExifTag XPComment => new ExifTag(ExifTagValue.XPComment); + + /// + /// Gets the XPAuthor exif tag. + /// + public static ExifTag XPAuthor => new ExifTag(ExifTagValue.XPAuthor); + + /// + /// Gets the XPKeywords exif tag. + /// + public static ExifTag XPKeywords => new ExifTag(ExifTagValue.XPKeywords); + + /// + /// Gets the XPSubject exif tag. + /// + public static ExifTag XPSubject => new ExifTag(ExifTagValue.XPSubject); + + /// + /// Gets the GPSVersionID exif tag. + /// + public static ExifTag GPSVersionID => new ExifTag(ExifTagValue.GPSVersionID); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs new file mode 100644 index 000000000..6cbae4c55 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs @@ -0,0 +1,29 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the PixelScale exif tag. + /// + public static ExifTag PixelScale { get; } = new ExifTag(ExifTagValue.PixelScale); + + /// + /// Gets the IntergraphMatrix exif tag. + /// + public static ExifTag IntergraphMatrix { get; } = new ExifTag(ExifTagValue.IntergraphMatrix); + + /// + /// Gets the ModelTiePoint exif tag. + /// + public static ExifTag ModelTiePoint { get; } = new ExifTag(ExifTagValue.ModelTiePoint); + + /// + /// Gets the ModelTransform exif tag. + /// + public static ExifTag ModelTransform { get; } = new ExifTag(ExifTagValue.ModelTransform); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs new file mode 100644 index 000000000..571b50efb --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs @@ -0,0 +1,114 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the SubfileType exif tag. + /// + public static ExifTag SubfileType { get; } = new ExifTag(ExifTagValue.SubfileType); + + /// + /// Gets the SubIFDOffset exif tag. + /// + public static ExifTag SubIFDOffset { get; } = new ExifTag(ExifTagValue.SubIFDOffset); + + /// + /// Gets the GPSIFDOffset exif tag. + /// + public static ExifTag GPSIFDOffset { get; } = new ExifTag(ExifTagValue.GPSIFDOffset); + + /// + /// Gets the T4Options exif tag. + /// + public static ExifTag T4Options { get; } = new ExifTag(ExifTagValue.T4Options); + + /// + /// Gets the T6Options exif tag. + /// + public static ExifTag T6Options { get; } = new ExifTag(ExifTagValue.T6Options); + + /// + /// Gets the XClipPathUnits exif tag. + /// + public static ExifTag XClipPathUnits { get; } = new ExifTag(ExifTagValue.XClipPathUnits); + + /// + /// Gets the YClipPathUnits exif tag. + /// + public static ExifTag YClipPathUnits { get; } = new ExifTag(ExifTagValue.YClipPathUnits); + + /// + /// Gets the ProfileType exif tag. + /// + public static ExifTag ProfileType { get; } = new ExifTag(ExifTagValue.ProfileType); + + /// + /// Gets the CodingMethods exif tag. + /// + public static ExifTag CodingMethods { get; } = new ExifTag(ExifTagValue.CodingMethods); + + /// + /// Gets the T82ptions exif tag. + /// + public static ExifTag T82ptions { get; } = new ExifTag(ExifTagValue.T82ptions); + + /// + /// Gets the JPEGInterchangeFormat exif tag. + /// + public static ExifTag JPEGInterchangeFormat { get; } = new ExifTag(ExifTagValue.JPEGInterchangeFormat); + + /// + /// Gets the JPEGInterchangeFormatLength exif tag. + /// + public static ExifTag JPEGInterchangeFormatLength { get; } = new ExifTag(ExifTagValue.JPEGInterchangeFormatLength); + + /// + /// Gets the MDFileTag exif tag. + /// + public static ExifTag MDFileTag { get; } = new ExifTag(ExifTagValue.MDFileTag); + + /// + /// Gets the StandardOutputSensitivity exif tag. + /// + public static ExifTag StandardOutputSensitivity { get; } = new ExifTag(ExifTagValue.StandardOutputSensitivity); + + /// + /// Gets the RecommendedExposureIndex exif tag. + /// + public static ExifTag RecommendedExposureIndex { get; } = new ExifTag(ExifTagValue.RecommendedExposureIndex); + + /// + /// Gets the ISOSpeed exif tag. + /// + public static ExifTag ISOSpeed { get; } = new ExifTag(ExifTagValue.ISOSpeed); + + /// + /// Gets the ISOSpeedLatitudeyyy exif tag. + /// + public static ExifTag ISOSpeedLatitudeyyy { get; } = new ExifTag(ExifTagValue.ISOSpeedLatitudeyyy); + + /// + /// Gets the ISOSpeedLatitudezzz exif tag. + /// + public static ExifTag ISOSpeedLatitudezzz { get; } = new ExifTag(ExifTagValue.ISOSpeedLatitudezzz); + + /// + /// Gets the FaxRecvParams exif tag. + /// + public static ExifTag FaxRecvParams { get; } = new ExifTag(ExifTagValue.FaxRecvParams); + + /// + /// Gets the FaxRecvTime exif tag. + /// + public static ExifTag FaxRecvTime { get; } = new ExifTag(ExifTagValue.FaxRecvTime); + + /// + /// Gets the ImageNumber exif tag. + /// + public static ExifTag ImageNumber { get; } = new ExifTag(ExifTagValue.ImageNumber); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs new file mode 100644 index 000000000..120f2dab0 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs @@ -0,0 +1,69 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the FreeOffsets exif tag. + /// + public static ExifTag FreeOffsets { get; } = new ExifTag(ExifTagValue.FreeOffsets); + + /// + /// Gets the FreeByteCounts exif tag. + /// + public static ExifTag FreeByteCounts { get; } = new ExifTag(ExifTagValue.FreeByteCounts); + + /// + /// Gets the ColorResponseUnit exif tag. + /// + public static ExifTag ColorResponseUnit { get; } = new ExifTag(ExifTagValue.ColorResponseUnit); + + /// + /// Gets the TileOffsets exif tag. + /// + public static ExifTag TileOffsets { get; } = new ExifTag(ExifTagValue.TileOffsets); + + /// + /// Gets the SMinSampleValue exif tag. + /// + public static ExifTag SMinSampleValue { get; } = new ExifTag(ExifTagValue.SMinSampleValue); + + /// + /// Gets the SMaxSampleValue exif tag. + /// + public static ExifTag SMaxSampleValue { get; } = new ExifTag(ExifTagValue.SMaxSampleValue); + + /// + /// Gets the JPEGQTables exif tag. + /// + public static ExifTag JPEGQTables { get; } = new ExifTag(ExifTagValue.JPEGQTables); + + /// + /// Gets the JPEGDCTables exif tag. + /// + public static ExifTag JPEGDCTables { get; } = new ExifTag(ExifTagValue.JPEGDCTables); + + /// + /// Gets the JPEGACTables exif tag. + /// + public static ExifTag JPEGACTables { get; } = new ExifTag(ExifTagValue.JPEGACTables); + + /// + /// Gets the StripRowCounts exif tag. + /// + public static ExifTag StripRowCounts { get; } = new ExifTag(ExifTagValue.StripRowCounts); + + /// + /// Gets the IntergraphRegisters exif tag. + /// + public static ExifTag IntergraphRegisters { get; } = new ExifTag(ExifTagValue.IntergraphRegisters); + + /// + /// Gets the TimeZoneOffset exif tag. + /// + public static ExifTag TimeZoneOffset { get; } = new ExifTag(ExifTagValue.TimeZoneOffset); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs new file mode 100644 index 000000000..7f6be3c4d --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs @@ -0,0 +1,51 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the ImageWidth exif tag. + /// + public static ExifTag ImageWidth { get; } = new ExifTag(ExifTagValue.ImageWidth); + + /// + /// Gets the ImageLength exif tag. + /// + public static ExifTag ImageLength { get; } = new ExifTag(ExifTagValue.ImageLength); + + /// + /// Gets the TileWidth exif tag. + /// + public static ExifTag TileWidth { get; } = new ExifTag(ExifTagValue.TileWidth); + + /// + /// Gets the TileLength exif tag. + /// + public static ExifTag TileLength { get; } = new ExifTag(ExifTagValue.TileLength); + + /// + /// Gets the BadFaxLines exif tag. + /// + public static ExifTag BadFaxLines { get; } = new ExifTag(ExifTagValue.BadFaxLines); + + /// + /// Gets the ConsecutiveBadFaxLines exif tag. + /// + public static ExifTag ConsecutiveBadFaxLines { get; } = new ExifTag(ExifTagValue.ConsecutiveBadFaxLines); + + /// + /// Gets the PixelXDimension exif tag. + /// + public static ExifTag PixelXDimension { get; } = new ExifTag(ExifTagValue.PixelXDimension); + + /// + /// Gets the PixelYDimension exif tag. + /// + public static ExifTag PixelYDimension { get; } = new ExifTag(ExifTagValue.PixelYDimension); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs new file mode 100644 index 000000000..b4feba056 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the StripOffsets exif tag. + /// + public static ExifTag StripOffsets { get; } = new ExifTag(ExifTagValue.StripOffsets); + + /// + /// Gets the TileByteCounts exif tag. + /// + public static ExifTag TileByteCounts { get; } = new ExifTag(ExifTagValue.TileByteCounts); + + /// + /// Gets the ImageLayer exif tag. + /// + public static ExifTag ImageLayer { get; } = new ExifTag(ExifTagValue.ImageLayer); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs new file mode 100644 index 000000000..db52bbb22 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs @@ -0,0 +1,176 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the XPosition exif tag. + /// + public static ExifTag XPosition { get; } = new ExifTag(ExifTagValue.XPosition); + + /// + /// Gets the YPosition exif tag. + /// + public static ExifTag YPosition { get; } = new ExifTag(ExifTagValue.YPosition); + + /// + /// Gets the XResolution exif tag. + /// + public static ExifTag XResolution { get; } = new ExifTag(ExifTagValue.XResolution); + + /// + /// Gets the YResolution exif tag. + /// + public static ExifTag YResolution { get; } = new ExifTag(ExifTagValue.YResolution); + + /// + /// Gets the BatteryLevel exif tag. + /// + public static ExifTag BatteryLevel { get; } = new ExifTag(ExifTagValue.BatteryLevel); + + /// + /// Gets the ExposureTime exif tag. + /// + public static ExifTag ExposureTime { get; } = new ExifTag(ExifTagValue.ExposureTime); + + /// + /// Gets the FNumber exif tag. + /// + public static ExifTag FNumber { get; } = new ExifTag(ExifTagValue.FNumber); + + /// + /// Gets the MDScalePixel exif tag. + /// + public static ExifTag MDScalePixel { get; } = new ExifTag(ExifTagValue.MDScalePixel); + + /// + /// Gets the CompressedBitsPerPixel exif tag. + /// + public static ExifTag CompressedBitsPerPixel { get; } = new ExifTag(ExifTagValue.CompressedBitsPerPixel); + + /// + /// Gets the ApertureValue exif tag. + /// + public static ExifTag ApertureValue { get; } = new ExifTag(ExifTagValue.ApertureValue); + + /// + /// Gets the MaxApertureValue exif tag. + /// + public static ExifTag MaxApertureValue { get; } = new ExifTag(ExifTagValue.MaxApertureValue); + + /// + /// Gets the SubjectDistance exif tag. + /// + public static ExifTag SubjectDistance { get; } = new ExifTag(ExifTagValue.SubjectDistance); + + /// + /// Gets the FocalLength exif tag. + /// + public static ExifTag FocalLength { get; } = new ExifTag(ExifTagValue.FocalLength); + + /// + /// Gets the FlashEnergy2 exif tag. + /// + public static ExifTag FlashEnergy2 { get; } = new ExifTag(ExifTagValue.FlashEnergy2); + + /// + /// Gets the FocalPlaneXResolution2 exif tag. + /// + public static ExifTag FocalPlaneXResolution2 { get; } = new ExifTag(ExifTagValue.FocalPlaneXResolution2); + + /// + /// Gets the FocalPlaneYResolution2 exif tag. + /// + public static ExifTag FocalPlaneYResolution2 { get; } = new ExifTag(ExifTagValue.FocalPlaneYResolution2); + + /// + /// Gets the ExposureIndex2 exif tag. + /// + public static ExifTag ExposureIndex2 { get; } = new ExifTag(ExifTagValue.ExposureIndex2); + + /// + /// Gets the Humidity exif tag. + /// + public static ExifTag Humidity { get; } = new ExifTag(ExifTagValue.Humidity); + + /// + /// Gets the Pressure exif tag. + /// + public static ExifTag Pressure { get; } = new ExifTag(ExifTagValue.Pressure); + + /// + /// Gets the Acceleration exif tag. + /// + public static ExifTag Acceleration { get; } = new ExifTag(ExifTagValue.Acceleration); + + /// + /// Gets the FlashEnergy exif tag. + /// + public static ExifTag FlashEnergy { get; } = new ExifTag(ExifTagValue.FlashEnergy); + + /// + /// Gets the FocalPlaneXResolution exif tag. + /// + public static ExifTag FocalPlaneXResolution { get; } = new ExifTag(ExifTagValue.FocalPlaneXResolution); + + /// + /// Gets the FocalPlaneYResolution exif tag. + /// + public static ExifTag FocalPlaneYResolution { get; } = new ExifTag(ExifTagValue.FocalPlaneYResolution); + + /// + /// Gets the ExposureIndex exif tag. + /// + public static ExifTag ExposureIndex { get; } = new ExifTag(ExifTagValue.ExposureIndex); + + /// + /// Gets the DigitalZoomRatio exif tag. + /// + public static ExifTag DigitalZoomRatio { get; } = new ExifTag(ExifTagValue.DigitalZoomRatio); + + /// + /// Gets the LensInfo exif tag. + /// + public static ExifTag LensInfo { get; } = new ExifTag(ExifTagValue.LensInfo); + + /// + /// Gets the GPSAltitude exif tag. + /// + public static ExifTag GPSAltitude { get; } = new ExifTag(ExifTagValue.GPSAltitude); + + /// + /// Gets the GPSDOP exif tag. + /// + public static ExifTag GPSDOP { get; } = new ExifTag(ExifTagValue.GPSDOP); + + /// + /// Gets the GPSSpeed exif tag. + /// + public static ExifTag GPSSpeed { get; } = new ExifTag(ExifTagValue.GPSSpeed); + + /// + /// Gets the GPSTrack exif tag. + /// + public static ExifTag GPSTrack { get; } = new ExifTag(ExifTagValue.GPSTrack); + + /// + /// Gets the GPSImgDirection exif tag. + /// + public static ExifTag GPSImgDirection { get; } = new ExifTag(ExifTagValue.GPSImgDirection); + + /// + /// Gets the GPSDestBearing exif tag. + /// + public static ExifTag GPSDestBearing { get; } = new ExifTag(ExifTagValue.GPSDestBearing); + + /// + /// Gets the GPSDestDistance exif tag. + /// + public static ExifTag GPSDestDistance { get; } = new ExifTag(ExifTagValue.GPSDestDistance); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs new file mode 100644 index 000000000..ece06c247 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs @@ -0,0 +1,56 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the WhitePoint exif tag. + /// + public static ExifTag WhitePoint { get; } = new ExifTag(ExifTagValue.WhitePoint); + + /// + /// Gets the PrimaryChromaticities exif tag. + /// + public static ExifTag PrimaryChromaticities { get; } = new ExifTag(ExifTagValue.PrimaryChromaticities); + + /// + /// Gets the YCbCrCoefficients exif tag. + /// + public static ExifTag YCbCrCoefficients { get; } = new ExifTag(ExifTagValue.YCbCrCoefficients); + + /// + /// Gets the ReferenceBlackWhite exif tag. + /// + public static ExifTag ReferenceBlackWhite { get; } = new ExifTag(ExifTagValue.ReferenceBlackWhite); + + /// + /// Gets the GPSLatitude exif tag. + /// + public static ExifTag GPSLatitude { get; } = new ExifTag(ExifTagValue.GPSLatitude); + + /// + /// Gets the GPSLongitude exif tag. + /// + public static ExifTag GPSLongitude { get; } = new ExifTag(ExifTagValue.GPSLongitude); + + /// + /// Gets the GPSTimestamp exif tag. + /// + public static ExifTag GPSTimestamp { get; } = new ExifTag(ExifTagValue.GPSTimestamp); + + /// + /// Gets the GPSDestLatitude exif tag. + /// + public static ExifTag GPSDestLatitude { get; } = new ExifTag(ExifTagValue.GPSDestLatitude); + + /// + /// Gets the GPSDestLongitude exif tag. + /// + public static ExifTag GPSDestLongitude { get; } = new ExifTag(ExifTagValue.GPSDestLongitude); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs new file mode 100644 index 000000000..7fe9a58bc --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs @@ -0,0 +1,239 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the OldSubfileType exif tag. + /// + public static ExifTag OldSubfileType { get; } = new ExifTag(ExifTagValue.OldSubfileType); + + /// + /// Gets the Compression exif tag. + /// + public static ExifTag Compression { get; } = new ExifTag(ExifTagValue.Compression); + + /// + /// Gets the PhotometricInterpretation exif tag. + /// + public static ExifTag PhotometricInterpretation { get; } = new ExifTag(ExifTagValue.PhotometricInterpretation); + + /// + /// Gets the Thresholding exif tag. + /// + public static ExifTag Thresholding { get; } = new ExifTag(ExifTagValue.Thresholding); + + /// + /// Gets the CellWidth exif tag. + /// + public static ExifTag CellWidth { get; } = new ExifTag(ExifTagValue.CellWidth); + + /// + /// Gets the CellLength exif tag. + /// + public static ExifTag CellLength { get; } = new ExifTag(ExifTagValue.CellLength); + + /// + /// Gets the FillOrder exif tag. + /// + public static ExifTag FillOrder { get; } = new ExifTag(ExifTagValue.FillOrder); + + /// + /// Gets the Orientation exif tag. + /// + public static ExifTag Orientation { get; } = new ExifTag(ExifTagValue.Orientation); + + /// + /// Gets the SamplesPerPixel exif tag. + /// + public static ExifTag SamplesPerPixel { get; } = new ExifTag(ExifTagValue.SamplesPerPixel); + + /// + /// Gets the PlanarConfiguration exif tag. + /// + public static ExifTag PlanarConfiguration { get; } = new ExifTag(ExifTagValue.PlanarConfiguration); + + /// + /// Gets the GrayResponseUnit exif tag. + /// + public static ExifTag GrayResponseUnit { get; } = new ExifTag(ExifTagValue.GrayResponseUnit); + + /// + /// Gets the ResolutionUnit exif tag. + /// + public static ExifTag ResolutionUnit { get; } = new ExifTag(ExifTagValue.ResolutionUnit); + + /// + /// Gets the CleanFaxData exif tag. + /// + public static ExifTag CleanFaxData { get; } = new ExifTag(ExifTagValue.CleanFaxData); + + /// + /// Gets the InkSet exif tag. + /// + public static ExifTag InkSet { get; } = new ExifTag(ExifTagValue.InkSet); + + /// + /// Gets the NumberOfInks exif tag. + /// + public static ExifTag NumberOfInks { get; } = new ExifTag(ExifTagValue.NumberOfInks); + + /// + /// Gets the DotRange exif tag. + /// + public static ExifTag DotRange { get; } = new ExifTag(ExifTagValue.DotRange); + + /// + /// Gets the Indexed exif tag. + /// + public static ExifTag Indexed { get; } = new ExifTag(ExifTagValue.Indexed); + + /// + /// Gets the OPIProxy exif tag. + /// + public static ExifTag OPIProxy { get; } = new ExifTag(ExifTagValue.OPIProxy); + + /// + /// Gets the JPEGProc exif tag. + /// + public static ExifTag JPEGProc { get; } = new ExifTag(ExifTagValue.JPEGProc); + + /// + /// Gets the JPEGRestartInterval exif tag. + /// + public static ExifTag JPEGRestartInterval { get; } = new ExifTag(ExifTagValue.JPEGRestartInterval); + + /// + /// Gets the YCbCrPositioning exif tag. + /// + public static ExifTag YCbCrPositioning { get; } = new ExifTag(ExifTagValue.YCbCrPositioning); + + /// + /// Gets the Rating exif tag. + /// + public static ExifTag Rating { get; } = new ExifTag(ExifTagValue.Rating); + + /// + /// Gets the RatingPercent exif tag. + /// + public static ExifTag RatingPercent { get; } = new ExifTag(ExifTagValue.RatingPercent); + + /// + /// Gets the ExposureProgram exif tag. + /// + public static ExifTag ExposureProgram { get; } = new ExifTag(ExifTagValue.ExposureProgram); + + /// + /// Gets the Interlace exif tag. + /// + public static ExifTag Interlace { get; } = new ExifTag(ExifTagValue.Interlace); + + /// + /// Gets the SelfTimerMode exif tag. + /// + public static ExifTag SelfTimerMode { get; } = new ExifTag(ExifTagValue.SelfTimerMode); + + /// + /// Gets the SensitivityType exif tag. + /// + public static ExifTag SensitivityType { get; } = new ExifTag(ExifTagValue.SensitivityType); + + /// + /// Gets the MeteringMode exif tag. + /// + public static ExifTag MeteringMode { get; } = new ExifTag(ExifTagValue.MeteringMode); + + /// + /// Gets the LightSource exif tag. + /// + public static ExifTag LightSource { get; } = new ExifTag(ExifTagValue.LightSource); + + /// + /// Gets the FocalPlaneResolutionUnit2 exif tag. + /// + public static ExifTag FocalPlaneResolutionUnit2 { get; } = new ExifTag(ExifTagValue.FocalPlaneResolutionUnit2); + + /// + /// Gets the SensingMethod2 exif tag. + /// + public static ExifTag SensingMethod2 { get; } = new ExifTag(ExifTagValue.SensingMethod2); + + /// + /// Gets the Flash exif tag. + /// + public static ExifTag Flash { get; } = new ExifTag(ExifTagValue.Flash); + + /// + /// Gets the ColorSpace exif tag. + /// + public static ExifTag ColorSpace { get; } = new ExifTag(ExifTagValue.ColorSpace); + + /// + /// Gets the FocalPlaneResolutionUnit exif tag. + /// + public static ExifTag FocalPlaneResolutionUnit { get; } = new ExifTag(ExifTagValue.FocalPlaneResolutionUnit); + + /// + /// Gets the SensingMethod exif tag. + /// + public static ExifTag SensingMethod { get; } = new ExifTag(ExifTagValue.SensingMethod); + + /// + /// Gets the CustomRendered exif tag. + /// + public static ExifTag CustomRendered { get; } = new ExifTag(ExifTagValue.CustomRendered); + + /// + /// Gets the ExposureMode exif tag. + /// + public static ExifTag ExposureMode { get; } = new ExifTag(ExifTagValue.ExposureMode); + + /// + /// Gets the WhiteBalance exif tag. + /// + public static ExifTag WhiteBalance { get; } = new ExifTag(ExifTagValue.WhiteBalance); + + /// + /// Gets the FocalLengthIn35mmFilm exif tag. + /// + public static ExifTag FocalLengthIn35mmFilm { get; } = new ExifTag(ExifTagValue.FocalLengthIn35mmFilm); + + /// + /// Gets the SceneCaptureType exif tag. + /// + public static ExifTag SceneCaptureType { get; } = new ExifTag(ExifTagValue.SceneCaptureType); + + /// + /// Gets the GainControl exif tag. + /// + public static ExifTag GainControl { get; } = new ExifTag(ExifTagValue.GainControl); + + /// + /// Gets the Contrast exif tag. + /// + public static ExifTag Contrast { get; } = new ExifTag(ExifTagValue.Contrast); + + /// + /// Gets the Saturation exif tag. + /// + public static ExifTag Saturation { get; } = new ExifTag(ExifTagValue.Saturation); + + /// + /// Gets the Sharpness exif tag. + /// + public static ExifTag Sharpness { get; } = new ExifTag(ExifTagValue.Sharpness); + + /// + /// Gets the SubjectDistanceRange exif tag. + /// + public static ExifTag SubjectDistanceRange { get; } = new ExifTag(ExifTagValue.SubjectDistanceRange); + + /// + /// Gets the GPSDifferential exif tag. + /// + public static ExifTag GPSDifferential { get; } = new ExifTag(ExifTagValue.GPSDifferential); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs new file mode 100644 index 000000000..90485f75a --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs @@ -0,0 +1,114 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the BitsPerSample exif tag. + /// + public static ExifTag BitsPerSample { get; } = new ExifTag(ExifTagValue.BitsPerSample); + + /// + /// Gets the MinSampleValue exif tag. + /// + public static ExifTag MinSampleValue { get; } = new ExifTag(ExifTagValue.MinSampleValue); + + /// + /// Gets the MaxSampleValue exif tag. + /// + public static ExifTag MaxSampleValue { get; } = new ExifTag(ExifTagValue.MaxSampleValue); + + /// + /// Gets the GrayResponseCurve exif tag. + /// + public static ExifTag GrayResponseCurve { get; } = new ExifTag(ExifTagValue.GrayResponseCurve); + + /// + /// Gets the ColorMap exif tag. + /// + public static ExifTag ColorMap { get; } = new ExifTag(ExifTagValue.ColorMap); + + /// + /// Gets the ExtraSamples exif tag. + /// + public static ExifTag ExtraSamples { get; } = new ExifTag(ExifTagValue.ExtraSamples); + + /// + /// Gets the PageNumber exif tag. + /// + public static ExifTag PageNumber { get; } = new ExifTag(ExifTagValue.PageNumber); + + /// + /// Gets the TransferFunction exif tag. + /// + public static ExifTag TransferFunction { get; } = new ExifTag(ExifTagValue.TransferFunction); + + /// + /// Gets the Predictor exif tag. + /// + public static ExifTag Predictor { get; } = new ExifTag(ExifTagValue.Predictor); + + /// + /// Gets the HalftoneHints exif tag. + /// + public static ExifTag HalftoneHints { get; } = new ExifTag(ExifTagValue.HalftoneHints); + + /// + /// Gets the SampleFormat exif tag. + /// + public static ExifTag SampleFormat { get; } = new ExifTag(ExifTagValue.SampleFormat); + + /// + /// Gets the TransferRange exif tag. + /// + public static ExifTag TransferRange { get; } = new ExifTag(ExifTagValue.TransferRange); + + /// + /// Gets the DefaultImageColor exif tag. + /// + public static ExifTag DefaultImageColor { get; } = new ExifTag(ExifTagValue.DefaultImageColor); + + /// + /// Gets the JPEGLosslessPredictors exif tag. + /// + public static ExifTag JPEGLosslessPredictors { get; } = new ExifTag(ExifTagValue.JPEGLosslessPredictors); + + /// + /// Gets the JPEGPointTransforms exif tag. + /// + public static ExifTag JPEGPointTransforms { get; } = new ExifTag(ExifTagValue.JPEGPointTransforms); + + /// + /// Gets the YCbCrSubsampling exif tag. + /// + public static ExifTag YCbCrSubsampling { get; } = new ExifTag(ExifTagValue.YCbCrSubsampling); + + /// + /// Gets the CFARepeatPatternDim exif tag. + /// + public static ExifTag CFARepeatPatternDim { get; } = new ExifTag(ExifTagValue.CFARepeatPatternDim); + + /// + /// Gets the IntergraphPacketData exif tag. + /// + public static ExifTag IntergraphPacketData { get; } = new ExifTag(ExifTagValue.IntergraphPacketData); + + /// + /// Gets the ISOSpeedRatings exif tag. + /// + public static ExifTag ISOSpeedRatings { get; } = new ExifTag(ExifTagValue.ISOSpeedRatings); + + /// + /// Gets the SubjectArea exif tag. + /// + public static ExifTag SubjectArea { get; } = new ExifTag(ExifTagValue.SubjectArea); + + /// + /// Gets the SubjectLocation exif tag. + /// + public static ExifTag SubjectLocation { get; } = new ExifTag(ExifTagValue.SubjectLocation); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs new file mode 100644 index 000000000..58a713411 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the ShutterSpeedValue exif tag. + /// + public static ExifTag ShutterSpeedValue { get; } = new ExifTag(ExifTagValue.ShutterSpeedValue); + + /// + /// Gets the BrightnessValue exif tag. + /// + public static ExifTag BrightnessValue { get; } = new ExifTag(ExifTagValue.BrightnessValue); + + /// + /// Gets the ExposureBiasValue exif tag. + /// + public static ExifTag ExposureBiasValue { get; } = new ExifTag(ExifTagValue.ExposureBiasValue); + + /// + /// Gets the AmbientTemperature exif tag. + /// + public static ExifTag AmbientTemperature { get; } = new ExifTag(ExifTagValue.AmbientTemperature); + + /// + /// Gets the WaterDepth exif tag. + /// + public static ExifTag WaterDepth { get; } = new ExifTag(ExifTagValue.WaterDepth); + + /// + /// Gets the CameraElevationAngle exif tag. + /// + public static ExifTag CameraElevationAngle { get; } = new ExifTag(ExifTagValue.CameraElevationAngle); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs new file mode 100644 index 000000000..4022f5c1a --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs @@ -0,0 +1,16 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the Decode exif tag. + /// + public static ExifTag Decode { get; } = new ExifTag(ExifTagValue.Decode); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs new file mode 100644 index 000000000..506f87454 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs @@ -0,0 +1,279 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the ImageDescription exif tag. + /// + public static ExifTag ImageDescription { get; } = new ExifTag(ExifTagValue.ImageDescription); + + /// + /// Gets the Make exif tag. + /// + public static ExifTag Make { get; } = new ExifTag(ExifTagValue.Make); + + /// + /// Gets the Model exif tag. + /// + public static ExifTag Model { get; } = new ExifTag(ExifTagValue.Model); + + /// + /// Gets the Software exif tag. + /// + public static ExifTag Software { get; } = new ExifTag(ExifTagValue.Software); + + /// + /// Gets the DateTime exif tag. + /// + public static ExifTag DateTime { get; } = new ExifTag(ExifTagValue.DateTime); + + /// + /// Gets the Artist exif tag. + /// + public static ExifTag Artist { get; } = new ExifTag(ExifTagValue.Artist); + + /// + /// Gets the HostComputer exif tag. + /// + public static ExifTag HostComputer { get; } = new ExifTag(ExifTagValue.HostComputer); + + /// + /// Gets the Copyright exif tag. + /// + public static ExifTag Copyright { get; } = new ExifTag(ExifTagValue.Copyright); + + /// + /// Gets the DocumentName exif tag. + /// + public static ExifTag DocumentName { get; } = new ExifTag(ExifTagValue.DocumentName); + + /// + /// Gets the PageName exif tag. + /// + public static ExifTag PageName { get; } = new ExifTag(ExifTagValue.PageName); + + /// + /// Gets the InkNames exif tag. + /// + public static ExifTag InkNames { get; } = new ExifTag(ExifTagValue.InkNames); + + /// + /// Gets the TargetPrinter exif tag. + /// + public static ExifTag TargetPrinter { get; } = new ExifTag(ExifTagValue.TargetPrinter); + + /// + /// Gets the ImageID exif tag. + /// + public static ExifTag ImageID { get; } = new ExifTag(ExifTagValue.ImageID); + + /// + /// Gets the MDLabName exif tag. + /// + public static ExifTag MDLabName { get; } = new ExifTag(ExifTagValue.MDLabName); + + /// + /// Gets the MDSampleInfo exif tag. + /// + public static ExifTag MDSampleInfo { get; } = new ExifTag(ExifTagValue.MDSampleInfo); + + /// + /// Gets the MDPrepDate exif tag. + /// + public static ExifTag MDPrepDate { get; } = new ExifTag(ExifTagValue.MDPrepDate); + + /// + /// Gets the MDPrepTime exif tag. + /// + public static ExifTag MDPrepTime { get; } = new ExifTag(ExifTagValue.MDPrepTime); + + /// + /// Gets the MDFileUnits exif tag. + /// + public static ExifTag MDFileUnits => new ExifTag(ExifTagValue.MDFileUnits); + + /// + /// Gets the SEMInfo exif tag. + /// + public static ExifTag SEMInfo { get; } = new ExifTag(ExifTagValue.SEMInfo); + + /// + /// Gets the SpectralSensitivity exif tag. + /// + public static ExifTag SpectralSensitivity { get; } = new ExifTag(ExifTagValue.SpectralSensitivity); + + /// + /// Gets the DateTimeOriginal exif tag. + /// + public static ExifTag DateTimeOriginal { get; } = new ExifTag(ExifTagValue.DateTimeOriginal); + + /// + /// Gets the DateTimeDigitized exif tag. + /// + public static ExifTag DateTimeDigitized { get; } = new ExifTag(ExifTagValue.DateTimeDigitized); + + /// + /// Gets the SubsecTime exif tag. + /// + public static ExifTag SubsecTime { get; } = new ExifTag(ExifTagValue.SubsecTime); + + /// + /// Gets the SubsecTimeOriginal exif tag. + /// + public static ExifTag SubsecTimeOriginal { get; } = new ExifTag(ExifTagValue.SubsecTimeOriginal); + + /// + /// Gets the SubsecTimeDigitized exif tag. + /// + public static ExifTag SubsecTimeDigitized { get; } = new ExifTag(ExifTagValue.SubsecTimeDigitized); + + /// + /// Gets the RelatedSoundFile exif tag. + /// + public static ExifTag RelatedSoundFile { get; } = new ExifTag(ExifTagValue.RelatedSoundFile); + + /// + /// Gets the FaxSubaddress exif tag. + /// + public static ExifTag FaxSubaddress { get; } = new ExifTag(ExifTagValue.FaxSubaddress); + + /// + /// Gets the OffsetTime exif tag. + /// + public static ExifTag OffsetTime { get; } = new ExifTag(ExifTagValue.OffsetTime); + + /// + /// Gets the OffsetTimeOriginal exif tag. + /// + public static ExifTag OffsetTimeOriginal { get; } = new ExifTag(ExifTagValue.OffsetTimeOriginal); + + /// + /// Gets the OffsetTimeDigitized exif tag. + /// + public static ExifTag OffsetTimeDigitized { get; } = new ExifTag(ExifTagValue.OffsetTimeDigitized); + + /// + /// Gets the SecurityClassification exif tag. + /// + public static ExifTag SecurityClassification { get; } = new ExifTag(ExifTagValue.SecurityClassification); + + /// + /// Gets the ImageHistory exif tag. + /// + public static ExifTag ImageHistory { get; } = new ExifTag(ExifTagValue.ImageHistory); + + /// + /// Gets the ImageUniqueID exif tag. + /// + public static ExifTag ImageUniqueID { get; } = new ExifTag(ExifTagValue.ImageUniqueID); + + /// + /// Gets the OwnerName exif tag. + /// + public static ExifTag OwnerName { get; } = new ExifTag(ExifTagValue.OwnerName); + + /// + /// Gets the SerialNumber exif tag. + /// + public static ExifTag SerialNumber { get; } = new ExifTag(ExifTagValue.SerialNumber); + + /// + /// Gets the LensMake exif tag. + /// + public static ExifTag LensMake { get; } = new ExifTag(ExifTagValue.LensMake); + + /// + /// Gets the LensModel exif tag. + /// + public static ExifTag LensModel { get; } = new ExifTag(ExifTagValue.LensModel); + + /// + /// Gets the LensSerialNumber exif tag. + /// + public static ExifTag LensSerialNumber { get; } = new ExifTag(ExifTagValue.LensSerialNumber); + + /// + /// Gets the GDALMetadata exif tag. + /// + public static ExifTag GDALMetadata { get; } = new ExifTag(ExifTagValue.GDALMetadata); + + /// + /// Gets the GDALNoData exif tag. + /// + public static ExifTag GDALNoData { get; } = new ExifTag(ExifTagValue.GDALNoData); + + /// + /// Gets the GPSLatitudeRef exif tag. + /// + public static ExifTag GPSLatitudeRef { get; } = new ExifTag(ExifTagValue.GPSLatitudeRef); + + /// + /// Gets the GPSLongitudeRef exif tag. + /// + public static ExifTag GPSLongitudeRef { get; } = new ExifTag(ExifTagValue.GPSLongitudeRef); + + /// + /// Gets the GPSSatellites exif tag. + /// + public static ExifTag GPSSatellites { get; } = new ExifTag(ExifTagValue.GPSSatellites); + + /// + /// Gets the GPSStatus exif tag. + /// + public static ExifTag GPSStatus { get; } = new ExifTag(ExifTagValue.GPSStatus); + + /// + /// Gets the GPSMeasureMode exif tag. + /// + public static ExifTag GPSMeasureMode { get; } = new ExifTag(ExifTagValue.GPSMeasureMode); + + /// + /// Gets the GPSSpeedRef exif tag. + /// + public static ExifTag GPSSpeedRef { get; } = new ExifTag(ExifTagValue.GPSSpeedRef); + + /// + /// Gets the GPSTrackRef exif tag. + /// + public static ExifTag GPSTrackRef { get; } = new ExifTag(ExifTagValue.GPSTrackRef); + + /// + /// Gets the GPSImgDirectionRef exif tag. + /// + public static ExifTag GPSImgDirectionRef { get; } = new ExifTag(ExifTagValue.GPSImgDirectionRef); + + /// + /// Gets the GPSMapDatum exif tag. + /// + public static ExifTag GPSMapDatum { get; } = new ExifTag(ExifTagValue.GPSMapDatum); + + /// + /// Gets the GPSDestLatitudeRef exif tag. + /// + public static ExifTag GPSDestLatitudeRef { get; } = new ExifTag(ExifTagValue.GPSDestLatitudeRef); + + /// + /// Gets the GPSDestLongitudeRef exif tag. + /// + public static ExifTag GPSDestLongitudeRef { get; } = new ExifTag(ExifTagValue.GPSDestLongitudeRef); + + /// + /// Gets the GPSDestBearingRef exif tag. + /// + public static ExifTag GPSDestBearingRef { get; } = new ExifTag(ExifTagValue.GPSDestBearingRef); + + /// + /// Gets the GPSDestDistanceRef exif tag. + /// + public static ExifTag GPSDestDistanceRef { get; } = new ExifTag(ExifTagValue.GPSDestDistanceRef); + + /// + /// Gets the GPSDateStamp exif tag. + /// + public static ExifTag GPSDateStamp { get; } = new ExifTag(ExifTagValue.GPSDateStamp); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs new file mode 100644 index 000000000..5f4841226 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs @@ -0,0 +1,94 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + public abstract partial class ExifTag + { + /// + /// Gets the JPEGTables exif tag. + /// + public static ExifTag JPEGTables { get; } = new ExifTag(ExifTagValue.JPEGTables); + + /// + /// Gets the OECF exif tag. + /// + public static ExifTag OECF { get; } = new ExifTag(ExifTagValue.OECF); + + /// + /// Gets the ExifVersion exif tag. + /// + public static ExifTag ExifVersion { get; } = new ExifTag(ExifTagValue.ExifVersion); + + /// + /// Gets the ComponentsConfiguration exif tag. + /// + public static ExifTag ComponentsConfiguration { get; } = new ExifTag(ExifTagValue.ComponentsConfiguration); + + /// + /// Gets the MakerNote exif tag. + /// + public static ExifTag MakerNote { get; } = new ExifTag(ExifTagValue.MakerNote); + + /// + /// Gets the UserComment exif tag. + /// + public static ExifTag UserComment { get; } = new ExifTag(ExifTagValue.UserComment); + + /// + /// Gets the FlashpixVersion exif tag. + /// + public static ExifTag FlashpixVersion { get; } = new ExifTag(ExifTagValue.FlashpixVersion); + + /// + /// Gets the SpatialFrequencyResponse exif tag. + /// + public static ExifTag SpatialFrequencyResponse { get; } = new ExifTag(ExifTagValue.SpatialFrequencyResponse); + + /// + /// Gets the SpatialFrequencyResponse2 exif tag. + /// + public static ExifTag SpatialFrequencyResponse2 { get; } = new ExifTag(ExifTagValue.SpatialFrequencyResponse2); + + /// + /// Gets the Noise exif tag. + /// + public static ExifTag Noise { get; } = new ExifTag(ExifTagValue.Noise); + + /// + /// Gets the CFAPattern exif tag. + /// + public static ExifTag CFAPattern { get; } = new ExifTag(ExifTagValue.CFAPattern); + + /// + /// Gets the DeviceSettingDescription exif tag. + /// + public static ExifTag DeviceSettingDescription { get; } = new ExifTag(ExifTagValue.DeviceSettingDescription); + + /// + /// Gets the ImageSourceData exif tag. + /// + public static ExifTag ImageSourceData { get; } = new ExifTag(ExifTagValue.ImageSourceData); + + /// + /// Gets the GPSProcessingMethod exif tag. + /// + public static ExifTag GPSProcessingMethod { get; } = new ExifTag(ExifTagValue.GPSProcessingMethod); + + /// + /// Gets the GPSAreaInformation exif tag. + /// + public static ExifTag GPSAreaInformation { get; } = new ExifTag(ExifTagValue.GPSAreaInformation); + + /// + /// Gets the FileSource exif tag. + /// + public static ExifTag FileSource { get; } = new ExifTag(ExifTagValue.FileSource); + + /// + /// Gets the ImageDescription exif tag. + /// + public static ExifTag SceneType { get; } = new ExifTag(ExifTagValue.SceneType); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs new file mode 100644 index 000000000..65e031462 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs @@ -0,0 +1,70 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + /// Class that represents an exif tag from the Exif standard 2.31. + /// + public abstract partial class ExifTag : IEquatable + { + private readonly ushort value; + + internal ExifTag(ushort value) => this.value = value; + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator ushort(ExifTag tag) => tag?.value ?? (ushort)ExifTagValue.Unknown; + + /// + /// Determines whether the specified instances are considered equal. + /// + /// The first to compare. + /// The second to compare. + public static bool operator ==(ExifTag left, ExifTag right) => Equals(left, right); + + /// + /// Determines whether the specified instances are not considered equal. + /// + /// The first to compare. + /// The second to compare. + public static bool operator !=(ExifTag left, ExifTag right) => !Equals(left, right); + + /// + public override bool Equals(object obj) + { + if (obj is ExifTag value) + { + return this.Equals(value); + } + + return false; + } + + /// + public bool Equals(ExifTag other) + { + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + return this.value == other.value; + } + + /// + public override int GetHashCode() => this.value.GetHashCode(); + + /// + public override string ToString() => ((ExifTagValue)this.value).ToString(); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs similarity index 99% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs rename to src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs index ddd4591fa..7268762c6 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs @@ -1,13 +1,12 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { /// - /// All exif tags from the Exif standard 2.2 - /// Descriptions from: + /// All exif tags from the Exif standard 2.31. /// - public enum ExifTag + internal enum ExifTagValue { /// /// Unknown @@ -1539,6 +1538,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// /// GPSDifferential /// - GPSDifferential = 0x001E + GPSDifferential = 0x001E, } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs new file mode 100644 index 000000000..5a674277a --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs @@ -0,0 +1,17 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + /// Class that represents an exif tag from the Exif standard 2.31 with as the data type of the tag. + /// + /// The data type of the tag. + public sealed class ExifTag : ExifTag + { + internal ExifTag(ExifTagValue value) + : base((ushort)value) + { + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs b/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs new file mode 100644 index 000000000..8f0b36638 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs @@ -0,0 +1,13 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class UnkownExifTag : ExifTag + { + internal UnkownExifTag(ExifTagValue value) + : base((ushort)value) + { + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs new file mode 100644 index 000000000..263bf0934 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs @@ -0,0 +1,55 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal abstract class ExifArrayValue : ExifValue, IExifValue + { + protected ExifArrayValue(ExifTag tag) + : base(tag) + { + } + + protected ExifArrayValue(ExifTagValue tag) + : base(tag) + { + } + + internal ExifArrayValue(ExifArrayValue value) + : base(value) + { + } + + public override bool IsArray => true; + + public TValueType[] Value { get; set; } + + public override object GetValue() => this.Value; + + public override bool TrySetValue(object value) + { + if (value is null) + { + this.Value = null; + return true; + } + + Type type = value.GetType(); + if (value.GetType() == typeof(TValueType[])) + { + this.Value = (TValueType[])value; + return true; + } + + if (type == typeof(TValueType)) + { + this.Value = new TValueType[] { (TValueType)value }; + return true; + } + + return false; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs new file mode 100644 index 000000000..184f4a07c --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs @@ -0,0 +1,47 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifByte : ExifValue + { + public ExifByte(ExifTag tag, ExifDataType dataType) + : base(tag) => this.DataType = dataType; + + public ExifByte(ExifTagValue tag, ExifDataType dataType) + : base(tag) => this.DataType = dataType; + + private ExifByte(ExifByte value) + : base(value) => this.DataType = value.DataType; + + public override ExifDataType DataType { get; } + + protected override string StringValue => this.Value.ToString("X2", CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + if (intValue >= byte.MinValue && intValue <= byte.MaxValue) + { + this.Value = (byte)intValue; + return true; + } + + return false; + default: + return base.TrySetValue(value); + } + } + + public override IExifValue DeepClone() => new ExifByte(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs new file mode 100644 index 000000000..854eafc76 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs @@ -0,0 +1,66 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifByteArray : ExifArrayValue + { + public ExifByteArray(ExifTag tag, ExifDataType dataType) + : base(tag) => this.DataType = dataType; + + public ExifByteArray(ExifTagValue tag, ExifDataType dataType) + : base(tag) => this.DataType = dataType; + + private ExifByteArray(ExifByteArray value) + : base(value) => this.DataType = value.DataType; + + public override ExifDataType DataType { get; } + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + if (value is int[] intArrayValue) + { + return this.TrySetSignedIntArray(intArrayValue); + } + + if (value is int intValue) + { + if (intValue >= byte.MinValue && intValue <= byte.MaxValue) + { + this.Value = new byte[] { (byte)intValue }; + } + + return true; + } + + return false; + } + + public override IExifValue DeepClone() => new ExifByteArray(this); + + private bool TrySetSignedIntArray(int[] intArrayValue) + { + if (Array.FindIndex(intArrayValue, x => x < byte.MinValue || x > byte.MaxValue) > -1) + { + return false; + } + + var value = new byte[intArrayValue.Length]; + for (int i = 0; i < intArrayValue.Length; i++) + { + int s = intArrayValue[i]; + value[i] = (byte)s; + } + + this.Value = value; + return true; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs new file mode 100644 index 000000000..0af5f47ce --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifDouble : ExifValue + { + public ExifDouble(ExifTag tag) + : base(tag) + { + } + + public ExifDouble(ExifTagValue tag) + : base(tag) + { + } + + private ExifDouble(ExifDouble value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.DoubleFloat; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + this.Value = intValue; + return true; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifDouble(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs new file mode 100644 index 000000000..259d5c98a --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs @@ -0,0 +1,27 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifDoubleArray : ExifArrayValue + { + public ExifDoubleArray(ExifTag tag) + : base(tag) + { + } + + public ExifDoubleArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifDoubleArray(ExifDoubleArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.DoubleFloat; + + public override IExifValue DeepClone() => new ExifDoubleArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs new file mode 100644 index 000000000..8d6c41f58 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifFloat : ExifValue + { + public ExifFloat(ExifTagValue tag) + : base(tag) + { + } + + private ExifFloat(ExifFloat value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SingleFloat; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + this.Value = intValue; + return true; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifFloat(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs new file mode 100644 index 000000000..7789bc3b5 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifFloatArray : ExifArrayValue + { + public ExifFloatArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifFloatArray(ExifFloatArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SingleFloat; + + public override IExifValue DeepClone() => new ExifFloatArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs new file mode 100644 index 000000000..7f2f631a9 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs @@ -0,0 +1,53 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifLong : ExifValue + { + public ExifLong(ExifTag tag) + : base(tag) + { + } + + public ExifLong(ExifTagValue tag) + : base(tag) + { + } + + private ExifLong(ExifLong value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Long; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + if (intValue >= uint.MinValue) + { + this.Value = (uint)intValue; + return true; + } + + return false; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifLong(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs new file mode 100644 index 000000000..e05f50bee --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs @@ -0,0 +1,27 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifLongArray : ExifArrayValue + { + public ExifLongArray(ExifTag tag) + : base(tag) + { + } + + public ExifLongArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifLongArray(ExifLongArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Long; + + public override IExifValue DeepClone() => new ExifLongArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs new file mode 100644 index 000000000..8d886d21c --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs @@ -0,0 +1,74 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifNumber : ExifValue + { + public ExifNumber(ExifTag tag) + : base(tag) + { + } + + private ExifNumber(ExifNumber value) + : base(value) + { + } + + public override ExifDataType DataType + { + get + { + if (this.Value > ushort.MaxValue) + { + return ExifDataType.Long; + } + + return ExifDataType.Short; + } + } + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + if (intValue >= uint.MinValue) + { + this.Value = (uint)intValue; + return true; + } + + return false; + case uint uintValue: + this.Value = uintValue; + return true; + case short shortValue: + if (shortValue >= uint.MinValue) + { + this.Value = (uint)shortValue; + return true; + } + + return false; + case ushort ushortValue: + this.Value = ushortValue; + return true; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifNumber(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs new file mode 100644 index 000000000..a7ecf7bc8 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifNumberArray : ExifArrayValue + { + public ExifNumberArray(ExifTag tag) + : base(tag) + { + } + + private ExifNumberArray(ExifNumberArray value) + : base(value) + { + } + + public override ExifDataType DataType + { + get + { + if (this.Value is null) + { + return ExifDataType.Short; + } + + for (int i = 0; i < this.Value.Length; i++) + { + if (this.Value[i] > ushort.MaxValue) + { + return ExifDataType.Long; + } + } + + return ExifDataType.Short; + } + } + + public override IExifValue DeepClone() => new ExifNumberArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs new file mode 100644 index 000000000..2806386b5 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifRational : ExifValue + { + public ExifRational(ExifTag tag) + : base(tag) + { + } + + public ExifRational(ExifTagValue tag) + : base(tag) + { + } + + private ExifRational(ExifRational value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Rational; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case SignedRational signed: + + if (signed.Numerator >= uint.MinValue && signed.Denominator >= uint.MinValue) + { + this.Value = new Rational((uint)signed.Numerator, (uint)signed.Denominator); + } + + return true; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifRational(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs new file mode 100644 index 000000000..ae4fb0c57 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs @@ -0,0 +1,73 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifRationalArray : ExifArrayValue + { + public ExifRationalArray(ExifTag tag) + : base(tag) + { + } + + public ExifRationalArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifRationalArray(ExifRationalArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Rational; + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + if (value is SignedRational[] signedArray) + { + return this.TrySetSignedArray(signedArray); + } + + if (value is SignedRational signed) + { + if (signed.Numerator >= 0 && signed.Denominator >= 0) + { + this.Value = new[] { new Rational((uint)signed.Numerator, (uint)signed.Denominator) }; + } + + return true; + } + + return false; + } + + public override IExifValue DeepClone() => new ExifRationalArray(this); + + private bool TrySetSignedArray(SignedRational[] signed) + { + if (Array.FindIndex(signed, x => x.Numerator < 0 || x.Denominator < 0) > -1) + { + return false; + } + + var unsigned = new Rational[signed.Length]; + for (int i = 0; i < signed.Length; i++) + { + SignedRational s = signed[i]; + unsigned[i] = new Rational((uint)s.Numerator, (uint)s.Denominator); + } + + this.Value = unsigned; + return true; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs new file mode 100644 index 000000000..b11f3fc9f --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs @@ -0,0 +1,61 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifShort : ExifValue + { + public ExifShort(ExifTag tag) + : base(tag) + { + } + + public ExifShort(ExifTagValue tag) + : base(tag) + { + } + + private ExifShort(ExifShort value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Short; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + if (intValue >= ushort.MinValue && intValue <= ushort.MaxValue) + { + this.Value = (ushort)intValue; + return true; + } + + return false; + case short shortValue: + if (shortValue >= ushort.MinValue) + { + this.Value = (ushort)shortValue; + return true; + } + + return false; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifShort(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs new file mode 100644 index 000000000..379338c10 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs @@ -0,0 +1,105 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifShortArray : ExifArrayValue + { + public ExifShortArray(ExifTag tag) + : base(tag) + { + } + + public ExifShortArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifShortArray(ExifShortArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Short; + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + if (value is int[] signedIntArray) + { + return this.TrySetSignedIntArray(signedIntArray); + } + + if (value is short[] signedShortArray) + { + return this.TrySetSignedShortArray(signedShortArray); + } + + if (value is int signedInt) + { + if (signedInt >= ushort.MinValue && signedInt <= ushort.MaxValue) + { + this.Value = new ushort[] { (ushort)signedInt }; + } + + return true; + } + + if (value is short signedShort) + { + if (signedShort >= ushort.MinValue) + { + this.Value = new ushort[] { (ushort)signedShort }; + } + + return true; + } + + return false; + } + + public override IExifValue DeepClone() => new ExifShortArray(this); + + private bool TrySetSignedIntArray(int[] signed) + { + if (Array.FindIndex(signed, x => x < ushort.MinValue || x > ushort.MaxValue) > -1) + { + return false; + } + + var unsigned = new ushort[signed.Length]; + for (int i = 0; i < signed.Length; i++) + { + int s = signed[i]; + unsigned[i] = (ushort)s; + } + + this.Value = unsigned; + return true; + } + + private bool TrySetSignedShortArray(short[] signed) + { + if (Array.FindIndex(signed, x => x < ushort.MinValue) > -1) + { + return false; + } + + var unsigned = new ushort[signed.Length]; + for (int i = 0; i < signed.Length; i++) + { + short s = signed[i]; + unsigned[i] = (ushort)s; + } + + this.Value = unsigned; + return true; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs new file mode 100644 index 000000000..a9cb013ca --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedByte : ExifValue + { + public ExifSignedByte(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedByte(ExifSignedByte value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedByte; + + protected override string StringValue => this.Value.ToString("X2", CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + if (intValue >= sbyte.MinValue && intValue <= sbyte.MaxValue) + { + this.Value = (sbyte)intValue; + return true; + } + + return false; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifSignedByte(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs new file mode 100644 index 000000000..b0d35cc8a --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedByteArray : ExifArrayValue + { + public ExifSignedByteArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedByteArray(ExifSignedByteArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedByte; + + public override IExifValue DeepClone() => new ExifSignedByteArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs new file mode 100644 index 000000000..c1e6808bf --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs @@ -0,0 +1,26 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedLong : ExifValue + { + public ExifSignedLong(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedLong(ExifSignedLong value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedLong; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override IExifValue DeepClone() => new ExifSignedLong(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs new file mode 100644 index 000000000..36d4c0007 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedLongArray : ExifArrayValue + { + public ExifSignedLongArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedLongArray(ExifSignedLongArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedLong; + + public override IExifValue DeepClone() => new ExifSignedLongArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs new file mode 100644 index 000000000..2a4051601 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRational.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedRational : ExifValue + { + internal ExifSignedRational(ExifTag tag) + : base(tag) + { + } + + internal ExifSignedRational(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedRational(ExifSignedRational value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedRational; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override IExifValue DeepClone() => new ExifSignedRational(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs new file mode 100644 index 000000000..6c6bb0a4a --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedRationalArray.cs @@ -0,0 +1,29 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedRationalArray : ExifArrayValue + { + public ExifSignedRationalArray(ExifTag tag) + : base(tag) + { + } + + public ExifSignedRationalArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedRationalArray(ExifSignedRationalArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedRational; + + public override IExifValue DeepClone() => new ExifSignedRationalArray(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs new file mode 100644 index 000000000..e00f5c085 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShort.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedShort : ExifValue + { + public ExifSignedShort(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedShort(ExifSignedShort value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedShort; + + protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture); + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + if (intValue >= short.MinValue && intValue <= short.MaxValue) + { + this.Value = (short)intValue; + return true; + } + + return false; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifSignedShort(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs new file mode 100644 index 000000000..403a50186 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedShortArray.cs @@ -0,0 +1,67 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifSignedShortArray : ExifArrayValue + { + public ExifSignedShortArray(ExifTagValue tag) + : base(tag) + { + } + + private ExifSignedShortArray(ExifSignedShortArray value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.SignedShort; + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + if (value is int[] intArray) + { + return this.TrySetSignedArray(intArray); + } + + if (value is int intValue) + { + if (intValue >= short.MinValue && intValue <= short.MaxValue) + { + this.Value = new short[] { (short)intValue }; + } + + return true; + } + + return false; + } + + public override IExifValue DeepClone() => new ExifSignedShortArray(this); + + private bool TrySetSignedArray(int[] intArray) + { + if (Array.FindIndex(intArray, x => x < short.MinValue || x > short.MaxValue) > -1) + { + return false; + } + + var value = new short[intArray.Length]; + for (int i = 0; i < intArray.Length; i++) + { + int s = intArray[i]; + value[i] = (short)s; + } + + this.Value = value; + return true; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs new file mode 100644 index 000000000..0678bc3e4 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifString.cs @@ -0,0 +1,48 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Globalization; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal sealed class ExifString : ExifValue + { + public ExifString(ExifTag tag) + : base(tag) + { + } + + public ExifString(ExifTagValue tag) + : base(tag) + { + } + + private ExifString(ExifString value) + : base(value) + { + } + + public override ExifDataType DataType => ExifDataType.Ascii; + + protected override string StringValue => this.Value; + + public override bool TrySetValue(object value) + { + if (base.TrySetValue(value)) + { + return true; + } + + switch (value) + { + case int intValue: + this.Value = intValue.ToString(CultureInfo.InvariantCulture); + return true; + default: + return false; + } + } + + public override IExifValue DeepClone() => new ExifString(this); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs new file mode 100644 index 000000000..547e099c9 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal abstract class ExifValue : IExifValue, IEquatable + { + protected ExifValue(ExifTag tag) => this.Tag = tag; + + protected ExifValue(ExifTagValue tag) => this.Tag = new UnkownExifTag(tag); + + internal ExifValue(ExifValue other) + { + Guard.NotNull(other, nameof(other)); + + this.DataType = other.DataType; + this.IsArray = other.IsArray; + this.Tag = other.Tag; + + if (!other.IsArray) + { + // All types are value types except for string which is immutable so safe to simply assign. + this.TrySetValue(other.GetValue()); + } + else + { + // All array types are value types so Clone() is sufficient here. + var array = (Array)other.GetValue(); + this.TrySetValue(array.Clone()); + } + } + + public virtual ExifDataType DataType { get; } + + public virtual bool IsArray { get; } + + public ExifTag Tag { get; } + + public static bool operator ==(ExifValue left, ExifTag right) => Equals(left, right); + + public static bool operator !=(ExifValue left, ExifTag right) => !Equals(left, right); + + public override bool Equals(object obj) + { + if (obj is null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj is ExifTag tag) + { + return this.Equals(tag); + } + + if (obj is ExifValue value) + { + return this.Tag.Equals(value.Tag) && Equals(this.GetValue(), value.GetValue()); + } + + return false; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public bool Equals(ExifTag other) => this.Tag.Equals(other); + + [MethodImpl(InliningOptions.ShortMethod)] + public override int GetHashCode() => HashCode.Combine(this.Tag, this.GetValue()); + + public abstract object GetValue(); + + public abstract bool TrySetValue(object value); + + public abstract IExifValue DeepClone(); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs new file mode 100644 index 000000000..b183c4ec9 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs @@ -0,0 +1,307 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal static partial class ExifValues + { + public static ExifValue Create(ExifTagValue tag) => (ExifValue)CreateValue(tag); + + public static ExifValue Create(ExifTag tag) => (ExifValue)CreateValue((ExifTagValue)(ushort)tag); + + public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, uint numberOfComponents) + { + bool isArray = numberOfComponents != 1; + + switch (dataType) + { + case ExifDataType.Byte: return isArray ? (ExifValue)new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); + case ExifDataType.DoubleFloat: return isArray ? (ExifValue)new ExifDoubleArray(tag) : new ExifDouble(tag); + case ExifDataType.SingleFloat: return isArray ? (ExifValue)new ExifFloatArray(tag) : new ExifFloat(tag); + case ExifDataType.Long: return isArray ? (ExifValue)new ExifLongArray(tag) : new ExifLong(tag); + case ExifDataType.Rational: return isArray ? (ExifValue)new ExifRationalArray(tag) : new ExifRational(tag); + case ExifDataType.Short: return isArray ? (ExifValue)new ExifShortArray(tag) : new ExifShort(tag); + case ExifDataType.SignedByte: return isArray ? (ExifValue)new ExifSignedByteArray(tag) : new ExifSignedByte(tag); + case ExifDataType.SignedLong: return isArray ? (ExifValue)new ExifSignedLongArray(tag) : new ExifSignedLong(tag); + case ExifDataType.SignedRational: return isArray ? (ExifValue)new ExifSignedRationalArray(tag) : new ExifSignedRational(tag); + case ExifDataType.SignedShort: return isArray ? (ExifValue)new ExifSignedShortArray(tag) : new ExifSignedShort(tag); + case ExifDataType.Ascii: return new ExifString(tag); + case ExifDataType.Undefined: return isArray ? (ExifValue)new ExifByteArray(tag, dataType) : new ExifByte(tag, dataType); + default: return null; + } + } + + private static object CreateValue(ExifTagValue tag) + { + switch (tag) + { + case ExifTagValue.FaxProfile: return new ExifByte(ExifTag.FaxProfile, ExifDataType.Byte); + case ExifTagValue.ModeNumber: return new ExifByte(ExifTag.ModeNumber, ExifDataType.Byte); + case ExifTagValue.GPSAltitudeRef: return new ExifByte(ExifTag.GPSAltitudeRef, ExifDataType.Byte); + + case ExifTagValue.ClipPath: return new ExifByteArray(ExifTag.ClipPath, ExifDataType.Byte); + case ExifTagValue.VersionYear: return new ExifByteArray(ExifTag.VersionYear, ExifDataType.Byte); + case ExifTagValue.XMP: return new ExifByteArray(ExifTag.XMP, ExifDataType.Byte); + case ExifTagValue.CFAPattern2: return new ExifByteArray(ExifTag.CFAPattern2, ExifDataType.Byte); + case ExifTagValue.TIFFEPStandardID: return new ExifByteArray(ExifTag.TIFFEPStandardID, ExifDataType.Byte); + case ExifTagValue.XPTitle: return new ExifByteArray(ExifTag.XPTitle, ExifDataType.Byte); + case ExifTagValue.XPComment: return new ExifByteArray(ExifTag.XPComment, ExifDataType.Byte); + case ExifTagValue.XPAuthor: return new ExifByteArray(ExifTag.XPAuthor, ExifDataType.Byte); + case ExifTagValue.XPKeywords: return new ExifByteArray(ExifTag.XPKeywords, ExifDataType.Byte); + case ExifTagValue.XPSubject: return new ExifByteArray(ExifTag.XPSubject, ExifDataType.Byte); + case ExifTagValue.GPSVersionID: return new ExifByteArray(ExifTag.GPSVersionID, ExifDataType.Byte); + + case ExifTagValue.PixelScale: return new ExifDoubleArray(ExifTag.PixelScale); + case ExifTagValue.IntergraphMatrix: return new ExifDoubleArray(ExifTag.IntergraphMatrix); + case ExifTagValue.ModelTiePoint: return new ExifDoubleArray(ExifTag.ModelTiePoint); + case ExifTagValue.ModelTransform: return new ExifDoubleArray(ExifTag.ModelTransform); + + case ExifTagValue.SubfileType: return new ExifLong(ExifTag.SubfileType); + case ExifTagValue.SubIFDOffset: return new ExifLong(ExifTag.SubIFDOffset); + case ExifTagValue.GPSIFDOffset: return new ExifLong(ExifTag.GPSIFDOffset); + case ExifTagValue.T4Options: return new ExifLong(ExifTag.T4Options); + case ExifTagValue.T6Options: return new ExifLong(ExifTag.T6Options); + case ExifTagValue.XClipPathUnits: return new ExifLong(ExifTag.XClipPathUnits); + case ExifTagValue.YClipPathUnits: return new ExifLong(ExifTag.YClipPathUnits); + case ExifTagValue.ProfileType: return new ExifLong(ExifTag.ProfileType); + case ExifTagValue.CodingMethods: return new ExifLong(ExifTag.CodingMethods); + case ExifTagValue.T82ptions: return new ExifLong(ExifTag.T82ptions); + case ExifTagValue.JPEGInterchangeFormat: return new ExifLong(ExifTag.JPEGInterchangeFormat); + case ExifTagValue.JPEGInterchangeFormatLength: return new ExifLong(ExifTag.JPEGInterchangeFormatLength); + case ExifTagValue.MDFileTag: return new ExifLong(ExifTag.MDFileTag); + case ExifTagValue.StandardOutputSensitivity: return new ExifLong(ExifTag.StandardOutputSensitivity); + case ExifTagValue.RecommendedExposureIndex: return new ExifLong(ExifTag.RecommendedExposureIndex); + case ExifTagValue.ISOSpeed: return new ExifLong(ExifTag.ISOSpeed); + case ExifTagValue.ISOSpeedLatitudeyyy: return new ExifLong(ExifTag.ISOSpeedLatitudeyyy); + case ExifTagValue.ISOSpeedLatitudezzz: return new ExifLong(ExifTag.ISOSpeedLatitudezzz); + case ExifTagValue.FaxRecvParams: return new ExifLong(ExifTag.FaxRecvParams); + case ExifTagValue.FaxRecvTime: return new ExifLong(ExifTag.FaxRecvTime); + case ExifTagValue.ImageNumber: return new ExifLong(ExifTag.ImageNumber); + + case ExifTagValue.FreeOffsets: return new ExifLongArray(ExifTag.FreeOffsets); + case ExifTagValue.FreeByteCounts: return new ExifLongArray(ExifTag.FreeByteCounts); + case ExifTagValue.ColorResponseUnit: return new ExifLongArray(ExifTag.ColorResponseUnit); + case ExifTagValue.TileOffsets: return new ExifLongArray(ExifTag.TileOffsets); + case ExifTagValue.SMinSampleValue: return new ExifLongArray(ExifTag.SMinSampleValue); + case ExifTagValue.SMaxSampleValue: return new ExifLongArray(ExifTag.SMaxSampleValue); + case ExifTagValue.JPEGQTables: return new ExifLongArray(ExifTag.JPEGQTables); + case ExifTagValue.JPEGDCTables: return new ExifLongArray(ExifTag.JPEGDCTables); + case ExifTagValue.JPEGACTables: return new ExifLongArray(ExifTag.JPEGACTables); + case ExifTagValue.StripRowCounts: return new ExifLongArray(ExifTag.StripRowCounts); + case ExifTagValue.IntergraphRegisters: return new ExifLongArray(ExifTag.IntergraphRegisters); + case ExifTagValue.TimeZoneOffset: return new ExifLongArray(ExifTag.TimeZoneOffset); + + case ExifTagValue.ImageWidth: return new ExifNumber(ExifTag.ImageWidth); + case ExifTagValue.ImageLength: return new ExifNumber(ExifTag.ImageLength); + case ExifTagValue.TileWidth: return new ExifNumber(ExifTag.TileWidth); + case ExifTagValue.TileLength: return new ExifNumber(ExifTag.TileLength); + case ExifTagValue.BadFaxLines: return new ExifNumber(ExifTag.BadFaxLines); + case ExifTagValue.ConsecutiveBadFaxLines: return new ExifNumber(ExifTag.ConsecutiveBadFaxLines); + case ExifTagValue.PixelXDimension: return new ExifNumber(ExifTag.PixelXDimension); + case ExifTagValue.PixelYDimension: return new ExifNumber(ExifTag.PixelYDimension); + + case ExifTagValue.StripOffsets: return new ExifNumberArray(ExifTag.StripOffsets); + case ExifTagValue.TileByteCounts: return new ExifNumberArray(ExifTag.TileByteCounts); + case ExifTagValue.ImageLayer: return new ExifNumberArray(ExifTag.ImageLayer); + + case ExifTagValue.XPosition: return new ExifRational(ExifTag.XPosition); + case ExifTagValue.YPosition: return new ExifRational(ExifTag.YPosition); + case ExifTagValue.XResolution: return new ExifRational(ExifTag.XResolution); + case ExifTagValue.YResolution: return new ExifRational(ExifTag.YResolution); + case ExifTagValue.BatteryLevel: return new ExifRational(ExifTag.BatteryLevel); + case ExifTagValue.ExposureTime: return new ExifRational(ExifTag.ExposureTime); + case ExifTagValue.FNumber: return new ExifRational(ExifTag.FNumber); + case ExifTagValue.MDScalePixel: return new ExifRational(ExifTag.MDScalePixel); + case ExifTagValue.CompressedBitsPerPixel: return new ExifRational(ExifTag.CompressedBitsPerPixel); + case ExifTagValue.ApertureValue: return new ExifRational(ExifTag.ApertureValue); + case ExifTagValue.MaxApertureValue: return new ExifRational(ExifTag.MaxApertureValue); + case ExifTagValue.SubjectDistance: return new ExifRational(ExifTag.SubjectDistance); + case ExifTagValue.FocalLength: return new ExifRational(ExifTag.FocalLength); + case ExifTagValue.FlashEnergy2: return new ExifRational(ExifTag.FlashEnergy2); + case ExifTagValue.FocalPlaneXResolution2: return new ExifRational(ExifTag.FocalPlaneXResolution2); + case ExifTagValue.FocalPlaneYResolution2: return new ExifRational(ExifTag.FocalPlaneYResolution2); + case ExifTagValue.ExposureIndex2: return new ExifRational(ExifTag.ExposureIndex2); + case ExifTagValue.Humidity: return new ExifRational(ExifTag.Humidity); + case ExifTagValue.Pressure: return new ExifRational(ExifTag.Pressure); + case ExifTagValue.Acceleration: return new ExifRational(ExifTag.Acceleration); + case ExifTagValue.FlashEnergy: return new ExifRational(ExifTag.FlashEnergy); + case ExifTagValue.FocalPlaneXResolution: return new ExifRational(ExifTag.FocalPlaneXResolution); + case ExifTagValue.FocalPlaneYResolution: return new ExifRational(ExifTag.FocalPlaneYResolution); + case ExifTagValue.ExposureIndex: return new ExifRational(ExifTag.ExposureIndex); + case ExifTagValue.DigitalZoomRatio: return new ExifRational(ExifTag.DigitalZoomRatio); + case ExifTagValue.LensInfo: return new ExifRational(ExifTag.LensInfo); + case ExifTagValue.GPSAltitude: return new ExifRational(ExifTag.GPSAltitude); + case ExifTagValue.GPSDOP: return new ExifRational(ExifTag.GPSDOP); + case ExifTagValue.GPSSpeed: return new ExifRational(ExifTag.GPSSpeed); + case ExifTagValue.GPSTrack: return new ExifRational(ExifTag.GPSTrack); + case ExifTagValue.GPSImgDirection: return new ExifRational(ExifTag.GPSImgDirection); + case ExifTagValue.GPSDestBearing: return new ExifRational(ExifTag.GPSDestBearing); + case ExifTagValue.GPSDestDistance: return new ExifRational(ExifTag.GPSDestDistance); + + case ExifTagValue.WhitePoint: return new ExifRationalArray(ExifTag.WhitePoint); + case ExifTagValue.PrimaryChromaticities: return new ExifRationalArray(ExifTag.PrimaryChromaticities); + case ExifTagValue.YCbCrCoefficients: return new ExifRationalArray(ExifTag.YCbCrCoefficients); + case ExifTagValue.ReferenceBlackWhite: return new ExifRationalArray(ExifTag.ReferenceBlackWhite); + case ExifTagValue.GPSLatitude: return new ExifRationalArray(ExifTag.GPSLatitude); + case ExifTagValue.GPSLongitude: return new ExifRationalArray(ExifTag.GPSLongitude); + case ExifTagValue.GPSTimestamp: return new ExifRationalArray(ExifTag.GPSTimestamp); + case ExifTagValue.GPSDestLatitude: return new ExifRationalArray(ExifTag.GPSDestLatitude); + case ExifTagValue.GPSDestLongitude: return new ExifRationalArray(ExifTag.GPSDestLongitude); + + case ExifTagValue.OldSubfileType: return new ExifShort(ExifTag.OldSubfileType); + case ExifTagValue.Compression: return new ExifShort(ExifTag.Compression); + case ExifTagValue.PhotometricInterpretation: return new ExifShort(ExifTag.PhotometricInterpretation); + case ExifTagValue.Thresholding: return new ExifShort(ExifTag.Thresholding); + case ExifTagValue.CellWidth: return new ExifShort(ExifTag.CellWidth); + case ExifTagValue.CellLength: return new ExifShort(ExifTag.CellLength); + case ExifTagValue.FillOrder: return new ExifShort(ExifTag.FillOrder); + case ExifTagValue.Orientation: return new ExifShort(ExifTag.Orientation); + case ExifTagValue.SamplesPerPixel: return new ExifShort(ExifTag.SamplesPerPixel); + case ExifTagValue.PlanarConfiguration: return new ExifShort(ExifTag.PlanarConfiguration); + case ExifTagValue.GrayResponseUnit: return new ExifShort(ExifTag.GrayResponseUnit); + case ExifTagValue.ResolutionUnit: return new ExifShort(ExifTag.ResolutionUnit); + case ExifTagValue.CleanFaxData: return new ExifShort(ExifTag.CleanFaxData); + case ExifTagValue.InkSet: return new ExifShort(ExifTag.InkSet); + case ExifTagValue.NumberOfInks: return new ExifShort(ExifTag.NumberOfInks); + case ExifTagValue.DotRange: return new ExifShort(ExifTag.DotRange); + case ExifTagValue.Indexed: return new ExifShort(ExifTag.Indexed); + case ExifTagValue.OPIProxy: return new ExifShort(ExifTag.OPIProxy); + case ExifTagValue.JPEGProc: return new ExifShort(ExifTag.JPEGProc); + case ExifTagValue.JPEGRestartInterval: return new ExifShort(ExifTag.JPEGRestartInterval); + case ExifTagValue.YCbCrPositioning: return new ExifShort(ExifTag.YCbCrPositioning); + case ExifTagValue.Rating: return new ExifShort(ExifTag.Rating); + case ExifTagValue.RatingPercent: return new ExifShort(ExifTag.RatingPercent); + case ExifTagValue.ExposureProgram: return new ExifShort(ExifTag.ExposureProgram); + case ExifTagValue.Interlace: return new ExifShort(ExifTag.Interlace); + case ExifTagValue.SelfTimerMode: return new ExifShort(ExifTag.SelfTimerMode); + case ExifTagValue.SensitivityType: return new ExifShort(ExifTag.SensitivityType); + case ExifTagValue.MeteringMode: return new ExifShort(ExifTag.MeteringMode); + case ExifTagValue.LightSource: return new ExifShort(ExifTag.LightSource); + case ExifTagValue.FocalPlaneResolutionUnit2: return new ExifShort(ExifTag.FocalPlaneResolutionUnit2); + case ExifTagValue.SensingMethod2: return new ExifShort(ExifTag.SensingMethod2); + case ExifTagValue.Flash: return new ExifShort(ExifTag.Flash); + case ExifTagValue.ColorSpace: return new ExifShort(ExifTag.ColorSpace); + case ExifTagValue.FocalPlaneResolutionUnit: return new ExifShort(ExifTag.FocalPlaneResolutionUnit); + case ExifTagValue.SensingMethod: return new ExifShort(ExifTag.SensingMethod); + case ExifTagValue.CustomRendered: return new ExifShort(ExifTag.CustomRendered); + case ExifTagValue.ExposureMode: return new ExifShort(ExifTag.ExposureMode); + case ExifTagValue.WhiteBalance: return new ExifShort(ExifTag.WhiteBalance); + case ExifTagValue.FocalLengthIn35mmFilm: return new ExifShort(ExifTag.FocalLengthIn35mmFilm); + case ExifTagValue.SceneCaptureType: return new ExifShort(ExifTag.SceneCaptureType); + case ExifTagValue.GainControl: return new ExifShort(ExifTag.GainControl); + case ExifTagValue.Contrast: return new ExifShort(ExifTag.Contrast); + case ExifTagValue.Saturation: return new ExifShort(ExifTag.Saturation); + case ExifTagValue.Sharpness: return new ExifShort(ExifTag.Sharpness); + case ExifTagValue.SubjectDistanceRange: return new ExifShort(ExifTag.SubjectDistanceRange); + case ExifTagValue.GPSDifferential: return new ExifShort(ExifTag.GPSDifferential); + + case ExifTagValue.BitsPerSample: return new ExifShortArray(ExifTag.BitsPerSample); + case ExifTagValue.MinSampleValue: return new ExifShortArray(ExifTag.MinSampleValue); + case ExifTagValue.MaxSampleValue: return new ExifShortArray(ExifTag.MaxSampleValue); + case ExifTagValue.GrayResponseCurve: return new ExifShortArray(ExifTag.GrayResponseCurve); + case ExifTagValue.ColorMap: return new ExifShortArray(ExifTag.ColorMap); + case ExifTagValue.ExtraSamples: return new ExifShortArray(ExifTag.ExtraSamples); + case ExifTagValue.PageNumber: return new ExifShortArray(ExifTag.PageNumber); + case ExifTagValue.TransferFunction: return new ExifShortArray(ExifTag.TransferFunction); + case ExifTagValue.Predictor: return new ExifShortArray(ExifTag.Predictor); + case ExifTagValue.HalftoneHints: return new ExifShortArray(ExifTag.HalftoneHints); + case ExifTagValue.SampleFormat: return new ExifShortArray(ExifTag.SampleFormat); + case ExifTagValue.TransferRange: return new ExifShortArray(ExifTag.TransferRange); + case ExifTagValue.DefaultImageColor: return new ExifShortArray(ExifTag.DefaultImageColor); + case ExifTagValue.JPEGLosslessPredictors: return new ExifShortArray(ExifTag.JPEGLosslessPredictors); + case ExifTagValue.JPEGPointTransforms: return new ExifShortArray(ExifTag.JPEGPointTransforms); + case ExifTagValue.YCbCrSubsampling: return new ExifShortArray(ExifTag.YCbCrSubsampling); + case ExifTagValue.CFARepeatPatternDim: return new ExifShortArray(ExifTag.CFARepeatPatternDim); + case ExifTagValue.IntergraphPacketData: return new ExifShortArray(ExifTag.IntergraphPacketData); + case ExifTagValue.ISOSpeedRatings: return new ExifShortArray(ExifTag.ISOSpeedRatings); + case ExifTagValue.SubjectArea: return new ExifShortArray(ExifTag.SubjectArea); + case ExifTagValue.SubjectLocation: return new ExifShortArray(ExifTag.SubjectLocation); + + case ExifTagValue.ShutterSpeedValue: return new ExifSignedRational(ExifTag.ShutterSpeedValue); + case ExifTagValue.BrightnessValue: return new ExifSignedRational(ExifTag.BrightnessValue); + case ExifTagValue.ExposureBiasValue: return new ExifSignedRational(ExifTag.ExposureBiasValue); + case ExifTagValue.AmbientTemperature: return new ExifSignedRational(ExifTag.AmbientTemperature); + case ExifTagValue.WaterDepth: return new ExifSignedRational(ExifTag.WaterDepth); + case ExifTagValue.CameraElevationAngle: return new ExifSignedRational(ExifTag.CameraElevationAngle); + + case ExifTagValue.Decode: return new ExifSignedRationalArray(ExifTag.Decode); + + case ExifTagValue.ImageDescription: return new ExifString(ExifTag.ImageDescription); + case ExifTagValue.Make: return new ExifString(ExifTag.Make); + case ExifTagValue.Model: return new ExifString(ExifTag.Model); + case ExifTagValue.Software: return new ExifString(ExifTag.Software); + case ExifTagValue.DateTime: return new ExifString(ExifTag.DateTime); + case ExifTagValue.Artist: return new ExifString(ExifTag.Artist); + case ExifTagValue.HostComputer: return new ExifString(ExifTag.HostComputer); + case ExifTagValue.Copyright: return new ExifString(ExifTag.Copyright); + case ExifTagValue.DocumentName: return new ExifString(ExifTag.DocumentName); + case ExifTagValue.PageName: return new ExifString(ExifTag.PageName); + case ExifTagValue.InkNames: return new ExifString(ExifTag.InkNames); + case ExifTagValue.TargetPrinter: return new ExifString(ExifTag.TargetPrinter); + case ExifTagValue.ImageID: return new ExifString(ExifTag.ImageID); + case ExifTagValue.MDLabName: return new ExifString(ExifTag.MDLabName); + case ExifTagValue.MDSampleInfo: return new ExifString(ExifTag.MDSampleInfo); + case ExifTagValue.MDPrepDate: return new ExifString(ExifTag.MDPrepDate); + case ExifTagValue.MDPrepTime: return new ExifString(ExifTag.MDPrepTime); + case ExifTagValue.MDFileUnits: return new ExifString(ExifTag.MDFileUnits); + case ExifTagValue.SEMInfo: return new ExifString(ExifTag.SEMInfo); + case ExifTagValue.SpectralSensitivity: return new ExifString(ExifTag.SpectralSensitivity); + case ExifTagValue.DateTimeOriginal: return new ExifString(ExifTag.DateTimeOriginal); + case ExifTagValue.DateTimeDigitized: return new ExifString(ExifTag.DateTimeDigitized); + case ExifTagValue.SubsecTime: return new ExifString(ExifTag.SubsecTime); + case ExifTagValue.SubsecTimeOriginal: return new ExifString(ExifTag.SubsecTimeOriginal); + case ExifTagValue.SubsecTimeDigitized: return new ExifString(ExifTag.SubsecTimeDigitized); + case ExifTagValue.RelatedSoundFile: return new ExifString(ExifTag.RelatedSoundFile); + case ExifTagValue.FaxSubaddress: return new ExifString(ExifTag.FaxSubaddress); + case ExifTagValue.OffsetTime: return new ExifString(ExifTag.OffsetTime); + case ExifTagValue.OffsetTimeOriginal: return new ExifString(ExifTag.OffsetTimeOriginal); + case ExifTagValue.OffsetTimeDigitized: return new ExifString(ExifTag.OffsetTimeDigitized); + case ExifTagValue.SecurityClassification: return new ExifString(ExifTag.SecurityClassification); + case ExifTagValue.ImageHistory: return new ExifString(ExifTag.ImageHistory); + case ExifTagValue.ImageUniqueID: return new ExifString(ExifTag.ImageUniqueID); + case ExifTagValue.OwnerName: return new ExifString(ExifTag.OwnerName); + case ExifTagValue.SerialNumber: return new ExifString(ExifTag.SerialNumber); + case ExifTagValue.LensMake: return new ExifString(ExifTag.LensMake); + case ExifTagValue.LensModel: return new ExifString(ExifTag.LensModel); + case ExifTagValue.LensSerialNumber: return new ExifString(ExifTag.LensSerialNumber); + case ExifTagValue.GDALMetadata: return new ExifString(ExifTag.GDALMetadata); + case ExifTagValue.GDALNoData: return new ExifString(ExifTag.GDALNoData); + case ExifTagValue.GPSLatitudeRef: return new ExifString(ExifTag.GPSLatitudeRef); + case ExifTagValue.GPSLongitudeRef: return new ExifString(ExifTag.GPSLongitudeRef); + case ExifTagValue.GPSSatellites: return new ExifString(ExifTag.GPSSatellites); + case ExifTagValue.GPSStatus: return new ExifString(ExifTag.GPSStatus); + case ExifTagValue.GPSMeasureMode: return new ExifString(ExifTag.GPSMeasureMode); + case ExifTagValue.GPSSpeedRef: return new ExifString(ExifTag.GPSSpeedRef); + case ExifTagValue.GPSTrackRef: return new ExifString(ExifTag.GPSTrackRef); + case ExifTagValue.GPSImgDirectionRef: return new ExifString(ExifTag.GPSImgDirectionRef); + case ExifTagValue.GPSMapDatum: return new ExifString(ExifTag.GPSMapDatum); + case ExifTagValue.GPSDestLatitudeRef: return new ExifString(ExifTag.GPSDestLatitudeRef); + case ExifTagValue.GPSDestLongitudeRef: return new ExifString(ExifTag.GPSDestLongitudeRef); + case ExifTagValue.GPSDestBearingRef: return new ExifString(ExifTag.GPSDestBearingRef); + case ExifTagValue.GPSDestDistanceRef: return new ExifString(ExifTag.GPSDestDistanceRef); + case ExifTagValue.GPSDateStamp: return new ExifString(ExifTag.GPSDateStamp); + + case ExifTagValue.FileSource: return new ExifByte(ExifTag.FileSource, ExifDataType.Undefined); + case ExifTagValue.SceneType: return new ExifByte(ExifTag.SceneType, ExifDataType.Undefined); + + case ExifTagValue.JPEGTables: return new ExifByteArray(ExifTag.JPEGTables, ExifDataType.Undefined); + case ExifTagValue.OECF: return new ExifByteArray(ExifTag.OECF, ExifDataType.Undefined); + case ExifTagValue.ExifVersion: return new ExifByteArray(ExifTag.ExifVersion, ExifDataType.Undefined); + case ExifTagValue.ComponentsConfiguration: return new ExifByteArray(ExifTag.ComponentsConfiguration, ExifDataType.Undefined); + case ExifTagValue.MakerNote: return new ExifByteArray(ExifTag.MakerNote, ExifDataType.Undefined); + case ExifTagValue.UserComment: return new ExifByteArray(ExifTag.UserComment, ExifDataType.Undefined); + case ExifTagValue.FlashpixVersion: return new ExifByteArray(ExifTag.FlashpixVersion, ExifDataType.Undefined); + case ExifTagValue.SpatialFrequencyResponse: return new ExifByteArray(ExifTag.SpatialFrequencyResponse, ExifDataType.Undefined); + case ExifTagValue.SpatialFrequencyResponse2: return new ExifByteArray(ExifTag.SpatialFrequencyResponse2, ExifDataType.Undefined); + case ExifTagValue.Noise: return new ExifByteArray(ExifTag.Noise, ExifDataType.Undefined); + case ExifTagValue.CFAPattern: return new ExifByteArray(ExifTag.CFAPattern, ExifDataType.Undefined); + case ExifTagValue.DeviceSettingDescription: return new ExifByteArray(ExifTag.DeviceSettingDescription, ExifDataType.Undefined); + case ExifTagValue.ImageSourceData: return new ExifByteArray(ExifTag.ImageSourceData, ExifDataType.Undefined); + case ExifTagValue.GPSProcessingMethod: return new ExifByteArray(ExifTag.GPSProcessingMethod, ExifDataType.Undefined); + case ExifTagValue.GPSAreaInformation: return new ExifByteArray(ExifTag.GPSAreaInformation, ExifDataType.Undefined); + + default: return null; + } + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs new file mode 100644 index 000000000..601630af6 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValue{TValueType}.cs @@ -0,0 +1,62 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + internal abstract class ExifValue : ExifValue, IExifValue + { + protected ExifValue(ExifTag tag) + : base(tag) + { + } + + protected ExifValue(ExifTagValue tag) + : base(tag) + { + } + + internal ExifValue(ExifValue value) + : base(value) + { + } + + public TValueType Value { get; set; } + + /// + /// Gets the value of the current instance as a string. + /// + protected abstract string StringValue { get; } + + public override object GetValue() => this.Value; + + public override bool TrySetValue(object value) + { + if (value is null) + { + this.Value = default; + return true; + } + + // We use type comparison here over "is" to avoid compiler optimizations + // that equate short with ushort, and sbyte with byte. + if (value.GetType() == typeof(TValueType)) + { + this.Value = (TValueType)value; + return true; + } + + return false; + } + + public override string ToString() + { + if (this.Value == null) + { + return null; + } + + string description = ExifTagDescriptionAttribute.GetDescription(this.Tag, this.Value); + return description ?? this.StringValue; + } + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs new file mode 100644 index 000000000..50c421832 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + /// A value of the exif profile. + /// + public interface IExifValue : IDeepCloneable + { + /// + /// Gets the data type of the exif value. + /// + ExifDataType DataType { get; } + + /// + /// Gets a value indicating whether the value is an array. + /// + bool IsArray { get; } + + /// + /// Gets the tag of the exif value. + /// + ExifTag Tag { get; } + + /// + /// Gets the value of this exif value. + /// + /// The value of this exif value. + object GetValue(); + + /// + /// Sets the value of this exif value. + /// + /// The value of this exif value. + /// A value indicating whether the value could be set. + bool TrySetValue(object value); + } +} diff --git a/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs new file mode 100644 index 000000000..72b93ddf9 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/Exif/Values/IExifValue{TValueType}.cs @@ -0,0 +1,17 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Metadata.Profiles.Exif +{ + /// + /// A value of the exif profile. + /// + /// The type of the value. + public interface IExifValue : IExifValue + { + /// + /// Gets or sets the value. + /// + TValueType Value { get; set; } + } +} diff --git a/src/ImageSharp/Primitives/Number.cs b/src/ImageSharp/Primitives/Number.cs new file mode 100644 index 000000000..88974e72b --- /dev/null +++ b/src/ImageSharp/Primitives/Number.cs @@ -0,0 +1,187 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.Primitives +{ + /// + /// Represents an integral number. + /// + [StructLayout(LayoutKind.Explicit)] + public struct Number : IEquatable, IComparable + { + [FieldOffset(0)] + private readonly int signedValue; + + [FieldOffset(0)] + private readonly uint unsignedValue; + + [FieldOffset(4)] + private readonly bool isSigned; + + /// + /// Initializes a new instance of the struct. + /// + /// The value of the number. + public Number(int value) + : this() + { + this.signedValue = value; + this.isSigned = true; + } + + /// + /// Initializes a new instance of the struct. + /// + /// The value of the number. + public Number(uint value) + : this() + { + this.unsignedValue = value; + this.isSigned = false; + } + + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(int value) => new Number(value); + + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(uint value) => new Number(value); + + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(ushort value) => new Number((uint)value); + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator int(Number number) + { + return number.isSigned + ? number.signedValue + : (int)number.unsignedValue.Clamp(0, int.MaxValue); + } + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator uint(Number number) + { + return number.isSigned + ? (uint)number.signedValue.Clamp(0, int.MaxValue) + : number.unsignedValue; + } + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator ushort(Number number) + { + return number.isSigned + ? (ushort)number.signedValue.Clamp(ushort.MinValue, ushort.MaxValue) + : (ushort)number.unsignedValue.Clamp(ushort.MinValue, ushort.MaxValue); + } + + /// + /// Determines whether the specified instances are considered equal. + /// + /// The first to compare. + /// The second to compare. + public static bool operator ==(Number left, Number right) => Equals(left, right); + + /// + /// Determines whether the specified instances are not considered equal. + /// + /// The first to compare. + /// The second to compare. + public static bool operator !=(Number left, Number right) => !Equals(left, right); + + /// + /// Determines whether the first is more than the second . + /// + /// The first to compare. + /// The second to compare. + public static bool operator >(Number left, Number right) => left.CompareTo(right) == 1; + + /// + /// Determines whether the first is less than the second . + /// + /// The first to compare. + /// The second to compare. + public static bool operator <(Number left, Number right) => left.CompareTo(right) == -1; + + /// + /// Determines whether the first is more than or equal to the second . + /// + /// The first to compare. + /// The second to compare. + public static bool operator >=(Number left, Number right) => left.CompareTo(right) >= 0; + + /// + /// Determines whether the first is less than or equal to the second . + /// + /// The first to compare. + /// The second to compare. + public static bool operator <=(Number left, Number right) => left.CompareTo(right) <= 0; + + /// + public int CompareTo(Number other) + { + return this.isSigned + ? this.signedValue.CompareTo(other.signedValue) + : this.unsignedValue.CompareTo(other.unsignedValue); + } + + /// + public override bool Equals(object obj) => obj is Number other && this.Equals(other); + + /// + public bool Equals(Number other) + { + if (this.isSigned != other.isSigned) + { + return false; + } + + return this.isSigned + ? this.signedValue.Equals(other.signedValue) + : this.unsignedValue.Equals(other.unsignedValue); + } + + /// + public override int GetHashCode() + { + return this.isSigned + ? this.signedValue.GetHashCode() + : this.unsignedValue.GetHashCode(); + } + + /// + public override string ToString() => this.ToString(CultureInfo.InvariantCulture); + + /// + /// Converts the numeric value of this instance to its equivalent string representation using the specified culture-specific format information. + /// + /// An object that supplies culture-specific formatting information. + /// The string representation of the value of this instance, which consists of a sequence of digits ranging from 0 to 9, without a sign or leading zeros. + public string ToString(IFormatProvider provider) + { + return this.isSigned + ? this.signedValue.ToString(provider) + : this.unsignedValue.ToString(provider); + } + } +} diff --git a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs index 328ccdf94..5d986b6cc 100644 --- a/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs +++ b/src/ImageSharp/Processing/DefaultImageProcessorContext{TPixel}.cs @@ -1,10 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing @@ -23,10 +21,12 @@ namespace SixLabors.ImageSharp.Processing /// /// Initializes a new instance of the class. /// - /// The image. - /// The mutate. - public DefaultImageProcessorContext(Image source, bool mutate) + /// The configuration which allows altering default behaviour or extending the library. + /// The source image. + /// Whether to mutate the image. + public DefaultImageProcessorContext(Configuration configuration, Image source, bool mutate) { + this.Configuration = configuration; this.mutate = mutate; this.source = source; @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing } /// - public MemoryAllocator MemoryAllocator => this.source.GetConfiguration().MemoryAllocator; + public Configuration Configuration { get; } /// public Image GetResultImage() @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing // interim clone if the first processor in the pipeline is a cloning processor. if (processor is ICloningImageProcessor cloningImageProcessor) { - using (ICloningImageProcessor pixelProcessor = cloningImageProcessor.CreatePixelSpecificCloningProcessor(this.source, rectangle)) + using (ICloningImageProcessor pixelProcessor = cloningImageProcessor.CreatePixelSpecificCloningProcessor(this.Configuration, this.source, rectangle)) { this.destination = pixelProcessor.CloneAndExecute(); return this; @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.Processing } // Standard processing pipeline. - using (IImageProcessor specificProcessor = processor.CreatePixelSpecificProcessor(this.destination, rectangle)) + using (IImageProcessor specificProcessor = processor.CreatePixelSpecificProcessor(this.Configuration, this.destination, rectangle)) { specificProcessor.Execute(); } diff --git a/src/ImageSharp/Processing/Extensions/BinaryDiffuseExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryDiffuseExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BinaryDiffuseExtensions.cs rename to src/ImageSharp/Processing/Extensions/Binarization/BinaryDiffuseExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BinaryDitherExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryDitherExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BinaryDitherExtensions.cs rename to src/ImageSharp/Processing/Extensions/Binarization/BinaryDitherExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BinaryThresholdExtensions.cs b/src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BinaryThresholdExtensions.cs rename to src/ImageSharp/Processing/Extensions/Binarization/BinaryThresholdExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BokehBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/BokehBlurExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BokehBlurExtensions.cs rename to src/ImageSharp/Processing/Extensions/Convolution/BokehBlurExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BoxBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BoxBlurExtensions.cs rename to src/ImageSharp/Processing/Extensions/Convolution/BoxBlurExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/DetectEdgesExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/DetectEdgesExtensions.cs rename to src/ImageSharp/Processing/Extensions/Convolution/DetectEdgesExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/GaussianBlurExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/GaussianBlurExtensions.cs rename to src/ImageSharp/Processing/Extensions/Convolution/GaussianBlurExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/GaussianSharpenExtensions.cs b/src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/GaussianSharpenExtensions.cs rename to src/ImageSharp/Processing/Extensions/Convolution/GaussianSharpenExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs b/src/ImageSharp/Processing/Extensions/Dithering/DiffuseExtensions.cs similarity index 99% rename from src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs rename to src/ImageSharp/Processing/Extensions/Dithering/DiffuseExtensions.cs index b72111099..45eb932fe 100644 --- a/src/ImageSharp/Processing/Extensions/DiffuseExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Dithering/DiffuseExtensions.cs @@ -6,7 +6,7 @@ using System; using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.Primitives; -namespace SixLabors.ImageSharp.Processing.Dithering +namespace SixLabors.ImageSharp.Processing { /// /// Defines extension methods to apply diffusion to an diff --git a/src/ImageSharp/Processing/Extensions/DitherExtensions.cs b/src/ImageSharp/Processing/Extensions/Dithering/DitherExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/DitherExtensions.cs rename to src/ImageSharp/Processing/Extensions/Dithering/DitherExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/OilPaintExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/OilPaintExtensions.cs rename to src/ImageSharp/Processing/Extensions/Effects/OilPaintExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/Effects/PixelShaderExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/PixelShaderExtensions.cs new file mode 100644 index 000000000..b866e7fb1 --- /dev/null +++ b/src/ImageSharp/Processing/Extensions/Effects/PixelShaderExtensions.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Effects; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Defines extension methods that allow the application of user defined pixel shaders to an . + /// + public static class PixelShaderExtensions + { + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PixelShader pixelShader) + => source.ApplyProcessor(new PixelShaderProcessor(pixelShader)); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// The to apply during the pixel conversions. + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PixelShader pixelShader, PixelConversionModifiers modifiers) + => source.ApplyProcessor(new PixelShaderProcessor(pixelShader, modifiers)); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PixelShader pixelShader, Rectangle rectangle) + => source.ApplyProcessor(new PixelShaderProcessor(pixelShader), rectangle); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to apply during the pixel conversions. + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PixelShader pixelShader, Rectangle rectangle, PixelConversionModifiers modifiers) + => source.ApplyProcessor(new PixelShaderProcessor(pixelShader, modifiers), rectangle); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PositionAwarePixelShader pixelShader) + => source.ApplyProcessor(new PositionAwarePixelShaderProcessor(pixelShader)); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// The to apply during the pixel conversions. + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PositionAwarePixelShader pixelShader, PixelConversionModifiers modifiers) + => source.ApplyProcessor(new PositionAwarePixelShaderProcessor(pixelShader, modifiers)); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PositionAwarePixelShader pixelShader, Rectangle rectangle) + => source.ApplyProcessor(new PositionAwarePixelShaderProcessor(pixelShader), rectangle); + + /// + /// Applies a user defined pixel shader to the image. + /// + /// The image this method extends. + /// The user defined pixel shader to use to modify images. + /// + /// The structure that specifies the portion of the image object to alter. + /// + /// The to apply during the pixel conversions. + /// The to allow chaining of operations. + public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PositionAwarePixelShader pixelShader, Rectangle rectangle, PixelConversionModifiers modifiers) + => source.ApplyProcessor(new PositionAwarePixelShaderProcessor(pixelShader, modifiers), rectangle); + } +} diff --git a/src/ImageSharp/Processing/Extensions/PixelateExtensions.cs b/src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/PixelateExtensions.cs rename to src/ImageSharp/Processing/Extensions/Effects/PixelateExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BlackWhiteExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BlackWhiteExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/BlackWhiteExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BrightnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/BrightnessExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BrightnessExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/BrightnessExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/ColorBlindnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/ColorBlindnessExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/ColorBlindnessExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/ContrastExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/ContrastExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/ContrastExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/FilterExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/FilterExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/FilterExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/GrayscaleExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/GrayscaleExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/HueExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/HueExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/HueExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/InvertExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/InvertExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/InvertExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/KodachromeExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/KodachromeExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/KodachromeExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/KodachromeExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/LightnessExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/LightnessExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/LightnessExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/LightnessExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/LomographExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/LomographExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/LomographExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/OpacityExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/OpacityExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/OpacityExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/PolaroidExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/PolaroidExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/PolaroidExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/SaturateExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/SaturateExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/SaturateExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/SepiaExtensions.cs b/src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/SepiaExtensions.cs rename to src/ImageSharp/Processing/Extensions/Filters/SepiaExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs b/src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/HistogramEqualizationExtensions.cs rename to src/ImageSharp/Processing/Extensions/Normalization/HistogramEqualizationExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/BackgroundColorExtensions.cs rename to src/ImageSharp/Processing/Extensions/Overlays/BackgroundColorExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/GlowExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/GlowExtensions.cs rename to src/ImageSharp/Processing/Extensions/Overlays/GlowExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/VignetteExtensions.cs b/src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/VignetteExtensions.cs rename to src/ImageSharp/Processing/Extensions/Overlays/VignetteExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs index 40b1c439e..36966c296 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs @@ -20,12 +20,22 @@ namespace SixLabors.ImageSharp.Processing /// The image to mutate. /// The operation to perform on the source. public static void Mutate(this Image source, Action operation) + => Mutate(source, source.GetConfiguration(), operation); + + /// + /// Mutates the source image by applying the image operation to it. + /// + /// The image to mutate. + /// The configuration which allows altering default behaviour or extending the library. + /// The operation to perform on the source. + public static void Mutate(this Image source, Configuration configuration, Action operation) { + Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); - source.AcceptVisitor(new ProcessingVisitor(operation, true)); + source.AcceptVisitor(new ProcessingVisitor(configuration, operation, true)); } /// @@ -36,14 +46,25 @@ namespace SixLabors.ImageSharp.Processing /// The operation to perform on the source. public static void Mutate(this Image source, Action operation) where TPixel : struct, IPixel + => Mutate(source, source.GetConfiguration(), operation); + + /// + /// Mutates the source image by applying the image operation to it. + /// + /// The pixel format. + /// The image to mutate. + /// The configuration which allows altering default behaviour or extending the library. + /// The operation to perform on the source. + public static void Mutate(this Image source, Configuration configuration, Action operation) + where TPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); IInternalImageProcessingContext operationsRunner - = source.GetConfiguration() - .ImageOperationsProvider.CreateImageProcessingContext(source, true); + = configuration.ImageOperationsProvider.CreateImageProcessingContext(configuration, source, true); operation(operationsRunner); } @@ -56,14 +77,24 @@ namespace SixLabors.ImageSharp.Processing /// The operations to perform on the source. public static void Mutate(this Image source, params IImageProcessor[] operations) where TPixel : struct, IPixel + => Mutate(source, source.GetConfiguration(), operations); + + /// + /// Mutates the source image by applying the operations to it. + /// + /// The pixel format. + /// The image to mutate. + /// The configuration which allows altering default behaviour or extending the library. + /// The operations to perform on the source. + public static void Mutate(this Image source, Configuration configuration, params IImageProcessor[] operations) + where TPixel : struct, IPixel { Guard.NotNull(source, nameof(source)); Guard.NotNull(operations, nameof(operations)); source.EnsureNotDisposed(); IInternalImageProcessingContext operationsRunner - = source.GetConfiguration() - .ImageOperationsProvider.CreateImageProcessingContext(source, true); + = configuration.ImageOperationsProvider.CreateImageProcessingContext(configuration, source, true); operationsRunner.ApplyProcessors(operations); } @@ -75,12 +106,23 @@ namespace SixLabors.ImageSharp.Processing /// The operation to perform on the clone. /// The new . public static Image Clone(this Image source, Action operation) + => Clone(source, source.GetConfiguration(), operation); + + /// + /// Creates a deep clone of the current image. The clone is then mutated by the given operation. + /// + /// The image to clone. + /// The configuration which allows altering default behaviour or extending the library. + /// The operation to perform on the clone. + /// The new . + public static Image Clone(this Image source, Configuration configuration, Action operation) { + Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); - var visitor = new ProcessingVisitor(operation, false); + var visitor = new ProcessingVisitor(configuration, operation, false); source.AcceptVisitor(visitor); return visitor.ResultImage; } @@ -94,14 +136,26 @@ namespace SixLabors.ImageSharp.Processing /// The new public static Image Clone(this Image source, Action operation) where TPixel : struct, IPixel + => Clone(source, source.GetConfiguration(), operation); + + /// + /// Creates a deep clone of the current image. The clone is then mutated by the given operation. + /// + /// The pixel format. + /// The image to clone. + /// The configuration which allows altering default behaviour or extending the library. + /// The operation to perform on the clone. + /// The new + public static Image Clone(this Image source, Configuration configuration, Action operation) + where TPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); Guard.NotNull(operation, nameof(operation)); source.EnsureNotDisposed(); IInternalImageProcessingContext operationsRunner - = source.GetConfiguration() - .ImageOperationsProvider.CreateImageProcessingContext(source, false); + = configuration.ImageOperationsProvider.CreateImageProcessingContext(configuration, source, false); operation(operationsRunner); return operationsRunner.GetResultImage(); @@ -116,14 +170,26 @@ namespace SixLabors.ImageSharp.Processing /// The new public static Image Clone(this Image source, params IImageProcessor[] operations) where TPixel : struct, IPixel + => Clone(source, source.GetConfiguration(), operations); + + /// + /// Creates a deep clone of the current image. The clone is then mutated by the given operations. + /// + /// The pixel format. + /// The image to clone. + /// The configuration which allows altering default behaviour or extending the library. + /// The operations to perform on the clone. + /// The new + public static Image Clone(this Image source, Configuration configuration, params IImageProcessor[] operations) + where TPixel : struct, IPixel { + Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(source, nameof(source)); Guard.NotNull(operations, nameof(operations)); source.EnsureNotDisposed(); IInternalImageProcessingContext operationsRunner - = source.GetConfiguration() - .ImageOperationsProvider.CreateImageProcessingContext(source, false); + = configuration.ImageOperationsProvider.CreateImageProcessingContext(configuration, source, false); operationsRunner.ApplyProcessors(operations); return operationsRunner.GetResultImage(); @@ -149,12 +215,15 @@ namespace SixLabors.ImageSharp.Processing private class ProcessingVisitor : IImageVisitor { + private readonly Configuration configuration; + private readonly Action operation; private readonly bool mutate; - public ProcessingVisitor(Action operation, bool mutate) + public ProcessingVisitor(Configuration configuration, Action operation, bool mutate) { + this.configuration = configuration; this.operation = operation; this.mutate = mutate; } @@ -165,8 +234,7 @@ namespace SixLabors.ImageSharp.Processing where TPixel : struct, IPixel { IInternalImageProcessingContext operationsRunner = - image.GetConfiguration() - .ImageOperationsProvider.CreateImageProcessingContext(image, this.mutate); + this.configuration.ImageOperationsProvider.CreateImageProcessingContext(this.configuration, image, this.mutate); this.operation(operationsRunner); this.ResultImage = operationsRunner.GetResultImage(); diff --git a/src/ImageSharp/Processing/Extensions/QuantizeExtensions.cs b/src/ImageSharp/Processing/Extensions/Quantization/QuantizeExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/QuantizeExtensions.cs rename to src/ImageSharp/Processing/Extensions/Quantization/QuantizeExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/AutoOrientExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/AutoOrientExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/AutoOrientExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/CropExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/CropExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/CropExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/EntropyCropExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/EntropyCropExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/EntropyCropExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/FlipExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/FlipExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/FlipExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/PadExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/PadExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/PadExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/ResizeExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/ResizeExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/ResizeExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/ResizeExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/RotateExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/RotateExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/RotateExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/RotateFlipExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/RotateFlipExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/RotateFlipExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/SkewExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/SkewExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/SkewExtensions.cs diff --git a/src/ImageSharp/Processing/Extensions/TransformExtensions.cs b/src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs similarity index 100% rename from src/ImageSharp/Processing/Extensions/TransformExtensions.cs rename to src/ImageSharp/Processing/Extensions/Transforms/TransformExtensions.cs diff --git a/src/ImageSharp/Processing/IImageProcessingContext.cs b/src/ImageSharp/Processing/IImageProcessingContext.cs index 509b1313d..e10c14088 100644 --- a/src/ImageSharp/Processing/IImageProcessingContext.cs +++ b/src/ImageSharp/Processing/IImageProcessingContext.cs @@ -13,10 +13,9 @@ namespace SixLabors.ImageSharp.Processing public interface IImageProcessingContext { /// - /// Gets a reference to the used to allocate buffers - /// for this context. + /// Gets the configuration which allows altering default behaviour or extending the library. /// - MemoryAllocator MemoryAllocator { get; } + Configuration Configuration { get; } /// /// Gets the image dimensions at the current point in the processing pipeline. @@ -39,4 +38,4 @@ namespace SixLabors.ImageSharp.Processing /// The current operations class to allow chaining of operations. IImageProcessingContext ApplyProcessor(IImageProcessor processor); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/IImageProcessingContextFactory.cs b/src/ImageSharp/Processing/IImageProcessingContextFactory.cs index 948e70b44..e3051ccdd 100644 --- a/src/ImageSharp/Processing/IImageProcessingContextFactory.cs +++ b/src/ImageSharp/Processing/IImageProcessingContextFactory.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -14,10 +14,11 @@ namespace SixLabors.ImageSharp.Processing /// Called during mutate operations to generate the image operations provider. /// /// The pixel format + /// The configuration which allows altering default behaviour or extending the library. /// The source image. /// A flag to determine whether image operations are allowed to mutate the source image. /// A new - IInternalImageProcessingContext CreateImageProcessingContext(Image source, bool mutate) + IInternalImageProcessingContext CreateImageProcessingContext(Configuration configuration, Image source, bool mutate) where TPixel : struct, IPixel; } @@ -27,10 +28,10 @@ namespace SixLabors.ImageSharp.Processing internal class DefaultImageOperationsProviderFactory : IImageProcessingContextFactory { /// - public IInternalImageProcessingContext CreateImageProcessingContext(Image source, bool mutate) + public IInternalImageProcessingContext CreateImageProcessingContext(Configuration configuration, Image source, bool mutate) where TPixel : struct, IPixel { - return new DefaultImageProcessorContext(source, mutate); + return new DefaultImageProcessorContext(configuration, source, mutate); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs b/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs index 55303b1ef..9d023cca8 100644 --- a/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs +++ b/src/ImageSharp/Processing/IInternalImageProcessingContext{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -13,10 +13,10 @@ namespace SixLabors.ImageSharp.Processing where TPixel : struct, IPixel { /// - /// Returns the result image to return by + /// Returns the result image to return by /// (and other overloads). /// /// The current image or a new image depending on whether it is requested to mutate the source image. Image GetResultImage(); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/PixelShader.cs b/src/ImageSharp/Processing/PixelShader.cs new file mode 100644 index 000000000..0245931fb --- /dev/null +++ b/src/ImageSharp/Processing/PixelShader.cs @@ -0,0 +1,15 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A representing a user defined pixel shader. + /// + /// The target row of pixels to process. + /// The , , , and fields map the RGBA channels respectively. + public delegate void PixelShader(Span span); +} diff --git a/src/ImageSharp/Processing/PositionAwarePixelShader.cs b/src/ImageSharp/Processing/PositionAwarePixelShader.cs new file mode 100644 index 000000000..1ae3ba295 --- /dev/null +++ b/src/ImageSharp/Processing/PositionAwarePixelShader.cs @@ -0,0 +1,17 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// A representing a user defined pixel shader. + /// + /// The target row of pixels to process. + /// The initial horizontal and vertical offset for the input pixels to process. + /// The , , , and fields map the RGBA channels respectively. + public delegate void PositionAwarePixelShader(Span span, Point offset); +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 80164793b..caedf87ba 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -70,8 +70,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public Color LowerColor { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - => new BinaryErrorDiffusionProcessor(this, source, sourceRectangle); + => new BinaryErrorDiffusionProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs index c59e77b10..cdea1780f 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs @@ -22,11 +22,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public BinaryErrorDiffusionProcessor(BinaryErrorDiffusionProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public BinaryErrorDiffusionProcessor(Configuration configuration, BinaryErrorDiffusionProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 0a426c893..6a2ee7623 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -52,8 +52,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public Color LowerColor { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - => new BinaryOrderedDitherProcessor(this, source, sourceRectangle); + => new BinaryOrderedDitherProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs index d750c9f07..64fb617c6 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs @@ -22,11 +22,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public BinaryOrderedDitherProcessor(BinaryOrderedDitherProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public BinaryOrderedDitherProcessor(Configuration configuration, BinaryOrderedDitherProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index a33c46469..102232b13 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -50,8 +50,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public Color LowerColor { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - => new BinaryThresholdProcessor(this, source, sourceRectangle); + => new BinaryThresholdProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index 20a22fba3..45cb1d9f7 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -22,11 +22,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public BinaryThresholdProcessor(BinaryThresholdProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public BinaryThresholdProcessor(Configuration configuration, BinaryThresholdProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index 5e9ca2e54..3b88cf7f0 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -12,11 +12,11 @@ namespace SixLabors.ImageSharp.Processing.Processors public abstract class CloningImageProcessor : ICloningImageProcessor { /// - public abstract ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) + public abstract ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; /// - IImageProcessor IImageProcessor.CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - => this.CreatePixelSpecificCloningProcessor(source, sourceRectangle); + IImageProcessor IImageProcessor.CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => this.CreatePixelSpecificCloningProcessor(configuration, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs index 42d2f0e1d..780bec22c 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -22,13 +21,14 @@ namespace SixLabors.ImageSharp.Processing.Processors /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The source for the current processor instance. /// The source area to process for the current processor instance. - protected CloningImageProcessor(Image source, Rectangle sourceRectangle) + protected CloningImageProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) { + this.Configuration = configuration; this.Source = source; this.SourceRectangle = sourceRectangle; - this.Configuration = this.Source.GetConfiguration(); } /// @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Image clone = this.CreateTarget(); this.CheckFrameCount(this.Source, clone); - Configuration configuration = this.Source.GetConfiguration(); + Configuration configuration = this.Configuration; this.BeforeImageApply(clone); for (int i = 0; i < this.Source.Frames.Count; i++) @@ -173,16 +173,19 @@ namespace SixLabors.ImageSharp.Processing.Processors Image source = this.Source; Size targetSize = this.GetTargetSize(); - // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select, ImageFrame>( - x => new ImageFrame( - source.GetConfiguration(), + // We will always be creating the clone even for mutate because we may need to resize the canvas. + var targetFrames = new ImageFrame[source.Frames.Count]; + for (int i = 0; i < targetFrames.Length; i++) + { + targetFrames[i] = new ImageFrame( + this.Configuration, targetSize.Width, targetSize.Height, - x.Metadata.DeepClone())); + source.Frames[i].Metadata.DeepClone()); + } - // Use the overload to prevent an extra frame being added - return new Image(this.Configuration, source.Metadata.DeepClone(), frames); + // Use the overload to prevent an extra frame being added. + return new Image(this.Configuration, source.Metadata.DeepClone(), targetFrames); } private void CheckFrameCount(Image a, Image b) diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs index 1812884b8..477c3da9a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs @@ -71,10 +71,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public float Gamma { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new BokehBlurProcessor(this, source, sourceRectangle); - } + => new BokehBlurProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index efd18dafb..6ffda59a8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -69,11 +69,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public BokehBlurProcessor(BokehBlurProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public BokehBlurProcessor(Configuration configuration, BokehBlurProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.radius = definition.Radius; this.kernelSize = (this.radius * 2) + 1; diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index a5368c463..94ecce9d1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -7,7 +7,7 @@ using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// - /// Defines a box blur processor of a given Radius. + /// Defines a box blur processor of a given radius. /// public sealed class BoxBlurProcessor : IImageProcessor { @@ -41,10 +41,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public int Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new BoxBlurProcessor(this, source, sourceRectangle); - } + => new BoxBlurProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs index 77110e642..f127fc1a8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs @@ -14,18 +14,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution internal class BoxBlurProcessor : ImageProcessor where TPixel : struct, IPixel { - private readonly BoxBlurProcessor definition; - /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public BoxBlurProcessor(BoxBlurProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public BoxBlurProcessor(Configuration configuration, BoxBlurProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { - this.definition = definition; int kernelSize = (definition.Radius * 2) + 1; this.KernelX = CreateBoxKernel(kernelSize); this.KernelY = this.KernelX.Transpose(); @@ -44,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source) { - using (var processor = new Convolution2PassProcessor(this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle)) + using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle)) { processor.Apply(source); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index 4419f064e..44faf3eb1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -23,18 +23,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The horizontal gradient operator. /// The vertical gradient operator. /// Whether the convolution filter is applied to alpha as well as the color channels. /// The source for the current processor instance. /// The source area to process for the current processor instance. public Convolution2DProcessor( + Configuration configuration, in DenseMatrix kernelX, in DenseMatrix kernelY, bool preserveAlpha, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + : base(configuration, source, sourceRectangle) { Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index 9fad8b5b7..5182d90b1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -23,18 +23,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The horizontal gradient operator. /// The vertical gradient operator. /// Whether the convolution filter is applied to alpha as well as the color channels. /// The source for the current processor instance. /// The source area to process for the current processor instance. public Convolution2PassProcessor( + Configuration configuration, in DenseMatrix kernelX, in DenseMatrix kernelY, bool preserveAlpha, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + : base(configuration, source, sourceRectangle) { this.KernelX = kernelX; this.KernelY = kernelY; diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index f657e131d..6f0e7914b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -23,16 +23,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The 2d gradient operator. /// Whether the convolution filter is applied to alpha as well as the color channels. /// The source for the current processor instance. /// The source area to process for the current processor instance. public ConvolutionProcessor( + Configuration configuration, in DenseMatrix kernelXY, bool preserveAlpha, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + : base(configuration, source, sourceRectangle) { this.KernelXY = kernelXY; this.PreserveAlpha = preserveAlpha; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs index 8358abe7d..dbd82191c 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs @@ -18,18 +18,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The horizontal gradient operator. /// The vertical gradient operator. /// Whether to convert the image to grayscale before performing edge detection. /// The source for the current processor instance. /// The source area to process for the current processor instance. internal EdgeDetector2DProcessor( + Configuration configuration, in DenseMatrix kernelX, in DenseMatrix kernelY, bool grayscale, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + : base(configuration, source, sourceRectangle) { Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; @@ -54,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).Execute(this.Source, this.SourceRectangle); + new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle); } base.BeforeImageApply(); @@ -63,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source) { - using (var processor = new Convolution2DProcessor(this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle)) + using (var processor = new Convolution2DProcessor(this.Configuration, this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle)) { processor.Apply(source); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index 4fa87bc98..f3940bb73 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -25,12 +25,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// Gets the kernels to use. /// Whether to convert the image to grayscale before performing edge detection. /// The source for the current processor instance. /// The source area to process for the current processor instance. - internal EdgeDetectorCompassProcessor(CompassKernels kernels, bool grayscale, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + internal EdgeDetectorCompassProcessor(Configuration configuration, CompassKernels kernels, bool grayscale, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.Grayscale = grayscale; this.Kernels = kernels; @@ -45,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).Execute(this.Source, this.SourceRectangle); + new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle); } base.BeforeImageApply(); @@ -70,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution // we need a clean copy for each pass to start from using (ImageFrame cleanCopy = source.Clone()) { - using (var processor = new ConvolutionProcessor(kernels[0], true, this.Source, this.SourceRectangle)) + using (var processor = new ConvolutionProcessor(this.Configuration, kernels[0], true, this.Source, this.SourceRectangle)) { processor.Apply(source); } @@ -102,7 +103,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { using (ImageFrame pass = cleanCopy.Clone()) { - using (var processor = new ConvolutionProcessor(kernels[i], true, this.Source, this.SourceRectangle)) + using (var processor = new ConvolutionProcessor(this.Configuration, kernels[i], true, this.Source, this.SourceRectangle)) { processor.Apply(pass); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs index 24b95da69..f369d60dd 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public bool Grayscale { get; } /// - public abstract IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public abstract IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs index 5246dc3b7..e6411f8cb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs @@ -18,12 +18,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The 2d gradient operator. /// Whether to convert the image to grayscale before performing edge detection. /// The source for the current processor instance. /// The target area to process for the current processor instance. - public EdgeDetectorProcessor(in DenseMatrix kernelXY, bool grayscale, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public EdgeDetectorProcessor( + Configuration configuration, + in DenseMatrix kernelXY, + bool grayscale, + Image source, + Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.KernelXY = kernelXY; this.Grayscale = grayscale; @@ -41,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).Execute(this.Source, this.SourceRectangle); + new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle); } base.BeforeImageApply(); @@ -50,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source) { - using (var processor = new ConvolutionProcessor(this.KernelXY, true, this.Source, this.SourceRectangle)) + using (var processor = new ConvolutionProcessor(this.Configuration, this.KernelXY, true, this.Source, this.SourceRectangle)) { processor.Apply(source); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index aabc8041d..bdba8f4ca 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -71,10 +71,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public int Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new GaussianBlurProcessor(this, source, sourceRectangle); - } + => new GaussianBlurProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs index bbf36ea5e..2ccd8d577 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs @@ -17,11 +17,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public GaussianBlurProcessor(GaussianBlurProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public GaussianBlurProcessor( + Configuration configuration, + GaussianBlurProcessor definition, + Image source, + Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { int kernelSize = (definition.Radius * 2) + 1; this.KernelX = ConvolutionProcessorHelpers.CreateGaussianBlurKernel(kernelSize, definition.Sigma); @@ -41,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source) { - using (var processor = new Convolution2PassProcessor(this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle)) + using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle)) { processor.Apply(source); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index 0262ec8e4..d1b2b3072 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// public sealed class GaussianSharpenProcessor : IImageProcessor { - /// + /// /// The default value for . /// public const float DefaultSigma = 3f; @@ -71,10 +71,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public int Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new GaussianSharpenProcessor(this, source, sourceRectangle); - } + => new GaussianSharpenProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs index dab55b232..d61d8e6c5 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs @@ -17,11 +17,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public GaussianSharpenProcessor(GaussianSharpenProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public GaussianSharpenProcessor( + Configuration configuration, + GaussianSharpenProcessor definition, + Image source, + Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { int kernelSize = (definition.Radius * 2) + 1; this.KernelX = ConvolutionProcessorHelpers.CreateGaussianSharpenKernel(kernelSize, definition.Sigma); @@ -41,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source) { - using (var processor = new Convolution2PassProcessor(this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle)) + using (var processor = new Convolution2PassProcessor(this.Configuration, this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle)) { processor.Apply(source); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs index 202651261..cc29be983 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs @@ -21,14 +21,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetector2DProcessor( + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetector2DProcessor( + configuration, KayyaliKernels.KayyaliX, KayyaliKernels.KayyaliY, this.Grayscale, source, sourceRectangle); - } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs index bbbfc64d9..182a30c08 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs @@ -21,9 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetectorCompassProcessor(new KirschKernels(), this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetectorCompassProcessor(configuration, new KirschKernels(), this.Grayscale, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs index 64f99ebe6..163420f3d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs @@ -21,9 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetectorProcessor(LaplacianKernels.Laplacian3x3, this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetectorProcessor(configuration, LaplacianKernels.Laplacian3x3, this.Grayscale, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs index d1c909a94..77cfffced 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs @@ -21,9 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetectorProcessor(LaplacianKernels.Laplacian5x5, this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetectorProcessor(configuration, LaplacianKernels.Laplacian5x5, this.Grayscale, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs index 0eecaefe1..a8d3ff6f1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs @@ -21,9 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetectorProcessor(LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetectorProcessor(configuration, LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs index 242e3f7b9..dcb20573a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs @@ -21,9 +21,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetector2DProcessor(PrewittKernels.PrewittX, PrewittKernels.PrewittY, this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetector2DProcessor( + configuration, + PrewittKernels.PrewittX, + PrewittKernels.PrewittY, + this.Grayscale, + source, + sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs index 481a990ff..84b685467 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs @@ -21,14 +21,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetector2DProcessor( + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetector2DProcessor( + configuration, RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY, this.Grayscale, source, sourceRectangle); - } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs index 324ed3154..34c4ab35a 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs @@ -21,9 +21,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetectorCompassProcessor(new RobinsonKernels(), this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetectorCompassProcessor(configuration, new RobinsonKernels(), this.Grayscale, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs index 6a4bf6afd..76a4ae08d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs @@ -21,9 +21,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetector2DProcessor(ScharrKernels.ScharrX, ScharrKernels.ScharrY, this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetector2DProcessor( + configuration, + ScharrKernels.ScharrX, + ScharrKernels.ScharrY, + this.Grayscale, + source, + sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs index 96ed3bcea..185ac891d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs @@ -21,9 +21,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new EdgeDetector2DProcessor(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new EdgeDetector2DProcessor( + configuration, + SobelKernels.SobelX, + SobelKernels.SobelY, + this.Grayscale, + source, + sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index 4e45130cc..48ad546f2 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -58,9 +58,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public float Threshold { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) { - return new ErrorDiffusionPaletteProcessor(this, source, sourceRectangle); + return new ErrorDiffusionPaletteProcessor(configuration, this, source, sourceRectangle); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs index 37dcd7d5c..ff4b6de52 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs @@ -19,11 +19,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public ErrorDiffusionPaletteProcessor(ErrorDiffusionPaletteProcessor definition, Image source, Rectangle sourceRectangle) - : base(definition, source, sourceRectangle) + public ErrorDiffusionPaletteProcessor(Configuration configuration, ErrorDiffusionPaletteProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition, source, sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index 87bb3e517..d66ce2192 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -35,9 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public IOrderedDither Dither { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new OrderedDitherPaletteProcessor(this, source, sourceRectangle); - } + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new OrderedDitherPaletteProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs index 8cde8943e..6568033ea 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs @@ -19,11 +19,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public OrderedDitherPaletteProcessor(OrderedDitherPaletteProcessor definition, Image source, Rectangle sourceRectangle) - : base(definition, source, sourceRectangle) + public OrderedDitherPaletteProcessor(Configuration configuration, OrderedDitherPaletteProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition, source, sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs index 0de964b52..a8f46f3ad 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering public ReadOnlyMemory Palette { get; } /// - public abstract IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public abstract IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 10e963942..10c9a421e 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -8,7 +8,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering @@ -29,11 +28,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - protected PaletteDitherProcessor(PaletteDitherProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + protected PaletteDitherProcessor(Configuration configuration, PaletteDitherProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.Definition = definition; this.palette = this.Configuration.MemoryAllocator.Allocate(definition.Palette.Length); diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 6f9e1869a..0e11020eb 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -40,10 +40,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects public int BrushSize { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new OilPaintingProcessor(this, source, sourceRectangle); - } + => new OilPaintingProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs index 943d7f234..e2e2d8d5d 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs @@ -29,11 +29,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public OilPaintingProcessor(OilPaintingProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public OilPaintingProcessor(Configuration configuration, OilPaintingProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessor.cs new file mode 100644 index 000000000..2d43fd53c --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessor.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Effects +{ + /// + /// Applies a user defined pixel shader effect through a given delegate. + /// + public sealed class PixelShaderProcessor : IImageProcessor + { + /// + /// The default to apply during the pixel conversions. + /// + public const PixelConversionModifiers DefaultModifiers = PixelConversionModifiers.None; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The user defined pixel shader to use to modify images. + /// + public PixelShaderProcessor(PixelShader pixelShader) + { + this.PixelShader = pixelShader; + this.Modifiers = DefaultModifiers; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The user defined pixel shader to use to modify images. + /// + /// The to apply during the pixel conversions. + public PixelShaderProcessor(PixelShader pixelShader, PixelConversionModifiers modifiers) + { + this.PixelShader = pixelShader; + this.Modifiers = modifiers; + } + + /// + /// Gets the user defined pixel shader. + /// + public PixelShader PixelShader { get; } + + /// + /// Gets the to apply during the pixel conversions. + /// + public PixelConversionModifiers Modifiers { get; } + + /// + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + where TPixel : struct, IPixel + => new PixelShaderProcessor(configuration, this, source, sourceRectangle); + } +} diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessorBase.cs b/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessorBase.cs new file mode 100644 index 000000000..9cee3779d --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessorBase.cs @@ -0,0 +1,74 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Advanced.ParallelUtils; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Effects +{ + /// + /// Applies a user defined pixel shader effect through a given delegate. + /// + /// The pixel format. + internal abstract class PixelShaderProcessorBase : ImageProcessor + where TPixel : struct, IPixel + { + /// + /// The to apply during the pixel conversions. + /// + private readonly PixelConversionModifiers modifiers; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration which allows altering default behaviour or extending the library. + /// The to apply during the pixel conversions. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + protected PixelShaderProcessorBase(Configuration configuration, PixelConversionModifiers modifiers, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) + { + this.modifiers = modifiers; + } + + /// + protected override void OnFrameApply(ImageFrame source) + { + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + int startX = interest.X; + Configuration configuration = this.Configuration; + PixelConversionModifiers modifiers = this.modifiers; + + ParallelHelper.IterateRowsWithTempBuffer( + interest, + this.Configuration, + (rows, vectorBuffer) => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span vectorSpan = vectorBuffer.Span; + int length = vectorSpan.Length; + Span rowSpan = source.GetPixelRowSpan(y).Slice(startX, length); + PixelOperations.Instance.ToVector4(configuration, rowSpan, vectorSpan, modifiers); + + // Run the user defined pixel shader on the current row of pixels + this.ApplyPixelShader(vectorSpan, new Point(startX, y)); + + PixelOperations.Instance.FromVector4Destructive(configuration, vectorSpan, rowSpan, modifiers); + } + }); + } + + /// + /// Applies the current pixel shader effect on a target row of preprocessed pixels. + /// + /// The target row of pixels to process. + /// The initial horizontal and vertical offset for the input pixels to process. + protected abstract void ApplyPixelShader(Span span, Point offset); + } +} diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessor{TPixel}.cs new file mode 100644 index 000000000..a4338423e --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Effects/PixelShaderProcessor{TPixel}.cs @@ -0,0 +1,40 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Effects +{ + /// + /// Applies a user defined pixel shader effect through a given delegate. + /// + /// The pixel format. + internal sealed class PixelShaderProcessor : PixelShaderProcessorBase + where TPixel : struct, IPixel + { + /// + /// The user defined pixel shader. + /// + private readonly PixelShader pixelShader; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration which allows altering default behaviour or extending the library. + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public PixelShaderProcessor(Configuration configuration, PixelShaderProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition.Modifiers, source, sourceRectangle) + { + this.pixelShader = definition.PixelShader; + } + + /// + protected override void ApplyPixelShader(Span span, Point offset) => this.pixelShader(span); + } +} diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index 2d7cef8ff..9b67545e5 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -30,10 +30,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects public int Size { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new PixelateProcessor(this, source, sourceRectangle); - } + => new PixelateProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs index 53acc351c..d15bfc007 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs @@ -24,11 +24,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The . /// The source for the current processor instance. /// The source area to process for the current processor instance. - public PixelateProcessor(PixelateProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public PixelateProcessor(Configuration configuration, PixelateProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelShaderProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelShaderProcessor.cs new file mode 100644 index 000000000..46d2e31cf --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelShaderProcessor.cs @@ -0,0 +1,59 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Effects +{ + /// + /// Applies a user defined pixel shader effect through a given delegate. + /// + public sealed class PositionAwarePixelShaderProcessor : IImageProcessor + { + /// + /// The default to apply during the pixel conversions. + /// + public const PixelConversionModifiers DefaultModifiers = PixelConversionModifiers.None; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The user defined pixel shader to use to modify images. + /// + public PositionAwarePixelShaderProcessor(PositionAwarePixelShader pixelShader) + { + this.PixelShader = pixelShader; + this.Modifiers = DefaultModifiers; + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The user defined pixel shader to use to modify images. + /// + /// The to apply during the pixel conversions. + public PositionAwarePixelShaderProcessor(PositionAwarePixelShader pixelShader, PixelConversionModifiers modifiers) + { + this.PixelShader = pixelShader; + this.Modifiers = modifiers; + } + + /// + /// Gets the user defined pixel shader. + /// + public PositionAwarePixelShader PixelShader { get; } + + /// + /// Gets the to apply during the pixel conversions. + /// + public PixelConversionModifiers Modifiers { get; } + + /// + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + where TPixel : struct, IPixel + => new PositionAwarePixelShaderProcessor(configuration, this, source, sourceRectangle); + } +} diff --git a/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelShaderProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelShaderProcessor{TPixel}.cs new file mode 100644 index 000000000..db2d85bfc --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Effects/PositionAwarePixelShaderProcessor{TPixel}.cs @@ -0,0 +1,40 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Effects +{ + /// + /// Applies a user defined pixel shader effect through a given delegate. + /// + /// The pixel format. + internal sealed class PositionAwarePixelShaderProcessor : PixelShaderProcessorBase + where TPixel : struct, IPixel + { + /// + /// The user defined pixel shader. + /// + private readonly PositionAwarePixelShader pixelShader; + + /// + /// Initializes a new instance of the class. + /// + /// The configuration which allows altering default behaviour or extending the library. + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public PositionAwarePixelShaderProcessor(Configuration configuration, PositionAwarePixelShaderProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition.Modifiers, source, sourceRectangle) + { + this.pixelShader = definition.PixelShader; + } + + /// + protected override void ApplyPixelShader(Span span, Point offset) => this.pixelShader(span, offset); + } +} diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index 9cd4a9e46..028060f66 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -24,10 +24,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters public ColorMatrix Matrix { get; } /// - public virtual IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public virtual IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new FilterProcessor(this, source, sourceRectangle); - } + => new FilterProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index 731cd2a05..86d990a38 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -23,11 +23,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The . /// The source for the current processor instance. /// The source area to process for the current processor instance. - public FilterProcessor(FilterProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public FilterProcessor(Configuration configuration, FilterProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs index fdfaa9cb0..8836bd62c 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) => - new LomographProcessor(this, source, sourceRectangle); + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) => + new LomographProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index 7d3a5bbc0..30731fcbf 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -18,18 +18,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public LomographProcessor(LomographProcessor definition, Image source, Rectangle sourceRectangle) - : base(definition, source, sourceRectangle) + public LomographProcessor(Configuration configuration, LomographProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition, source, sourceRectangle) { } /// protected override void AfterImageApply() { - new VignetteProcessor(VeryDarkGreen).Execute(this.Source, this.SourceRectangle); + new VignetteProcessor(VeryDarkGreen).Execute(this.Configuration, this.Source, this.SourceRectangle); base.AfterImageApply(); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs index c8527a29c..9a8c2b518 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) => - new PolaroidProcessor(this, source, sourceRectangle); + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) => + new PolaroidProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index f7ab1a1ec..08235e1bf 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -14,25 +14,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters where TPixel : struct, IPixel { private static readonly Color LightOrange = Color.FromRgba(255, 153, 102, 128); - private static readonly Color VeryDarkOrange = Color.FromRgb(102, 34, 0); /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public PolaroidProcessor(PolaroidProcessor definition, Image source, Rectangle sourceRectangle) - : base(definition, source, sourceRectangle) + public PolaroidProcessor(Configuration configuration, PolaroidProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition, source, sourceRectangle) { } /// protected override void AfterImageApply() { - new VignetteProcessor(VeryDarkOrange).Execute(this.Source, this.SourceRectangle); - new GlowProcessor(LightOrange, this.Source.Width / 4F).Execute(this.Source, this.SourceRectangle); + new VignetteProcessor(VeryDarkOrange).Execute(this.Configuration, this.Source, this.SourceRectangle); + new GlowProcessor(LightOrange, this.Source.Width / 4F).Execute(this.Configuration, this.Source, this.SourceRectangle); base.AfterImageApply(); } } diff --git a/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs index 554a4b886..7ffa5bcc0 100644 --- a/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs @@ -16,12 +16,13 @@ namespace SixLabors.ImageSharp.Processing.Processors /// the processing algorithm on an . /// /// The pixel type. + /// The configuration which allows altering default behaviour or extending the library. /// The source image. Cannot be null. /// /// The structure that specifies the portion of the image object to draw. /// /// The - ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) + ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/IImageProcessor.cs b/src/ImageSharp/Processing/Processors/IImageProcessor.cs index fb7a6a4d9..6b9b82b10 100644 --- a/src/ImageSharp/Processing/Processors/IImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/IImageProcessor.cs @@ -19,12 +19,13 @@ namespace SixLabors.ImageSharp.Processing.Processors /// the processing algorithm on an . /// /// The pixel type. + /// The configuration which allows altering default behaviour or extending the library. /// The source image. Cannot be null. /// /// The structure that specifies the portion of the image object to draw. /// /// The - IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs index ce8ed813b..7956ecd9a 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs @@ -13,18 +13,21 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Executes the processor against the given source image and rectangle bounds. /// /// The processor. + /// The configuration which allows altering default behaviour or extending the library. /// The source image. /// The source bounds. - public static void Execute(this IImageProcessor processor, Image source, Rectangle sourceRectangle) - => source.AcceptVisitor(new ExecuteVisitor(processor, sourceRectangle)); + public static void Execute(this IImageProcessor processor, Configuration configuration, Image source, Rectangle sourceRectangle) + => source.AcceptVisitor(new ExecuteVisitor(configuration, processor, sourceRectangle)); private class ExecuteVisitor : IImageVisitor { + private readonly Configuration configuration; private readonly IImageProcessor processor; private readonly Rectangle sourceRectangle; - public ExecuteVisitor(IImageProcessor processor, Rectangle sourceRectangle) + public ExecuteVisitor(Configuration configuration, IImageProcessor processor, Rectangle sourceRectangle) { + this.configuration = configuration; this.processor = processor; this.sourceRectangle = sourceRectangle; } @@ -32,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public void Visit(Image image) where TPixel : struct, IPixel { - using (IImageProcessor processorImpl = this.processor.CreatePixelSpecificProcessor(image, this.sourceRectangle)) + using (IImageProcessor processorImpl = this.processor.CreatePixelSpecificProcessor(this.configuration, image, this.sourceRectangle)) { processorImpl.Execute(); } diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs index b8bbe1e03..21d245a11 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor{TPixel}.cs @@ -19,13 +19,14 @@ namespace SixLabors.ImageSharp.Processing.Processors /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The source for the current processor instance. /// The source area to process for the current processor instance. - protected ImageProcessor(Image source, Rectangle sourceRectangle) + protected ImageProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) { + this.Configuration = configuration; this.Source = source; this.SourceRectangle = sourceRectangle; - this.Configuration = this.Source.GetConfiguration(); } /// diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs index 68c1474be..6d8ccdca3 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs @@ -35,9 +35,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization public int NumberOfTiles { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) { return new AdaptiveHistogramEqualizationProcessor( + configuration, this.LuminanceLevels, this.ClipHistogram, this.ClipLimit, diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index e3960035e..0e664a598 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -27,6 +27,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The number of different luminance levels. Typical values are 256 for 8-bit grayscale images /// or 65536 for 16-bit grayscale images. /// Indicating whether to clip the histogram bins at a specific value. @@ -35,13 +36,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// The source for the current processor instance. /// The source area to process for the current processor instance. public AdaptiveHistogramEqualizationProcessor( + Configuration configuration, int luminanceLevels, bool clipHistogram, int clipLimit, int tiles, Image source, Rectangle sourceRectangle) - : base(luminanceLevels, clipHistogram, clipLimit, source, sourceRectangle) + : base(configuration, luminanceLevels, clipHistogram, clipLimit, source, sourceRectangle) { Guard.MustBeGreaterThanOrEqualTo(tiles, 2, nameof(tiles)); Guard.MustBeLessThanOrEqualTo(tiles, 100, nameof(tiles)); diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs index 632cfcd59..cd29b18b9 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs @@ -34,15 +34,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization public int NumberOfTiles { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new AdaptiveHistogramEqualizationSlidingWindowProcessor( + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new AdaptiveHistogramEqualizationSlidingWindowProcessor( + configuration, this.LuminanceLevels, this.ClipHistogram, this.ClipLimit, this.NumberOfTiles, source, sourceRectangle); - } } } diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs index 622c133ae..901668e1f 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs @@ -26,6 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The number of different luminance levels. Typical values are 256 for 8-bit grayscale images /// or 65536 for 16-bit grayscale images. /// Indicating whether to clip the histogram bins at a specific value. @@ -34,13 +35,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// The source for the current processor instance. /// The source area to process for the current processor instance. public AdaptiveHistogramEqualizationSlidingWindowProcessor( + Configuration configuration, int luminanceLevels, bool clipHistogram, int clipLimit, int tiles, Image source, Rectangle sourceRectangle) - : base(luminanceLevels, clipHistogram, clipLimit, source, sourceRectangle) + : base(configuration, luminanceLevels, clipHistogram, clipLimit, source, sourceRectangle) { Guard.MustBeGreaterThanOrEqualTo(tiles, 2, nameof(tiles)); Guard.MustBeLessThanOrEqualTo(tiles, 100, nameof(tiles)); diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs index 0666b21bf..288b59d6b 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs @@ -22,14 +22,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization } /// - public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) - { - return new GlobalHistogramEqualizationProcessor( + public override IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new GlobalHistogramEqualizationProcessor( + configuration, this.LuminanceLevels, this.ClipHistogram, this.ClipLimit, source, sourceRectangle); - } } } diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs index f8cd5620a..f75655006 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs @@ -26,6 +26,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// /// The number of different luminance levels. Typical values are 256 for 8-bit grayscale images /// or 65536 for 16-bit grayscale images. @@ -35,12 +36,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// The source for the current processor instance. /// The source area to process for the current processor instance. public GlobalHistogramEqualizationProcessor( + Configuration configuration, int luminanceLevels, bool clipHistogram, int clipLimit, Image source, Rectangle sourceRectangle) - : base(luminanceLevels, clipHistogram, clipLimit, source, sourceRectangle) + : base(configuration, luminanceLevels, clipHistogram, clipLimit, source, sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index 4273e9375..7c1969ae2 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization public int ClipLimit { get; } /// - public abstract IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public abstract IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; /// diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs index 284b9de1f..8c25448d1 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -23,6 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The number of different luminance levels. Typical values are 256 for 8-bit grayscale images /// or 65536 for 16-bit grayscale images. /// Indicates, if histogram bins should be clipped. @@ -30,12 +30,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// The source for the current processor instance. /// The source area to process for the current processor instance. protected HistogramEqualizationProcessor( + Configuration configuration, int luminanceLevels, bool clipHistogram, int clipLimit, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + : base(configuration, source, sourceRectangle) { Guard.MustBeGreaterThan(luminanceLevels, 0, nameof(luminanceLevels)); Guard.MustBeGreaterThan(clipLimit, 1, nameof(clipLimit)); diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index e78f7e5e7..6531c7461 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -33,10 +33,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays public Color Color { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new BackgroundColorProcessor(this, source, sourceRectangle); - } + => new BackgroundColorProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index 7e3d2fdc5..0d9ee263a 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -24,11 +24,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public BackgroundColorProcessor(BackgroundColorProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public BackgroundColorProcessor(Configuration configuration, BackgroundColorProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 4b9a23eff..13936232a 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -70,10 +70,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays internal ValueSize Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new GlowProcessor(this, source, sourceRectangle); - } + => new GlowProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index 4082d9a65..3f52a1c88 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -21,17 +21,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays where TPixel : struct, IPixel { private readonly PixelBlender blender; - private readonly GlowProcessor definition; /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public GlowProcessor(GlowProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public GlowProcessor(Configuration configuration, GlowProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; this.blender = PixelOperations.Instance.GetPixelBlender(definition.GraphicsOptions); diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 3cf48e5a4..ebec16062 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -68,10 +68,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays internal ValueSize RadiusY { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new VignetteProcessor(this, source, sourceRectangle); - } + => new VignetteProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs index c27a634f3..41f11f5af 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs @@ -27,11 +27,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public VignetteProcessor(VignetteProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public VignetteProcessor(Configuration configuration, VignetteProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; this.blender = PixelOperations.Instance.GetPixelBlender(definition.GraphicsOptions); diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index 8cc14da67..0ac6b9b9c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -26,10 +26,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public IQuantizer Quantizer { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new QuantizeProcessor(this.Quantizer, source, sourceRectangle); - } + => new QuantizeProcessor(configuration, this.Quantizer, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 930946722..29b4c70c1 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -21,11 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The quantizer used to reduce the color palette. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public QuantizeProcessor(IQuantizer quantizer, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public QuantizeProcessor(Configuration configuration, IQuantizer quantizer, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { Guard.NotNull(quantizer, nameof(quantizer)); this.quantizer = quantizer; diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 6ca844fae..ffd5bc2d7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public Size TargetDimensions { get; } /// - public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) - => new AffineTransformProcessor(this, source, sourceRectangle); + public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new AffineTransformProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs index e693de8f6..9251b95fc 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs @@ -24,11 +24,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public AffineTransformProcessor(AffineTransformProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public AffineTransformProcessor(Configuration configuration, AffineTransformProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.targetSize = definition.TargetDimensions; this.transformMatrix = definition.TransformMatrix; diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs index eef7643da..e17588cd0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs @@ -12,10 +12,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public sealed class AutoOrientProcessor : IImageProcessor { /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new AutoOrientProcessor(source, sourceRectangle); - } + => new AutoOrientProcessor(configuration, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs index b9952ac8f..ebc81b604 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs @@ -19,10 +19,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public AutoOrientProcessor(Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public AutoOrientProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { } @@ -34,33 +35,33 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms switch (orientation) { case OrientationMode.TopRight: - new FlipProcessor(FlipMode.Horizontal).Execute(this.Source, this.SourceRectangle); + new FlipProcessor(FlipMode.Horizontal).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.BottomRight: - new RotateProcessor((int)RotateMode.Rotate180, size).Execute(this.Source, this.SourceRectangle); + new RotateProcessor((int)RotateMode.Rotate180, size).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.BottomLeft: - new FlipProcessor(FlipMode.Vertical).Execute(this.Source, this.SourceRectangle); + new FlipProcessor(FlipMode.Vertical).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.LeftTop: - new RotateProcessor((int)RotateMode.Rotate90, size).Execute(this.Source, this.SourceRectangle); - new FlipProcessor(FlipMode.Horizontal).Execute(this.Source, this.SourceRectangle); + new RotateProcessor((int)RotateMode.Rotate90, size).Execute(this.Configuration, this.Source, this.SourceRectangle); + new FlipProcessor(FlipMode.Horizontal).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.RightTop: - new RotateProcessor((int)RotateMode.Rotate90, size).Execute(this.Source, this.SourceRectangle); + new RotateProcessor((int)RotateMode.Rotate90, size).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.RightBottom: - new FlipProcessor(FlipMode.Vertical).Execute(this.Source, this.SourceRectangle); - new RotateProcessor((int)RotateMode.Rotate270, size).Execute(this.Source, this.SourceRectangle); + new FlipProcessor(FlipMode.Vertical).Execute(this.Configuration, this.Source, this.SourceRectangle); + new RotateProcessor((int)RotateMode.Rotate270, size).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.LeftBottom: - new RotateProcessor((int)RotateMode.Rotate270, size).Execute(this.Source, this.SourceRectangle); + new RotateProcessor((int)RotateMode.Rotate270, size).Execute(this.Configuration, this.Source, this.SourceRectangle); break; case OrientationMode.Unknown: @@ -90,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return OrientationMode.Unknown; } - ExifValue value = source.Metadata.ExifProfile.GetValue(ExifTag.Orientation); + IExifValue value = source.Metadata.ExifProfile.GetValue(ExifTag.Orientation); if (value is null) { return OrientationMode.Unknown; diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 245a54208..39f00e9a1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public Rectangle CropRectangle { get; } /// - public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) - => new CropProcessor(this, source, sourceRectangle); + public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new CropProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs index 2cc4a3867..b63036a01 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs @@ -21,11 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The . /// The source for the current processor instance. /// The source area to process for the current processor instance. - public CropProcessor(CropProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public CropProcessor(Configuration configuration, CropProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) => this.cropRectangle = definition.CropRectangle; /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs index 22eecb598..fdba6ed4f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs @@ -38,10 +38,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public float Threshold { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new EntropyCropProcessor(this, source, sourceRectangle); - } + => new EntropyCropProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs index 2b900ee36..62cd24fa0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs @@ -21,11 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The . /// The source for the current processor instance. /// The source area to process for the current processor instance. - public EntropyCropProcessor(EntropyCropProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public EntropyCropProcessor(Configuration configuration, EntropyCropProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } @@ -42,16 +43,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Configuration configuration = this.Source.GetConfiguration(); // Detect the edges. - new SobelProcessor(false).Execute(temp, this.SourceRectangle); + new SobelProcessor(false).Execute(this.Configuration, temp, this.SourceRectangle); // Apply threshold binarization filter. - new BinaryThresholdProcessor(this.definition.Threshold).Execute(temp, this.SourceRectangle); + new BinaryThresholdProcessor(this.definition.Threshold).Execute(this.Configuration, temp, this.SourceRectangle); // Search for the first white pixels rectangle = ImageMaths.GetFilteredBoundingRectangle(temp.Frames.RootFrame, 0); } - new CropProcessor(rectangle, this.Source.Size()).Execute(this.Source, this.SourceRectangle); + new CropProcessor(rectangle, this.Source.Size()).Execute(this.Configuration, this.Source, this.SourceRectangle); base.BeforeImageApply(); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index e2364e180..455edf668 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -15,10 +15,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Initializes a new instance of the class. /// /// The used to perform flipping. - public FlipProcessor(FlipMode flipMode) - { - this.FlipMode = flipMode; - } + public FlipProcessor(FlipMode flipMode) => this.FlipMode = flipMode; /// /// Gets the used to perform flipping. @@ -26,10 +23,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public FlipMode FlipMode { get; } /// - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new FlipProcessor(this, source, sourceRectangle); - } + => new FlipProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs index 9ee8d0922..cbae932b8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs @@ -23,11 +23,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The . /// The source for the current processor instance. /// The source area to process for the current processor instance. - public FlipProcessor(FlipProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public FlipProcessor(Configuration configuration, FlipProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.definition = definition; } diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index d91db9a72..93ff800c8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public Size TargetDimensions { get; } /// - public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) - => new ProjectiveTransformProcessor(this, source, sourceRectangle); + public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new ProjectiveTransformProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs index c6212a7d3..f924ef3c9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs @@ -25,11 +25,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public ProjectiveTransformProcessor(ProjectiveTransformProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public ProjectiveTransformProcessor(Configuration configuration, ProjectiveTransformProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.targetSize = definition.TargetDimensions; this.transformMatrix = definition.TransformMatrix; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index ccaa1ef9e..87b202ff7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public bool Compand { get; } /// - public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) - => new ResizeProcessor(this, source, sourceRectangle); + public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new ResizeProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 3b508032a..24752ae48 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -33,8 +33,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private ResizeKernelMap horizontalKernelMap; private ResizeKernelMap verticalKernelMap; - public ResizeProcessor(ResizeProcessor definition, Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public ResizeProcessor(Configuration configuration, ResizeProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { this.targetWidth = definition.TargetWidth; this.targetHeight = definition.TargetHeight; diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 7d6ec0e08..016395317 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public float Degrees { get; } /// - public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Image source, Rectangle sourceRectangle) - => new RotateProcessor(this, source, sourceRectangle); + public override ICloningImageProcessor CreatePixelSpecificCloningProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + => new RotateProcessor(configuration, this, source, sourceRectangle); } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs index 92776b7db..6adab8bdf 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs @@ -21,11 +21,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The defining the processor parameters. /// The source for the current processor instance. /// The source area to process for the current processor instance. - public RotateProcessor(RotateProcessor definition, Image source, Rectangle sourceRectangle) - : base(definition, source, sourceRectangle) + public RotateProcessor(Configuration configuration, RotateProcessor definition, Image source, Rectangle sourceRectangle) + : base(configuration, definition, source, sourceRectangle) { this.Degrees = definition.Degrees; } diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs index 1f0c6ebc8..513e6962e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs @@ -16,10 +16,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Initializes a new instance of the class. /// + /// The configuration which allows altering default behaviour or extending the library. /// The source for the current processor instance. /// The source area to process for the current processor instance. - protected TransformProcessor(Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + protected TransformProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs index 00c1227a6..abc8c9d43 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { @@ -25,34 +26,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - // Removing the previously stored value allows us to set a value with our own data tag if required. + // Only set the value if it already exists. if (profile.GetValue(ExifTag.PixelXDimension) != null) { - profile.RemoveValue(ExifTag.PixelXDimension); - - if (image.Width <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelXDimension, (ushort)image.Width); - } - else - { - profile.SetValue(ExifTag.PixelXDimension, (uint)image.Width); - } + profile.SetValue(ExifTag.PixelXDimension, image.Width); } if (profile.GetValue(ExifTag.PixelYDimension) != null) { - profile.RemoveValue(ExifTag.PixelYDimension); - - if (image.Height <= ushort.MaxValue) - { - profile.SetValue(ExifTag.PixelYDimension, (ushort)image.Height); - } - else - { - profile.SetValue(ExifTag.PixelYDimension, (uint)image.Height); - } + profile.SetValue(ExifTag.PixelYDimension, image.Height); } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs index e3c721610..527b6bb8b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/DecodeTga.cs @@ -1,15 +1,16 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System.Buffers; using System.IO; - +using System.Threading; using BenchmarkDotNet.Attributes; using ImageMagick; - +using Pfim; +using SixLabors.ImageSharp.Formats.Tga; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Benchmarks.Codecs { @@ -17,26 +18,74 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public class DecodeTga : BenchmarkBase { private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); + private readonly PfimConfig pfimConfig = new PfimConfig(allocator: new PfimAllocator()); + private byte[] data; [Params(TestImages.Tga.Bit24)] public string TestImage { get; set; } + [GlobalSetup] + public void SetupData() + { + this.data = File.ReadAllBytes(this.TestImageFullPath); + } + [Benchmark(Baseline = true, Description = "ImageMagick Tga")] - public Size TgaImageMagick() + public int TgaImageMagick() { - using (var magickImage = new MagickImage(this.TestImageFullPath)) + var settings = new MagickReadSettings { Format = MagickFormat.Tga }; + using (var image = new MagickImage(new MemoryStream(this.data), settings)) { - return new Size(magickImage.Width, magickImage.Height); + return image.Width; } } [Benchmark(Description = "ImageSharp Tga")] - public Size TgaCore() + public int TgaCore() { - using (var image = Image.Load(this.TestImageFullPath)) + using (var image = Image.Load(this.data, new TgaDecoder())) { - return new Size(image.Width, image.Height); + return image.Width; } } + + [Benchmark(Description = "Pfim Tga")] + public int TgaPfim() + { + using (var image = Targa.Create(this.data, this.pfimConfig)) + { + return image.Width; + } + } + + private class PfimAllocator : IImageAllocator + { + private int rented; + private readonly ArrayPool shared = ArrayPool.Shared; + + public byte[] Rent(int size) + { + return this.shared.Rent(size); + } + + public void Return(byte[] data) + { + Interlocked.Decrement(ref this.rented); + this.shared.Return(data); + } + + public int Rented => this.rented; + } + + // RESULTS (07/01/2020) + //| Method | Runtime | TestImage | Mean | Error | StdDev | Ratio | Gen 0 | Gen 1 | Gen 2 | Allocated | + //|------------------ |-------------- |-------------------- |-------------:|-------------:|-----------:|------:|-------:|------:|------:|----------:| + //| 'ImageMagick Tga' | .NET 4.7.2 | Tga/targa_24bit.tga | 1,778.965 us | 1,711.088 us | 93.7905 us | 1.000 | 1.9531 | - | - | 13668 B | + //| 'ImageSharp Tga' | .NET 4.7.2 | Tga/targa_24bit.tga | 38.659 us | 6.886 us | 0.3774 us | 0.022 | 0.3052 | - | - | 1316 B | + //| 'Pfim Tga' | .NET 4.7.2 | Tga/targa_24bit.tga | 6.752 us | 10.268 us | 0.5628 us | 0.004 | 0.0687 | - | - | 313 B | + //| | | | | | | | | | | | + //| 'ImageMagick Tga' | .NET Core 2.1 | Tga/targa_24bit.tga | 1,407.585 us | 124.215 us | 6.8087 us | 1.000 | 1.9531 | - | - | 13307 B | + //| 'ImageSharp Tga' | .NET Core 2.1 | Tga/targa_24bit.tga | 17.958 us | 9.352 us | 0.5126 us | 0.013 | 0.2747 | - | - | 1256 B | + //| 'Pfim Tga' | .NET Core 2.1 | Tga/targa_24bit.tga | 5.645 us | 2.279 us | 0.1249 us | 0.004 | 0.0610 | - | - | 280 B | } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 99b071e59..17ad79e58 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -6,6 +6,7 @@ using System.IO; using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; using SixLabors.ImageSharp.Formats.Jpeg; @@ -35,8 +36,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg public ShortClr() { this.Add( - // Job.Clr.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3) + // Job.Default.With(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3), + Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(2).WithIterationCount(3) ); } } diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs index bf694211d..6d4caa843 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs @@ -17,6 +17,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Diagnosers; + using BenchmarkDotNet.Environments; using SixLabors.ImageSharp.Tests; using CoreImage = ImageSharp.Image; @@ -36,7 +37,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs public ShortClr() { this.Add( - Job.Core.WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2) + Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(1).WithIterationCount(2) ); } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index 0543cbc50..018a2e02b 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using BenchmarkDotNet.Configs; using BenchmarkDotNet.Diagnosers; +using BenchmarkDotNet.Environments; using BenchmarkDotNet.Jobs; namespace SixLabors.ImageSharp.Benchmarks @@ -19,10 +20,10 @@ namespace SixLabors.ImageSharp.Benchmarks public ShortClr() { this.Add( - Job.Clr.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), - Job.Core.WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3) + Job.Default.With(ClrRuntime.Net472).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3), + Job.Default.With(CoreRuntime.Core21).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3) ); } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index a57d388a9..cd8497ee4 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,4 +1,4 @@ - + @@ -19,6 +19,7 @@ + diff --git a/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs b/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs index 6e67d11ef..c2b9cdc19 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Diffuse.cs @@ -1,7 +1,6 @@ using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Dithering; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Benchmarks.Samplers diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs index e259d29d9..dd6b07f9a 100644 --- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs @@ -13,6 +13,7 @@ using SixLabors.Primitives; using Xunit; using SixLabors.ImageSharp.Processing.Processors.Drawing; using SixLabors.Shapes; +using SixLabors.ImageSharp.Advanced; namespace SixLabors.ImageSharp.Tests.Drawing { @@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing }; var processor = new FillRegionProcessor(options, brush.Object, region); var img = new Image(1, 1); - processor.Execute(img, bounds); + processor.Execute(img.GetConfiguration(), img, bounds); Assert.Equal(4, region.ScanInvocationCounter); } @@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var options = new GraphicsOptions { Antialias = true }; var processor = new FillRegionProcessor(options, brush.Object, new MockRegion1()); var img = new Image(10, 10); - processor.Execute(img, bounds); + processor.Execute(img.GetConfiguration(), img, bounds); } [Fact] diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 4f928e070..9c86d060a 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -6,6 +6,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -44,16 +45,19 @@ namespace SixLabors.ImageSharp.Tests Assert.Null(image.Metadata.ExifProfile); + const string expected = "Dirk Lemstra"; image.Metadata.ExifProfile = new ExifProfile(); - image.Metadata.ExifProfile.SetValue(ExifTag.Copyright, "Dirk Lemstra"); + image.Metadata.ExifProfile.SetValue(ExifTag.Copyright, expected); image = WriteAndRead(image, imageFormat); Assert.NotNull(image.Metadata.ExifProfile); - Assert.Equal(1, image.Metadata.ExifProfile.Values.Count()); + Assert.Equal(1, image.Metadata.ExifProfile.Values.Count); - ExifValue value = image.Metadata.ExifProfile.Values.FirstOrDefault(val => val.Tag == ExifTag.Copyright); - TestValue(value, "Dirk Lemstra"); + IExifValue value = image.Metadata.ExifProfile.GetValue(ExifTag.Copyright); + + Assert.NotNull(value); + Assert.Equal(expected, value.Value); } [Fact] @@ -100,9 +104,9 @@ namespace SixLabors.ImageSharp.Tests profile = image.Metadata.ExifProfile; Assert.NotNull(profile); - ExifValue value = profile.GetValue(ExifTag.ExposureTime); + IExifValue value = profile.GetValue(ExifTag.ExposureTime); Assert.NotNull(value); - Assert.NotEqual(exposureTime, ((Rational)value.Value).ToDouble()); + Assert.NotEqual(exposureTime, value.Value.ToDouble()); memStream.Position = 0; profile = GetExifProfile(); @@ -116,7 +120,9 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(profile); value = profile.GetValue(ExifTag.ExposureTime); - Assert.Equal(exposureTime, ((Rational)value.Value).ToDouble()); + Assert.Equal(exposureTime, value.Value.ToDouble()); + + image.Dispose(); } } @@ -129,7 +135,7 @@ namespace SixLabors.ImageSharp.Tests image.Metadata.ExifProfile.SetValue(ExifTag.ExposureBiasValue, new SignedRational(double.PositiveInfinity)); image = WriteAndReadJpeg(image); - ExifValue value = image.Metadata.ExifProfile.GetValue(ExifTag.ExposureBiasValue); + IExifValue value = image.Metadata.ExifProfile.GetValue(ExifTag.ExposureBiasValue); Assert.NotNull(value); Assert.Equal(new SignedRational(double.PositiveInfinity), value.Value); @@ -143,9 +149,9 @@ namespace SixLabors.ImageSharp.Tests image.Metadata.ExifProfile.SetValue(ExifTag.FlashEnergy, new Rational(double.NegativeInfinity)); image = WriteAndRead(image, imageFormat); - value = image.Metadata.ExifProfile.GetValue(ExifTag.FlashEnergy); - Assert.NotNull(value); - Assert.Equal(new Rational(double.PositiveInfinity), value.Value); + IExifValue value2 = image.Metadata.ExifProfile.GetValue(ExifTag.FlashEnergy); + Assert.NotNull(value2); + Assert.Equal(new Rational(double.PositiveInfinity), value2.Value); } [Theory] @@ -153,77 +159,84 @@ namespace SixLabors.ImageSharp.Tests [InlineData(TestImageWriteFormat.Png)] public void SetValue(TestImageWriteFormat imageFormat) { - var latitude = new Rational[] { new Rational(12.3), new Rational(4.56), new Rational(789.0) }; - Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image(); image.Metadata.ExifProfile.SetValue(ExifTag.Software, "ImageSharp"); - ExifValue value = image.Metadata.ExifProfile.GetValue(ExifTag.Software); - TestValue(value, "ImageSharp"); + IExifValue software = image.Metadata.ExifProfile.GetValue(ExifTag.Software); + Assert.Equal("ImageSharp", software.Value); - Assert.Throws(() => { value.WithValue(15); }); + // ExifString can set integer values. + Assert.True(software.TrySetValue(15)); + Assert.False(software.TrySetValue(15F)); image.Metadata.ExifProfile.SetValue(ExifTag.ShutterSpeedValue, new SignedRational(75.55)); - value = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); - - TestValue(value, new SignedRational(7555, 100)); + IExifValue shutterSpeed = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); - Assert.Throws(() => { value.WithValue(75); }); + Assert.Equal(new SignedRational(7555, 100), shutterSpeed.Value); + Assert.False(shutterSpeed.TrySetValue(75)); image.Metadata.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); // We also need to change this value because this overrides XResolution when the image is written. image.Metadata.HorizontalResolution = 150.0; - value = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); - TestValue(value, new Rational(150, 1)); + IExifValue xResolution = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); + Assert.Equal(new Rational(150, 1), xResolution.Value); - Assert.Throws(() => { value.WithValue("ImageSharp"); }); + Assert.False(xResolution.TrySetValue("ImageSharp")); image.Metadata.ExifProfile.SetValue(ExifTag.ReferenceBlackWhite, null); - value = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); - TestValue(value, (string)null); + IExifValue referenceBlackWhite = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); + Assert.Null(referenceBlackWhite.Value); - image.Metadata.ExifProfile.SetValue(ExifTag.GPSLatitude, latitude); + var expectedLatitude = new Rational[] { new Rational(12.3), new Rational(4.56), new Rational(789.0) }; + image.Metadata.ExifProfile.SetValue(ExifTag.GPSLatitude, expectedLatitude); - value = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); - TestValue(value, latitude); + IExifValue latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); + Assert.Equal(expectedLatitude, latitude.Value); + int profileCount = image.Metadata.ExifProfile.Values.Count; image = WriteAndRead(image, imageFormat); Assert.NotNull(image.Metadata.ExifProfile); - Assert.Equal(17, image.Metadata.ExifProfile.Values.Count()); - value = image.Metadata.ExifProfile.GetValue(ExifTag.Software); - TestValue(value, "ImageSharp"); + // Should be 3 less. + // 1 x due to setting of null "ReferenceBlackWhite" value. + // 2 x due to use of non-standard padding tag 0xEA1C listed in EXIF Tool. We can read those values but adhere + // strictly to the 2.3.1 specification when writing. (TODO: Support 2.3.2) + // https://exiftool.org/TagNames/EXIF.html + Assert.Equal(profileCount - 3, image.Metadata.ExifProfile.Values.Count); - value = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); - TestValue(value, new SignedRational(75.55)); + software = image.Metadata.ExifProfile.GetValue(ExifTag.Software); + Assert.Equal("15", software.Value); - value = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); - TestValue(value, new Rational(150.0)); + shutterSpeed = image.Metadata.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); + Assert.Equal(new SignedRational(75.55), shutterSpeed.Value); - value = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); - Assert.Null(value); + xResolution = image.Metadata.ExifProfile.GetValue(ExifTag.XResolution); + Assert.Equal(new Rational(150.0), xResolution.Value); - value = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); - TestValue(value, latitude); + referenceBlackWhite = image.Metadata.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); + Assert.Null(referenceBlackWhite); + + latitude = image.Metadata.ExifProfile.GetValue(ExifTag.GPSLatitude); + Assert.Equal(expectedLatitude, latitude.Value); image.Metadata.ExifProfile.Parts = ExifParts.ExifTags; image = WriteAndRead(image, imageFormat); Assert.NotNull(image.Metadata.ExifProfile); - Assert.Equal(8, image.Metadata.ExifProfile.Values.Count()); + Assert.Equal(8, image.Metadata.ExifProfile.Values.Count); Assert.NotNull(image.Metadata.ExifProfile.GetValue(ExifTag.ColorSpace)); Assert.True(image.Metadata.ExifProfile.RemoveValue(ExifTag.ColorSpace)); Assert.False(image.Metadata.ExifProfile.RemoveValue(ExifTag.ColorSpace)); Assert.Null(image.Metadata.ExifProfile.GetValue(ExifTag.ColorSpace)); - Assert.Equal(7, image.Metadata.ExifProfile.Values.Count()); + Assert.Equal(7, image.Metadata.ExifProfile.Values.Count); } [Fact] @@ -242,23 +255,23 @@ namespace SixLabors.ImageSharp.Tests metaData.HorizontalResolution = 100; - Assert.Equal(200, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(300, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + Assert.Equal(200, metaData.ExifProfile.GetValue(ExifTag.XResolution).Value.ToDouble()); + Assert.Equal(300, metaData.ExifProfile.GetValue(ExifTag.YResolution).Value.ToDouble()); exifProfile.Sync(metaData); - Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(300, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + Assert.Equal(100, (metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, (metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); metaData.VerticalResolution = 150; - Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(300, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + Assert.Equal(100, (metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, (metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); exifProfile.Sync(metaData); - Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(150, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + Assert.Equal(100, (metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(150, (metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); } [Fact] @@ -274,36 +287,42 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(170, thumbnail.Height); } - [Theory] - [InlineData(ExifTag.Software)] - [InlineData(ExifTag.Copyright)] - [InlineData(ExifTag.Model)] - [InlineData(ExifTag.ImageDescription)] - public void ReadWriteLargeProfileJpg(ExifTag exifValueToChange) + [Fact] + public void ReadWriteLargeProfileJpg() { - // arrange - var junk = new StringBuilder(); - for (int i = 0; i < 65600; i++) + ExifTag[] tags = new[] { ExifTag.Software, ExifTag.Copyright, ExifTag.Model, ExifTag.ImageDescription }; + foreach (ExifTag tag in tags) { - junk.Append("a"); - } - var image = new Image(100, 100); - ExifProfile expectedProfile = CreateExifProfile(); - var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList(); - expectedProfile.SetValue(exifValueToChange, junk.ToString()); - image.Metadata.ExifProfile = expectedProfile; + // Arrange + var junk = new StringBuilder(); + for (int i = 0; i < 65600; i++) + { + junk.Append("a"); + } - // act - Image reloadedImage = WriteAndRead(image, TestImageWriteFormat.Jpeg); + var image = new Image(100, 100); + ExifProfile expectedProfile = CreateExifProfile(); + var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList(); + expectedProfile.SetValue(tag, junk.ToString()); + image.Metadata.ExifProfile = expectedProfile; - // assert - ExifProfile actualProfile = reloadedImage.Metadata.ExifProfile; - Assert.NotNull(actualProfile); - foreach (ExifTag expectedProfileTag in expectedProfileTags) - { - ExifValue actualProfileValue = actualProfile.GetValue(expectedProfileTag); - ExifValue expectedProfileValue = expectedProfile.GetValue(expectedProfileTag); - Assert.Equal(expectedProfileValue.Value, actualProfileValue.Value); + // Act + Image reloadedImage = WriteAndRead(image, TestImageWriteFormat.Jpeg); + + // Assert + ExifProfile actualProfile = reloadedImage.Metadata.ExifProfile; + Assert.NotNull(actualProfile); + + foreach (ExifTag expectedProfileTag in expectedProfileTags) + { + IExifValue actualProfileValue = actualProfile.GetValueInternal(expectedProfileTag); + IExifValue expectedProfileValue = expectedProfile.GetValueInternal(expectedProfileTag); + Assert.Equal(expectedProfileValue.GetValue(), actualProfileValue.GetValue()); + } + + IExifValue expected = expectedProfile.GetValue(tag); + IExifValue actual = actualProfile.GetValue(tag); + Assert.Equal(expected, actual); } } @@ -312,7 +331,6 @@ namespace SixLabors.ImageSharp.Tests { // This image contains an 802 byte EXIF profile // It has a tag with an index offset of 18,481,152 bytes (overrunning the data) - Image image = TestFile.Create(TestImages.Jpeg.Progressive.Bad.ExifUndefType).CreateRgba32Image(); Assert.NotNull(image); @@ -323,7 +341,8 @@ namespace SixLabors.ImageSharp.Tests { if (value.DataType == ExifDataType.Undefined) { - Assert.Equal(4, value.NumberOfComponents); + Assert.True(value.IsArray); + Assert.Equal(4U, 4 * ExifDataTypes.GetSize(value.DataType)); } } } @@ -338,10 +357,10 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(profile); // Force parsing of the profile. - Assert.Equal(24, profile.Values.Count); + Assert.Equal(25, profile.Values.Count); byte[] bytes = profile.ToByteArray(); - Assert.Equal(489, bytes.Length); + Assert.Equal(525, bytes.Length); } [Theory] @@ -349,46 +368,45 @@ namespace SixLabors.ImageSharp.Tests [InlineData(TestImageWriteFormat.Png)] public void WritingImagePreservesExifProfile(TestImageWriteFormat imageFormat) { - // arrange + // Arrange var image = new Image(1, 1); - ExifProfile expected = CreateExifProfile(); - image.Metadata.ExifProfile = expected; + image.Metadata.ExifProfile = CreateExifProfile(); - // act + // Act Image reloadedImage = WriteAndRead(image, imageFormat); - // assert + // Assert ExifProfile actual = reloadedImage.Metadata.ExifProfile; Assert.NotNull(actual); foreach (KeyValuePair expectedProfileValue in TestProfileValues) { - ExifValue actualProfileValue = actual.GetValue(expectedProfileValue.Key); + IExifValue actualProfileValue = actual.GetValueInternal(expectedProfileValue.Key); Assert.NotNull(actualProfileValue); - Assert.Equal(expectedProfileValue.Value, actualProfileValue.Value); + Assert.Equal(expectedProfileValue.Value, actualProfileValue.GetValue()); } } [Fact] public void ProfileToByteArray() { - // arrange + // Arrange byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker; ExifProfile expectedProfile = CreateExifProfile(); var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList(); - // act + // Act byte[] actualBytes = expectedProfile.ToByteArray(); var actualProfile = new ExifProfile(actualBytes); - // assert + // Assert Assert.NotNull(actualBytes); Assert.NotEmpty(actualBytes); Assert.Equal(exifBytesWithoutExifCode, actualBytes.Take(exifBytesWithoutExifCode.Length).ToArray()); foreach (ExifTag expectedProfileTag in expectedProfileTags) { - ExifValue actualProfileValue = actualProfile.GetValue(expectedProfileTag); - ExifValue expectedProfileValue = expectedProfile.GetValue(expectedProfileTag); - Assert.Equal(expectedProfileValue.Value, actualProfileValue.Value); + IExifValue actualProfileValue = actualProfile.GetValueInternal(expectedProfileTag); + IExifValue expectedProfileValue = expectedProfile.GetValueInternal(expectedProfileTag); + Assert.Equal(expectedProfileValue.GetValue(), actualProfileValue.GetValue()); } } @@ -398,7 +416,7 @@ namespace SixLabors.ImageSharp.Tests foreach (KeyValuePair exifProfileValue in TestProfileValues) { - profile.SetValue(exifProfileValue.Key, exifProfileValue.Value); + profile.SetValueInternal(exifProfileValue.Key, exifProfileValue.Value); } return profile; @@ -423,7 +441,7 @@ namespace SixLabors.ImageSharp.Tests case TestImageWriteFormat.Png: return WriteAndReadPng(image); default: - throw new ArgumentException("unexpected test image format, only Jpeg and Png are allowed"); + throw new ArgumentException("Unexpected test image format, only Jpeg and Png are allowed"); } } @@ -455,65 +473,21 @@ namespace SixLabors.ImageSharp.Tests { Assert.NotNull(profile); - Assert.Equal(16, profile.Values.Count()); + Assert.Equal(16, profile.Values.Count); - foreach (ExifValue value in profile.Values) + foreach (IExifValue value in profile.Values) { - Assert.NotNull(value.Value); - - if (value.Tag == ExifTag.Software) - { - Assert.Equal("Windows Photo Editor 10.0.10011.16384", value.ToString()); - } - - if (value.Tag == ExifTag.XResolution) - { - Assert.Equal(new Rational(300.0), value.Value); - } - - if (value.Tag == ExifTag.PixelXDimension) - { - Assert.Equal(2338U, value.Value); - } + Assert.NotNull(value.GetValue()); } - } - - private static void TestValue(ExifValue value, string expected) - { - Assert.NotNull(value); - Assert.Equal(expected, value.Value); - } - - private static void TestValue(ExifValue value, Rational expected) - { - Assert.NotNull(value); - Assert.Equal(expected, value.Value); - } - - private static void TestValue(ExifValue value, SignedRational expected) - { - Assert.NotNull(value); - Assert.Equal(expected, value.Value); - } - private static void TestValue(ExifValue value, Rational[] expected) - { - Assert.NotNull(value); - - Assert.Equal(expected, (ICollection)value.Value); - } + IExifValue software = profile.GetValue(ExifTag.Software); + Assert.Equal("Windows Photo Editor 10.0.10011.16384", software.Value); - private static void TestValue(ExifValue value, double expected) - { - Assert.NotNull(value); - Assert.Equal(expected, value.Value); - } - - private static void TestValue(ExifValue value, double[] expected) - { - Assert.NotNull(value); + IExifValue xResolution = profile.GetValue(ExifTag.XResolution); + Assert.Equal(new Rational(300.0), xResolution.Value); - Assert.Equal(expected, (ICollection)value.Value); + IExifValue xDimension = profile.GetValue(ExifTag.PixelXDimension); + Assert.Equal(2338U, xDimension.Value); } } } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs index 19ff7d269..85c9231fa 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifReaderTests.cs @@ -1,6 +1,7 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using Xunit; @@ -12,9 +13,9 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Read_DataIsEmpty_ReturnsEmptyCollection() { - var reader = new ExifReader(new byte[] { }); + var reader = new ExifReader(Array.Empty()); - IList result = reader.ReadValues(); + IList result = reader.ReadValues(); Assert.Equal(0, result.Count); } @@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests { var reader = new ExifReader(new byte[] { 69, 120, 105, 102, 0, 0 }); - IList result = reader.ReadValues(); + IList result = reader.ReadValues(); Assert.Equal(0, result.Count); } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs index 144a6e4a3..a6ad8df8b 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -11,10 +11,10 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void TestExifTag() { - ExifProfile exifProfile = new ExifProfile(); + var exifProfile = new ExifProfile(); exifProfile.SetValue(ExifTag.ResolutionUnit, (ushort)1); - ExifValue value = exifProfile.GetValue(ExifTag.ResolutionUnit); + IExifValue value = exifProfile.GetValue(ExifTag.ResolutionUnit); Assert.Equal("None", value.ToString()); exifProfile.SetValue(ExifTag.ResolutionUnit, (ushort)2); @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests value = exifProfile.GetValue(ExifTag.ResolutionUnit); Assert.Equal("4", value.ToString()); - exifProfile.SetValue(ExifTag.ImageWidth, 123); + exifProfile.SetValue(ExifTag.ImageWidth, 123U); value = exifProfile.GetValue(ExifTag.ImageWidth); Assert.Equal("123", value.ToString()); } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs index 8d786811c..7f52fb6ca 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs @@ -1,7 +1,6 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Linq; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -10,40 +9,45 @@ namespace SixLabors.ImageSharp.Tests { public class ExifValueTests { - private static ExifValue GetExifValue() + private ExifProfile profile; + + public ExifValueTests() { - ExifProfile profile; using (Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image()) { - profile = image.Metadata.ExifProfile; + this.profile = image.Metadata.ExifProfile; } + } - Assert.NotNull(profile); + private IExifValue GetExifValue() + { + Assert.NotNull(this.profile); - return profile.Values.First(); + return this.profile.GetValue(ExifTag.Software); } [Fact] public void IEquatable() { - ExifValue first = GetExifValue(); - ExifValue second = GetExifValue(); + IExifValue first = this.GetExifValue(); + IExifValue second = this.GetExifValue(); Assert.True(first == second); Assert.True(first.Equals(second)); - Assert.True(first.Equals((object)second)); } [Fact] public void Properties() { - ExifValue value = GetExifValue(); + IExifValue value = this.GetExifValue(); Assert.Equal(ExifDataType.Ascii, value.DataType); - Assert.Equal(ExifTag.GPSDOP, value.Tag); + Assert.Equal(ExifTag.Software, value.Tag); Assert.False(value.IsArray); - Assert.Equal("Windows Photo Editor 10.0.10011.16384", value.ToString()); - Assert.Equal("Windows Photo Editor 10.0.10011.16384", value.Value); + + const string expected = "Windows Photo Editor 10.0.10011.16384"; + Assert.Equal(expected, value.ToString()); + Assert.Equal(expected, value.Value); } } } diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs new file mode 100644 index 000000000..d015fefc4 --- /dev/null +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/Values/ExifValuesTests.cs @@ -0,0 +1,553 @@ +using SixLabors.ImageSharp.Metadata.Profiles.Exif; +using SixLabors.ImageSharp.Primitives; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif.Values +{ + public class ExifValuesTests + { + public static TheoryData ByteTags => new TheoryData + { + { ExifTag.FaxProfile }, + { ExifTag.ModeNumber }, + { ExifTag.GPSAltitudeRef } + }; + + public static TheoryData ByteArrayTags => new TheoryData + { + { ExifTag.ClipPath }, + { ExifTag.VersionYear }, + { ExifTag.XMP }, + { ExifTag.CFAPattern2 }, + { ExifTag.TIFFEPStandardID }, + { ExifTag.XPTitle }, + { ExifTag.XPComment }, + { ExifTag.XPAuthor }, + { ExifTag.XPKeywords }, + { ExifTag.XPSubject }, + { ExifTag.GPSVersionID }, + }; + + public static TheoryData DoubleArrayTags => new TheoryData + { + { ExifTag.PixelScale }, + { ExifTag.IntergraphMatrix }, + { ExifTag.ModelTiePoint }, + { ExifTag.ModelTransform } + }; + + public static TheoryData LongTags => new TheoryData + { + { ExifTag.SubfileType }, + { ExifTag.SubIFDOffset }, + { ExifTag.GPSIFDOffset }, + { ExifTag.T4Options }, + { ExifTag.T6Options }, + { ExifTag.XClipPathUnits }, + { ExifTag.YClipPathUnits }, + { ExifTag.ProfileType }, + { ExifTag.CodingMethods }, + { ExifTag.T82ptions }, + { ExifTag.JPEGInterchangeFormat }, + { ExifTag.JPEGInterchangeFormatLength }, + { ExifTag.MDFileTag }, + { ExifTag.StandardOutputSensitivity }, + { ExifTag.RecommendedExposureIndex }, + { ExifTag.ISOSpeed }, + { ExifTag.ISOSpeedLatitudeyyy }, + { ExifTag.ISOSpeedLatitudezzz }, + { ExifTag.FaxRecvParams }, + { ExifTag.FaxRecvTime }, + { ExifTag.ImageNumber }, + }; + + public static TheoryData LongArrayTags => new TheoryData + { + { ExifTag.FreeOffsets }, + { ExifTag.FreeByteCounts }, + { ExifTag.ColorResponseUnit }, + { ExifTag.TileOffsets }, + { ExifTag.SMinSampleValue }, + { ExifTag.SMaxSampleValue }, + { ExifTag.JPEGQTables }, + { ExifTag.JPEGDCTables }, + { ExifTag.JPEGACTables }, + { ExifTag.StripRowCounts }, + { ExifTag.IntergraphRegisters }, + { ExifTag.TimeZoneOffset } + }; + + public static TheoryData NumberTags => new TheoryData + { + { ExifTag.ImageWidth }, + { ExifTag.ImageLength }, + { ExifTag.TileWidth }, + { ExifTag.TileLength }, + { ExifTag.BadFaxLines }, + { ExifTag.ConsecutiveBadFaxLines }, + { ExifTag.PixelXDimension }, + { ExifTag.PixelYDimension } + }; + + public static TheoryData NumberArrayTags => new TheoryData + { + { ExifTag.StripOffsets }, + { ExifTag.TileByteCounts }, + { ExifTag.ImageLayer } + }; + + public static TheoryData RationalTags => new TheoryData + { + { ExifTag.XPosition }, + { ExifTag.YPosition }, + { ExifTag.XResolution }, + { ExifTag.YResolution }, + { ExifTag.BatteryLevel }, + { ExifTag.ExposureTime }, + { ExifTag.FNumber }, + { ExifTag.MDScalePixel }, + { ExifTag.CompressedBitsPerPixel }, + { ExifTag.ApertureValue }, + { ExifTag.MaxApertureValue }, + { ExifTag.SubjectDistance }, + { ExifTag.FocalLength }, + { ExifTag.FlashEnergy2 }, + { ExifTag.FocalPlaneXResolution2 }, + { ExifTag.FocalPlaneYResolution2 }, + { ExifTag.ExposureIndex2 }, + { ExifTag.Humidity }, + { ExifTag.Pressure }, + { ExifTag.Acceleration }, + { ExifTag.FlashEnergy }, + { ExifTag.FocalPlaneXResolution }, + { ExifTag.FocalPlaneYResolution }, + { ExifTag.ExposureIndex }, + { ExifTag.DigitalZoomRatio }, + { ExifTag.LensInfo }, + { ExifTag.GPSAltitude }, + { ExifTag.GPSDOP }, + { ExifTag.GPSSpeed }, + { ExifTag.GPSTrack }, + { ExifTag.GPSImgDirection }, + { ExifTag.GPSDestBearing }, + { ExifTag.GPSDestDistance }, + }; + + public static TheoryData RationalArrayTags => new TheoryData + { + { ExifTag.WhitePoint }, + { ExifTag.PrimaryChromaticities }, + { ExifTag.YCbCrCoefficients }, + { ExifTag.ReferenceBlackWhite }, + { ExifTag.GPSLatitude }, + { ExifTag.GPSLongitude }, + { ExifTag.GPSTimestamp }, + { ExifTag.GPSDestLatitude }, + { ExifTag.GPSDestLongitude } + }; + + public static TheoryData ShortTags => new TheoryData + { + { ExifTag.OldSubfileType }, + { ExifTag.Compression }, + { ExifTag.PhotometricInterpretation }, + { ExifTag.Thresholding }, + { ExifTag.CellWidth }, + { ExifTag.CellLength }, + { ExifTag.FillOrder }, + { ExifTag.Orientation }, + { ExifTag.SamplesPerPixel }, + { ExifTag.PlanarConfiguration }, + { ExifTag.GrayResponseUnit }, + { ExifTag.ResolutionUnit }, + { ExifTag.CleanFaxData }, + { ExifTag.InkSet }, + { ExifTag.NumberOfInks }, + { ExifTag.DotRange }, + { ExifTag.Indexed }, + { ExifTag.OPIProxy }, + { ExifTag.JPEGProc }, + { ExifTag.JPEGRestartInterval }, + { ExifTag.YCbCrPositioning }, + { ExifTag.Rating }, + { ExifTag.RatingPercent }, + { ExifTag.ExposureProgram }, + { ExifTag.Interlace }, + { ExifTag.SelfTimerMode }, + { ExifTag.SensitivityType }, + { ExifTag.MeteringMode }, + { ExifTag.LightSource }, + { ExifTag.FocalPlaneResolutionUnit2 }, + { ExifTag.SensingMethod2 }, + { ExifTag.Flash }, + { ExifTag.ColorSpace }, + { ExifTag.FocalPlaneResolutionUnit }, + { ExifTag.SensingMethod }, + { ExifTag.CustomRendered }, + { ExifTag.ExposureMode }, + { ExifTag.WhiteBalance }, + { ExifTag.FocalLengthIn35mmFilm }, + { ExifTag.SceneCaptureType }, + { ExifTag.GainControl }, + { ExifTag.Contrast }, + { ExifTag.Saturation }, + { ExifTag.Sharpness }, + { ExifTag.SubjectDistanceRange }, + { ExifTag.GPSDifferential } + }; + + public static TheoryData ShortArrayTags => new TheoryData + { + { ExifTag.BitsPerSample }, + { ExifTag.MinSampleValue }, + { ExifTag.MaxSampleValue }, + { ExifTag.GrayResponseCurve }, + { ExifTag.ColorMap }, + { ExifTag.ExtraSamples }, + { ExifTag.PageNumber }, + { ExifTag.TransferFunction }, + { ExifTag.Predictor }, + { ExifTag.HalftoneHints }, + { ExifTag.SampleFormat }, + { ExifTag.TransferRange }, + { ExifTag.DefaultImageColor }, + { ExifTag.JPEGLosslessPredictors }, + { ExifTag.JPEGPointTransforms }, + { ExifTag.YCbCrSubsampling }, + { ExifTag.CFARepeatPatternDim }, + { ExifTag.IntergraphPacketData }, + { ExifTag.ISOSpeedRatings }, + { ExifTag.SubjectArea }, + { ExifTag.SubjectLocation } + }; + + public static TheoryData SignedRationalTags => new TheoryData + { + { ExifTag.ShutterSpeedValue }, + { ExifTag.BrightnessValue }, + { ExifTag.ExposureBiasValue }, + { ExifTag.AmbientTemperature }, + { ExifTag.WaterDepth }, + { ExifTag.CameraElevationAngle } + }; + + public static TheoryData SignedRationalArrayTags => new TheoryData + { + { ExifTag.Decode } + }; + + public static TheoryData StringTags => new TheoryData + { + { ExifTag.ImageDescription }, + { ExifTag.Make }, + { ExifTag.Model }, + { ExifTag.Software }, + { ExifTag.DateTime }, + { ExifTag.Artist }, + { ExifTag.HostComputer }, + { ExifTag.Copyright }, + { ExifTag.DocumentName }, + { ExifTag.PageName }, + { ExifTag.InkNames }, + { ExifTag.TargetPrinter }, + { ExifTag.ImageID }, + { ExifTag.MDLabName }, + { ExifTag.MDSampleInfo }, + { ExifTag.MDPrepDate }, + { ExifTag.MDPrepTime }, + { ExifTag.MDFileUnits }, + { ExifTag.SEMInfo }, + { ExifTag.SpectralSensitivity }, + { ExifTag.DateTimeOriginal }, + { ExifTag.DateTimeDigitized }, + { ExifTag.SubsecTime }, + { ExifTag.SubsecTimeOriginal }, + { ExifTag.SubsecTimeDigitized }, + { ExifTag.RelatedSoundFile }, + { ExifTag.FaxSubaddress }, + { ExifTag.OffsetTime }, + { ExifTag.OffsetTimeOriginal }, + { ExifTag.OffsetTimeDigitized }, + { ExifTag.SecurityClassification }, + { ExifTag.ImageHistory }, + { ExifTag.ImageUniqueID }, + { ExifTag.OwnerName }, + { ExifTag.SerialNumber }, + { ExifTag.LensMake }, + { ExifTag.LensModel }, + { ExifTag.LensSerialNumber }, + { ExifTag.GDALMetadata }, + { ExifTag.GDALNoData }, + { ExifTag.GPSLatitudeRef }, + { ExifTag.GPSLongitudeRef }, + { ExifTag.GPSSatellites }, + { ExifTag.GPSStatus }, + { ExifTag.GPSMeasureMode }, + { ExifTag.GPSSpeedRef }, + { ExifTag.GPSTrackRef }, + { ExifTag.GPSImgDirectionRef }, + { ExifTag.GPSMapDatum }, + { ExifTag.GPSDestLatitudeRef }, + { ExifTag.GPSDestLongitudeRef }, + { ExifTag.GPSDestBearingRef }, + { ExifTag.GPSDestDistanceRef }, + { ExifTag.GPSDateStamp } + }; + + public static TheoryData UndefinedTags => new TheoryData + { + { ExifTag.FileSource }, + { ExifTag.SceneType } + }; + + public static TheoryData UndefinedArrayTags => new TheoryData + { + { ExifTag.JPEGTables }, + { ExifTag.OECF }, + { ExifTag.ExifVersion }, + { ExifTag.ComponentsConfiguration }, + { ExifTag.MakerNote }, + { ExifTag.UserComment }, + { ExifTag.FlashpixVersion }, + { ExifTag.SpatialFrequencyResponse }, + { ExifTag.SpatialFrequencyResponse2 }, + { ExifTag.Noise }, + { ExifTag.CFAPattern }, + { ExifTag.DeviceSettingDescription }, + { ExifTag.ImageSourceData }, + { ExifTag.GPSProcessingMethod }, + { ExifTag.GPSAreaInformation } + }; + + [Theory] + [MemberData(nameof(ByteTags))] + public void ExifByteTests(ExifTag tag) + { + const byte expected = byte.MaxValue; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue((int)expected)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifByte)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(ByteArrayTags))] + public void ExifByteArrayTests(ExifTag tag) + { + byte[] expected = new[] { byte.MaxValue }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifByteArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(DoubleArrayTags))] + public void ExifDoubleArrayTests(ExifTag tag) + { + double[] expected = new[] { double.MaxValue }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifDoubleArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(LongTags))] + public void ExifLongTests(ExifTag tag) + { + const uint expected = uint.MaxValue; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifLong)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(LongArrayTags))] + public void ExifLongArrayTests(ExifTag tag) + { + uint[] expected = new[] { uint.MaxValue }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifLongArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(NumberTags))] + public void ExifNumberTests(ExifTag tag) + { + Number expected = ushort.MaxValue; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue((uint)expected)); + Assert.True(value.TrySetValue((int)expected)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifNumber)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(NumberArrayTags))] + public void ExifNumberArrayTests(ExifTag tag) + { + Number[] expected = new[] { new Number(uint.MaxValue) }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifNumberArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(RationalTags))] + public void ExifRationalTests(ExifTag tag) + { + var expected = new Rational(21, 42); + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(new SignedRational(expected.ToDouble()))); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifRational)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(RationalArrayTags))] + public void ExifRationalArrayTests(ExifTag tag) + { + Rational[] expected = new[] { new Rational(21, 42) }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifRationalArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(ShortTags))] + public void ExifShortTests(ExifTag tag) + { + const ushort expected = (ushort)short.MaxValue; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue((int)expected)); + Assert.True(value.TrySetValue((short)expected)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifShort)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(ShortArrayTags))] + public void ExifShortArrayTests(ExifTag tag) + { + ushort[] expected = new[] { ushort.MaxValue }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifShortArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(SignedRationalTags))] + public void ExifSignedRationalTests(ExifTag tag) + { + var expected = new SignedRational(21, 42); + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifSignedRational)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(SignedRationalArrayTags))] + public void ExifSignedRationalArrayTests(ExifTag tag) + { + SignedRational[] expected = new[] { new SignedRational(21, 42) }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifSignedRationalArray)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(StringTags))] + public void ExifStringTests(ExifTag tag) + { + const string expected = "ImageSharp"; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(0M)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifString)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(UndefinedTags))] + public void ExifUndefinedTests(ExifTag tag) + { + const byte expected = byte.MaxValue; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue((int)expected)); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifByte)value; + Assert.Equal(expected, typed.Value); + } + + [Theory] + [MemberData(nameof(UndefinedArrayTags))] + public void ExifUndefinedArrayTests(ExifTag tag) + { + byte[] expected = new[] { byte.MaxValue }; + ExifValue value = ExifValues.Create(tag); + + Assert.False(value.TrySetValue(expected.ToString())); + Assert.True(value.TrySetValue(expected)); + + var typed = (ExifByteArray)value; + Assert.Equal(expected, typed.Value); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs index cfac8645f..e97978198 100644 --- a/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/Processing/BaseImageOperationsExtensionTest.cs @@ -1,6 +1,7 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.Primitives; @@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Processing this.options = new GraphicsOptions { Antialias = false }; this.source = new Image(91 + 324, 123 + 56); this.rect = new Rectangle(91, 123, 324, 56); // make this random? - this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source, false); + this.internalOperations = new FakeImageOperationsProvider.FakeImageOperations(this.source.GetConfiguration(), this.source, false); this.operations = this.internalOperations; } @@ -38,7 +39,7 @@ namespace SixLabors.ImageSharp.Tests.Processing { return Assert.IsType(operation.NonGenericProcessor); } - + return Assert.IsType(operation.GenericProcessor); } @@ -49,12 +50,12 @@ namespace SixLabors.ImageSharp.Tests.Processing FakeImageOperationsProvider.FakeImageOperations.AppliedOperation operation = this.internalOperations.Applied[index]; Assert.Equal(rect, operation.Rectangle); - + if (operation.NonGenericProcessor != null) { return Assert.IsType(operation.NonGenericProcessor); } - + return Assert.IsType(operation.GenericProcessor); } } diff --git a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs index c5d18cbb2..53a50468b 100644 --- a/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs +++ b/tests/ImageSharp.Tests/Processing/Dithering/DitherTest.cs @@ -4,7 +4,6 @@ using System; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Dithering; using SixLabors.ImageSharp.Processing.Processors.Dithering; using Xunit; diff --git a/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs b/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs index 38d53c7b6..aecac22c0 100644 --- a/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs +++ b/tests/ImageSharp.Tests/Processing/FakeImageOperationsProvider.cs @@ -3,12 +3,9 @@ using System.Collections.Generic; using System.Linq; - -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Tests.Processing @@ -28,15 +25,17 @@ namespace SixLabors.ImageSharp.Tests.Processing .Where(x => x.Source == source); } - public IEnumerable.AppliedOperation> AppliedOperations(Image source) where TPixel : struct, IPixel + public IEnumerable.AppliedOperation> AppliedOperations(Image source) + where TPixel : struct, IPixel { return this.Created(source) .SelectMany(x => x.Applied); } - public IInternalImageProcessingContext CreateImageProcessingContext(Image source, bool mutate) where TPixel : struct, IPixel + public IInternalImageProcessingContext CreateImageProcessingContext(Configuration configuration, Image source, bool mutate) + where TPixel : struct, IPixel { - var op = new FakeImageOperations(source, mutate); + var op = new FakeImageOperations(configuration, source, mutate); this.ImageOperators.Add(op); return op; } @@ -44,11 +43,9 @@ namespace SixLabors.ImageSharp.Tests.Processing public class FakeImageOperations : IInternalImageProcessingContext where TPixel : struct, IPixel { - private bool mutate; - - public FakeImageOperations(Image source, bool mutate) + public FakeImageOperations(Configuration configuration, Image source, bool mutate) { - this.mutate = mutate; + this.Configuration = configuration; this.Source = mutate ? source : source?.Clone(); } @@ -56,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Processing public List Applied { get; } = new List(); - public MemoryAllocator MemoryAllocator => this.Source.GetConfiguration().MemoryAllocator; + public Configuration Configuration { get; } public Image GetResultImage() { @@ -71,19 +68,19 @@ namespace SixLabors.ImageSharp.Tests.Processing public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle) { this.Applied.Add(new AppliedOperation - { - Rectangle = rectangle, - NonGenericProcessor = processor - }); + { + Rectangle = rectangle, + NonGenericProcessor = processor + }); return this; } public IImageProcessingContext ApplyProcessor(IImageProcessor processor) { this.Applied.Add(new AppliedOperation - { - NonGenericProcessor = processor - }); + { + NonGenericProcessor = processor + }); return this; } diff --git a/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs b/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs index 1b5c16538..86a0d1485 100644 --- a/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs +++ b/tests/ImageSharp.Tests/Processing/ImageOperationTests.cs @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.Tests.Processing [Fact] public void ApplyProcessors_ListOfProcessors_AppliesAllProcessorsToOperation() { - var operations = new FakeImageOperationsProvider.FakeImageOperations(null, false); + var operations = new FakeImageOperationsProvider.FakeImageOperations(Configuration.Default, null, false); operations.ApplyProcessors(this.processorDefinition); Assert.Contains(this.processorDefinition, operations.Applied.Select(x => x.NonGenericProcessor)); } diff --git a/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs b/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs index 9d16583cd..6c2a142af 100644 --- a/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs +++ b/tests/ImageSharp.Tests/Processing/ImageProcessingContextTests.cs @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.Tests.Processing } this.processorDefinition - .Setup(p => p.CreatePixelSpecificProcessor(It.IsAny>(), It.IsAny())) + .Setup(p => p.CreatePixelSpecificProcessor(Configuration.Default, It.IsAny>(), It.IsAny())) .Returns(this.regularProcessorImpl.Object); } @@ -189,11 +189,11 @@ namespace SixLabors.ImageSharp.Tests.Processing } this.cloningProcessorDefinition - .Setup(p => p.CreatePixelSpecificCloningProcessor(It.IsAny>(), It.IsAny())) + .Setup(p => p.CreatePixelSpecificCloningProcessor(Configuration.Default, It.IsAny>(), It.IsAny())) .Returns(this.cloningProcessorImpl.Object); this.cloningProcessorDefinition - .Setup(p => p.CreatePixelSpecificProcessor(It.IsAny>(), It.IsAny())) + .Setup(p => p.CreatePixelSpecificProcessor(Configuration.Default, It.IsAny>(), It.IsAny())) .Returns(this.cloningProcessorImpl.Object); } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs index 6bd8c9b2f..cf97ae4af 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text.RegularExpressions; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing; @@ -58,8 +58,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution // Make sure the kernel components are the same using (var image = new Image(1, 1)) { + Configuration configuration = image.GetConfiguration(); var definition = new BokehBlurProcessor(10, BokehBlurProcessor.DefaultComponents, BokehBlurProcessor.DefaultGamma); - using (var processor = (BokehBlurProcessor)definition.CreatePixelSpecificProcessor(image, image.Bounds())) + using (var processor = (BokehBlurProcessor)definition.CreatePixelSpecificProcessor(configuration, image, image.Bounds())) { Assert.Equal(components.Count, processor.Kernels.Count); foreach ((Complex64[] a, Complex64[] b) in components.Zip(processor.Kernels, (a, b) => (a, b))) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs index 5417bc1f3..5d65a9e61 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Dithering/DitherTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Dithering; using SixLabors.ImageSharp.Processing.Processors.Dithering; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -149,4 +148,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Binarization appendPixelTypeToFileName: false); } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs new file mode 100644 index 000000000..c18f04385 --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Effects/PixelShaderTest.cs @@ -0,0 +1,113 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Effects +{ + [GroupOutput("Effects")] + public class PixelShaderTest + { + [Theory] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32)] + public void FullImage(TestImageProvider provider) + where TPixel : struct, IPixel + { + provider.RunValidatingProcessorTest( + x => x.ApplyPixelShaderProcessor( + span => + { + for (int i = 0; i < span.Length; i++) + { + Vector4 v4 = span[i]; + float avg = (v4.X + v4.Y + v4.Z) / 3f; + span[i] = new Vector4(avg); + } + }), + appendPixelTypeToFileName: false); + } + + [Theory] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32)] + public void InBox(TestImageProvider provider) + where TPixel : struct, IPixel + { + provider.RunRectangleConstrainedValidatingProcessorTest( + (x, rect) => x.ApplyPixelShaderProcessor( + span => + { + for (int i = 0; i < span.Length; i++) + { + Vector4 v4 = span[i]; + float avg = (v4.X + v4.Y + v4.Z) / 3f; + span[i] = new Vector4(avg); + } + }, rect)); + } + + [Theory] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32)] + public void PositionAwareFullImage(TestImageProvider provider) + where TPixel : struct, IPixel + { + provider.RunValidatingProcessorTest( + c => c.ApplyPixelShaderProcessor( + (span, offset) => + { + int y = offset.Y; + int x = offset.X; + for (int i = 0; i < span.Length; i++) + { + float + sine = MathF.Sin(y), + cosine = MathF.Cos(x + i), + sum = sine + cosine, + abs = MathF.Abs(sum), + a = 0.5f + (abs / 2); // Max value for sin(y) + cos(x) is 2 + + Vector4 v4 = span[i]; + float avg = (v4.X + v4.Y + v4.Z) / 3f; + var gray = new Vector4(avg, avg, avg, a); + + span[i] = Vector4.Clamp(gray, Vector4.Zero, Vector4.One); + } + }), + appendPixelTypeToFileName: false); + } + + [Theory] + [WithFile(TestImages.Png.CalliphoraPartial, PixelTypes.Rgba32)] + public void PositionAwareInBox(TestImageProvider provider) + where TPixel : struct, IPixel + { + provider.RunRectangleConstrainedValidatingProcessorTest( + (c, rect) => c.ApplyPixelShaderProcessor( + (span, offset) => + { + int y = offset.Y; + int x = offset.X; + for (int i = 0; i < span.Length; i++) + { + float + sine = MathF.Sin(y), + cosine = MathF.Cos(x + i), + sum = sine + cosine, + abs = MathF.Abs(sum), + a = 0.5f + (abs / 2); + + Vector4 v4 = span[i]; + float avg = (v4.X + v4.Y + v4.Z) / 3f; + var gray = new Vector4(avg, avg, avg, a); + + span[i] = Vector4.Clamp(gray, Vector4.Zero, Vector4.One); + } + }, rect)); + } + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 6171c3c69..c683a51dc 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -58,9 +58,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - [Theory( - Skip = "Debug only, enable manually" - )] + [Theory(Skip = "Debug only, enable manually")] [WithTestPatternImages(4000, 4000, PixelTypes.Rgba32, 300, 1024)] [WithTestPatternImages(3032, 3032, PixelTypes.Rgba32, 400, 1024)] [WithTestPatternImages(3032, 3032, PixelTypes.Rgba32, 400, 128)] @@ -560,5 +558,25 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms image.CompareToReferenceOutput(ValidatorComparer, provider); } } + + [Theory] + [WithFile(TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, DefaultPixelType)] + [WithFile(TestImages.Jpeg.Issues.ExifGetString750Transform, DefaultPixelType)] + [WithFile(TestImages.Jpeg.Issues.ExifResize1049, DefaultPixelType)] + public void CanResizeExifIssueImages(TestImageProvider provider) + where TPixel : struct, IPixel + { + // Test images are large so skip on 32bit for now. + if (!TestEnvironment.Is64BitProcess) + { + return; + } + + using (Image image = provider.GetImage()) + { + // Don't bother saving, we're testing the EXIF metadata updates. + image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2)); + } + } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs index 19226b307..9f8034fa3 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -19,8 +19,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { var profile = new ExifProfile(); img.Metadata.ExifProfile = profile; - profile.SetValue(ExifTag.PixelXDimension, (uint)xy); - profile.SetValue(ExifTag.PixelYDimension, (uint)xy); + profile.SetValue(ExifTag.PixelXDimension, xy + ushort.MaxValue); + profile.SetValue(ExifTag.PixelYDimension, xy + ushort.MaxValue); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelYDimension).DataType); @@ -32,4 +32,4 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms } } } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8389d8535..ada077496 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -191,6 +191,7 @@ namespace SixLabors.ImageSharp.Tests public const string IncorrectQuality845 = "Jpg/issues/Issue845-Incorrect-Quality99.jpg"; public const string IncorrectColorspace855 = "Jpg/issues/issue855-incorrect-colorspace.jpg"; public const string IncorrectResize1006 = "Jpg/issues/issue1006-incorrect-resize.jpg"; + public const string ExifResize1049 = "Jpg/issues/issue1049-exif-resize.jpg"; public static class Fuzz { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 9da39fbe4..f2bb7bdee 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -678,16 +678,16 @@ namespace SixLabors.ImageSharp.Tests private class MakeOpaqueProcessor : IImageProcessor { - public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) + public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - => new MakeOpaqueProcessor(source, sourceRectangle); + => new MakeOpaqueProcessor(configuration, source, sourceRectangle); } private class MakeOpaqueProcessor : ImageProcessor where TPixel : struct, IPixel { - public MakeOpaqueProcessor(Image source, Rectangle sourceRectangle) - : base(source, sourceRectangle) + public MakeOpaqueProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) + : base(configuration, source, sourceRectangle) { } diff --git a/tests/Images/External b/tests/Images/External index d7c099ceb..d8ea82085 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit d7c099cebd58f1d3ff997383351d52d28a29df3d +Subproject commit d8ea82085ac39a6aa6ca8e0806a9518d3a7d3337 diff --git a/tests/Images/Input/Jpg/issues/issue1049-exif-resize.jpg b/tests/Images/Input/Jpg/issues/issue1049-exif-resize.jpg new file mode 100644 index 000000000..b3abb7d2f --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue1049-exif-resize.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f313e48c5b9d4d1af2df44057970f03ddafc809862d14e8593f3e1fc0aef2c1 +size 718443