Browse Source

Merge branch 'master' into sw/github-actions

af/merge-core
James Jackson-South 6 years ago
parent
commit
a5f91eaabe
  1. 7
      Directory.Build.targets
  2. 1
      README.md
  3. 9
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
  4. 4
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
  5. 6
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
  6. 7
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs
  7. 6
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
  8. 4
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs
  9. 6
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
  10. 4
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs
  11. 8
      src/ImageSharp/Advanced/AotCompilerTools.cs
  12. 50
      src/ImageSharp/Common/Helpers/EnumUtils.cs
  13. 6
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  14. 4
      src/ImageSharp/Common/Helpers/TolerantMath.cs
  15. 9
      src/ImageSharp/Common/Helpers/UnitConverter.cs
  16. 2
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  17. 6
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  18. 0
      src/ImageSharp/Formats/Bmp/BmpMetadata.cs
  19. 21
      src/ImageSharp/Formats/Bmp/MetadataExtensions.cs
  20. 4
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  21. 6
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  22. 0
      src/ImageSharp/Formats/Gif/GifFrameMetadata.cs
  23. 0
      src/ImageSharp/Formats/Gif/GifMetadata.cs
  24. 28
      src/ImageSharp/Formats/Gif/MetadataExtensions.cs
  25. 7
      src/ImageSharp/Formats/IImageDecoder.cs
  26. 11
      src/ImageSharp/Formats/Jpeg/JpegDecoder.cs
  27. 78
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  28. 12
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  29. 0
      src/ImageSharp/Formats/Jpeg/JpegMetadata.cs
  30. 21
      src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs
  31. 21
      src/ImageSharp/Formats/Png/MetadataExtensions.cs
  32. 16
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  33. 30
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  34. 8
      src/ImageSharp/Formats/Png/PngMetadata.cs
  35. 111
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
  36. 21
      src/ImageSharp/Formats/Tga/MetadataExtensions.cs
  37. 10
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  38. 4
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  39. 44
      src/ImageSharp/Image.FromBytes.cs
  40. 22
      src/ImageSharp/Image.FromFile.cs
  41. 6
      src/ImageSharp/Image.FromStream.cs
  42. 4
      src/ImageSharp/ImageFrameCollection.cs
  43. 43
      src/ImageSharp/ImageSharp.csproj
  44. 18
      src/ImageSharp/Image{TPixel}.cs
  45. 281
      src/ImageSharp/MetaData/Profiles/Exif/ExifTags.cs
  46. 721
      src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs
  47. 3
      src/ImageSharp/MetaData/Profiles/Exif/README.md
  48. 0
      src/ImageSharp/Metadata/FrameDecodingMode.cs
  49. 0
      src/ImageSharp/Metadata/ImageFrameMetadata.cs
  50. 0
      src/ImageSharp/Metadata/ImageMetadata.cs
  51. 0
      src/ImageSharp/Metadata/PixelResolutionUnit.cs
  52. BIN
      src/ImageSharp/Metadata/Profiles/Exif/DC-008-Translation-2019-E.pdf
  53. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs
  54. 12
      src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs
  55. 45
      src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs
  56. 8
      src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs
  57. 130
      src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs
  58. 112
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  59. 7
      src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs
  60. 275
      src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs
  61. 238
      src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
  62. 3
      src/ImageSharp/Metadata/Profiles/Exif/README.md
  63. 24
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Byte.cs
  64. 64
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ByteArray.cs
  65. 29
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.DoubleArray.cs
  66. 114
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Long.cs
  67. 69
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs
  68. 51
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Number.cs
  69. 26
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.NumberArray.cs
  70. 176
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Rational.cs
  71. 56
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.RationalArray.cs
  72. 239
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Short.cs
  73. 114
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.ShortArray.cs
  74. 41
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRational.cs
  75. 16
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.SignedRationalArray.cs
  76. 279
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.String.cs
  77. 94
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.Undefined.cs
  78. 70
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.cs
  79. 11
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTagValue.cs
  80. 17
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag{TValueType}.cs
  81. 13
      src/ImageSharp/Metadata/Profiles/Exif/Tags/UnkownExifTag.cs
  82. 55
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifArrayValue{TValueType}.cs
  83. 47
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByte.cs
  84. 66
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifByteArray.cs
  85. 48
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDouble.cs
  86. 27
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifDoubleArray.cs
  87. 43
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloat.cs
  88. 22
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifFloatArray.cs
  89. 53
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong.cs
  90. 27
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLongArray.cs
  91. 74
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumber.cs
  92. 43
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs
  93. 54
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRational.cs
  94. 73
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifRationalArray.cs
  95. 61
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShort.cs
  96. 105
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifShortArray.cs
  97. 48
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByte.cs
  98. 22
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedByteArray.cs
  99. 26
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong.cs
  100. 22
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLongArray.cs

7
Directory.Build.targets

@ -22,18 +22,19 @@
<!-- Package versions for package references across all projects -->
<ItemGroup>
<PackageReference Update="BenchmarkDotNet" Version="0.11.5" />
<PackageReference Update="Colourful" Version="2.0.2" />
<PackageReference Update="BenchmarkDotNet" Version="0.12.0" />
<PackageReference Update="Colourful" Version="2.0.3" />
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="7.14.4" />
<PackageReference Update="Microsoft.Net.Compilers.Toolset" Version="3.3.1" />
<PackageReference Update="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Update="Moq" Version="4.10.0" />
<PackageReference Update="Pfim" Version="0.9.1" />
<PackageReference Update="SixLabors.Core" Version="1.0.0-beta0008" />
<PackageReference Update="SixLabors.Fonts" Version="1.0.0-beta0009" />
<PackageReference Update="SixLabors.Shapes" Version="1.0.0-beta0009" />
<PackageReference Update="SixLabors.Shapes.Text" Version="1.0.0-beta0009" />
<PackageReference Update="StyleCop.Analyzers" Version="1.1.118" />
<PackageReference Update="System.Drawing.Common" Version="4.5.1" />
<PackageReference Update="System.Drawing.Common" Version="4.7.0" />
<PackageReference Update="System.IO.Compression" Version="4.3.0" />
<PackageReference Update="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
<PackageReference Update="System.Runtime.CompilerServices.Unsafe" Version="4.5.1" />

1
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

9
src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs

@ -60,10 +60,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public float Opacity { get; }
/// <inheritdoc />
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Image<TPixelBg> source, Rectangle sourceRectangle)
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Configuration configuration, Image<TPixelBg> source, Rectangle sourceRectangle)
where TPixelBg : struct, IPixel<TPixelBg>
{
var visitor = new ProcessorFactoryVisitor<TPixelBg>(this, source, sourceRectangle);
var visitor = new ProcessorFactoryVisitor<TPixelBg>(configuration, this, source, sourceRectangle);
this.Image.AcceptVisitor(visitor);
return visitor.Result;
}
@ -71,12 +71,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
private class ProcessorFactoryVisitor<TPixelBg> : IImageVisitor
where TPixelBg : struct, IPixel<TPixelBg>
{
private readonly Configuration configuration;
private readonly DrawImageProcessor definition;
private readonly Image<TPixelBg> source;
private readonly Rectangle sourceRectangle;
public ProcessorFactoryVisitor(DrawImageProcessor definition, Image<TPixelBg> source, Rectangle sourceRectangle)
public ProcessorFactoryVisitor(Configuration configuration, DrawImageProcessor definition, Image<TPixelBg> 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<TPixelFg>
{
this.Result = new DrawImageProcessor<TPixelBg, TPixelFg>(
this.configuration,
image,
this.source,
this.sourceRectangle,

4
src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

@ -22,6 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelBg, TPixelFg}"/> class.
/// </summary>
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
/// <param name="image">The foreground <see cref="Image{TPixelFg}"/> to blend with the currently processing image.</param>
/// <param name="source">The source <see cref="Image{TPixelBg}"/> for the current processor instance.</param>
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
@ -30,6 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(
Configuration configuration,
Image<TPixelFg> image,
Image<TPixelBg> 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));

6
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs

@ -34,10 +34,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public GraphicsOptions Options { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new FillProcessor<TPixel>(this, source, sourceRectangle);
}
=> new FillProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

7
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<TPixel> source, Rectangle sourceRectangle)
: base(source, sourceRectangle)
public FillProcessor(Configuration configuration, FillProcessor definition, Image<TPixel> 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;
}

6
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs

@ -42,10 +42,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
public GraphicsOptions Options { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new FillRegionProcessor<TPixel>(this, source, sourceRectangle);
}
=> new FillRegionProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

4
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<TPixel> source, Rectangle sourceRectangle)
: base(source, sourceRectangle)
public FillRegionProcessor(Configuration configuration, FillRegionProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}

6
src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs

@ -72,10 +72,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
public PointF Location { get; }
/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Configuration configuration, Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new DrawTextProcessor<TPixel>(this, source, sourceRectangle);
}
=> new DrawTextProcessor<TPixel>(configuration, this, source, sourceRectangle);
}
}

4
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<TPixel> source, Rectangle sourceRectangle)
: base(source, sourceRectangle)
public DrawTextProcessor(Configuration configuration, DrawTextProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
this.definition = definition;
}

8
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Advanced
/// </summary>
private static void SeedEverything()
{
Seed<Alpha8>();
Seed<A8>();
Seed<Argb32>();
Seed<Bgr24>();
Seed<Bgr565>();
@ -48,8 +48,10 @@ namespace SixLabors.ImageSharp.Advanced
Seed<Bgra4444>();
Seed<Bgra5551>();
Seed<Byte4>();
Seed<Gray16>();
Seed<Gray8>();
Seed<L16>();
Seed<L8>();
Seed<La16>();
Seed<La32>();
Seed<HalfSingle>();
Seed<HalfVector2>();
Seed<HalfVector4>();

50
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
{
/// <summary>
/// Common utility methods for working with enums.
/// </summary>
internal static class EnumUtils
{
/// <summary>
/// Converts the numeric representation of the enumerated constants to an equivalent enumerated object.
/// </summary>
/// <typeparam name="TEnum">The type of enum </typeparam>
/// <param name="value">The value to parse</param>
/// <param name="defaultValue">The default value to return.</param>
/// <returns>The <typeparamref name="TEnum"/>.</returns>
public static TEnum Parse<TEnum>(int value, TEnum defaultValue)
where TEnum : Enum
{
foreach (TEnum enumValue in Enum.GetValues(typeof(TEnum)))
{
TEnum current = enumValue;
if (value == Unsafe.As<TEnum, int>(ref current))
{
return enumValue;
}
}
return defaultValue;
}
/// <summary>
/// Returns a value indicating whether the given enum has a flag of the given value.
/// </summary>
/// <typeparam name="TEnum">The type of enum.</typeparam>
/// <param name="value">The value.</param>
/// <param name="flag">The flag.</param>
/// <returns>The <see cref="bool"/>.</returns>
public static bool HasFlag<TEnum>(TEnum value, TEnum flag)
where TEnum : Enum
{
uint flagValue = Unsafe.As<TEnum, uint>(ref flag);
return (Unsafe.As<TEnum, uint>(ref value) & flagValue) == flagValue;
}
}
}

6
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="byte"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static byte Get8BitBT709Luminance(byte r, byte g, byte b) =>
(byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5f);
(byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
/// <summary>
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="ushort"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) =>
(ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
(ushort)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
/// <summary>
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="ushort"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(float r, float g, float b) =>
(ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
(ushort)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
/// <summary>
/// Scales a value from a 16 bit <see cref="ushort"/> to it's 8 bit <see cref="byte"/> equivalent.

4
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);
}
}
}
}

9
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<ushort> 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);
}
}
}

2
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -1321,7 +1321,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.metadata = meta;
short bitsPerPixel = this.infoHeader.BitsPerPixel;
this.bmpMetadata = this.metadata.GetFormatMetadata(BmpFormat.Instance);
this.bmpMetadata = this.metadata.GetBmpMetadata();
this.bmpMetadata.InfoHeaderType = infoHeaderType;
// We can only encode at these bit rates so far (1 bit and 4 bit are still missing).

6
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
BmpMetadata bmpMetadata = metadata.GetFormatMetadata(BmpFormat.Instance);
BmpMetadata bmpMetadata = metadata.GetBmpMetadata();
this.bitsPerPixel = this.bitsPerPixel ?? bmpMetadata.BitsPerPixel;
short bpp = (short)this.bitsPerPixel;
@ -315,11 +315,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private void Write8Bit<TPixel>(Stream stream, ImageFrame<TPixel> image)
where TPixel : struct, IPixel<TPixel>
{
bool isGray8 = typeof(TPixel) == typeof(Gray8);
bool isL8 = typeof(TPixel) == typeof(L8);
using (IMemoryOwner<byte> colorPaletteBuffer = this.memoryAllocator.AllocateManagedByteBuffer(ColorPaletteSize8Bit, AllocationOptions.Clean))
{
Span<byte> colorPalette = colorPaletteBuffer.GetSpan();
if (isGray8)
if (isL8)
{
this.Write8BitGray(stream, image, colorPalette);
}

0
src/ImageSharp/Formats/Bmp/BmpMetaData.cs → src/ImageSharp/Formats/Bmp/BmpMetadata.cs

21
src/ImageSharp/Formats/Bmp/MetadataExtensions.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary>
/// Gets the bmp format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="BmpMetadata"/>.</returns>
public static BmpMetadata GetBmpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(BmpFormat.Instance);
}
}

4
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -553,7 +553,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetFrameMetadata(ImageFrameMetadata meta)
{
GifFrameMetadata gifMeta = meta.GetFormatMetadata(GifFormat.Instance);
GifFrameMetadata gifMeta = meta.GetGifMetadata();
if (this.graphicsControlExtension.DelayTime > 0)
{
gifMeta.FrameDelay = this.graphicsControlExtension.DelayTime;
@ -615,7 +615,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
this.metadata = meta;
this.gifMetadata = meta.GetFormatMetadata(GifFormat.Instance);
this.gifMetadata = meta.GetGifMetadata();
this.gifMetadata.ColorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag
? GifColorTableMode.Global
: GifColorTableMode.Local;

6
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
GifMetadata gifMetadata = metadata.GetFormatMetadata(GifFormat.Instance);
GifMetadata gifMetadata = metadata.GetGifMetadata();
this.colorTableMode = this.colorTableMode ?? gifMetadata.ColorTableMode;
bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global;
@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
ImageFrame<TPixel> frame = image.Frames[i];
ImageFrameMetadata metadata = frame.Metadata;
GifFrameMetadata frameMetadata = metadata.GetFormatMetadata(GifFormat.Instance);
GifFrameMetadata frameMetadata = metadata.GetGifMetadata();
this.WriteGraphicalControlExtension(frameMetadata, transparencyIndex, stream);
this.WriteImageDescriptor(frame, false, stream);
@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
foreach (ImageFrame<TPixel> frame in image.Frames)
{
ImageFrameMetadata metadata = frame.Metadata;
GifFrameMetadata frameMetadata = metadata.GetFormatMetadata(GifFormat.Instance);
GifFrameMetadata frameMetadata = metadata.GetGifMetadata();
if (quantized is null)
{
// Allow each frame to be encoded at whatever color depth the frame designates if set.

0
src/ImageSharp/Formats/Gif/GifFrameMetaData.cs → src/ImageSharp/Formats/Gif/GifFrameMetadata.cs

0
src/ImageSharp/Formats/Gif/GifMetaData.cs → src/ImageSharp/Formats/Gif/GifMetadata.cs

28
src/ImageSharp/Formats/Gif/MetadataExtensions.cs

@ -0,0 +1,28 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary>
/// Gets the gif format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="GifMetadata"/>.</returns>
public static GifMetadata GetGifMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(GifFormat.Instance);
/// <summary>
/// Gets the gif format specific metadata for the image frame.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="GifFrameMetadata"/>.</returns>
public static GifFrameMetadata GetGifMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(GifFormat.Instance);
}
}

7
src/ImageSharp/Formats/IImageDecoder.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.IO;
@ -17,17 +17,16 @@ namespace SixLabors.ImageSharp.Formats
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The decoded image of a given pixel type.</returns>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel>;
/// <summary>
/// Decodes the image from the specified stream to an <see cref="Image"/>.
/// The decoder is free to choose the pixel type.
/// </summary>
/// <param name="configuration">The configuration for the image.</param>
/// <param name="stream">The <see cref="Stream"/> containing image data.</param>
/// <returns>The decoded image of a pixel type chosen by the decoder.</returns>
/// <returns>The <see cref="Image"/>.</returns>
Image Decode(Configuration configuration, Stream stream);
}
}

11
src/ImageSharp/Formats/Jpeg/JpegDecoder.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.IO;
@ -28,6 +28,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream)
=> this.Decode<Rgba32>(configuration, stream);
/// <inheritdoc/>
public IImageInfo Identify(Configuration configuration, Stream stream)
{
@ -38,8 +42,5 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
return decoder.Identify(stream);
}
}
/// <inheritdoc />
public Image Decode(Configuration configuration, Stream stream) => this.Decode<Rgba32>(configuration, stream);
}
}
}

78
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -465,24 +465,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
}
}
private double GetExifResolutionValue(ExifTag tag)
private double GetExifResolutionValue(ExifTag<Rational> tag)
{
if (!this.Metadata.ExifProfile.TryGetValue(tag, out ExifValue exifValue))
{
return 0;
}
IExifValue<Rational> 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();
}
/// <summary>
@ -649,48 +636,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
switch (quantizationTableSpec >> 4)
{
case 0:
{
// 8 bit values
if (remaining < 64)
{
// 8 bit values
if (remaining < 64)
{
done = true;
break;
}
done = true;
break;
}
this.InputStream.Read(this.temp, 0, 64);
remaining -= 64;
this.InputStream.Read(this.temp, 0, 64);
remaining -= 64;
ref Block8x8F table = ref this.QuantizationTables[tableIndex];
for (int j = 0; j < 64; j++)
{
table[j] = this.temp[j];
}
ref Block8x8F table = ref this.QuantizationTables[tableIndex];
for (int j = 0; j < 64; j++)
{
table[j] = this.temp[j];
}
}
break;
break;
case 1:
{
// 16 bit values
if (remaining < 128)
{
// 16 bit values
if (remaining < 128)
{
done = true;
break;
}
done = true;
break;
}
this.InputStream.Read(this.temp, 0, 128);
remaining -= 128;
this.InputStream.Read(this.temp, 0, 128);
remaining -= 128;
ref Block8x8F table = ref this.QuantizationTables[tableIndex];
for (int j = 0; j < 64; j++)
{
table[j] = (this.temp[2 * j] << 8) | this.temp[(2 * j) + 1];
}
ref Block8x8F table = ref this.QuantizationTables[tableIndex];
for (int j = 0; j < 64; j++)
{
table[j] = (this.temp[2 * j] << 8) | this.temp[(2 * j) + 1];
}
}
break;
break;
default:
{
JpegThrowHelper.ThrowBadQuantizationTable();
break;
}
}
if (done)

12
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;
@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
ImageMetadata metadata = image.Metadata;
// System.Drawing produces identical output for jpegs with a quality parameter of 0 and 1.
int qlty = (this.quality ?? metadata.GetFormatMetadata(JpegFormat.Instance).Quality).Clamp(1, 100);
int qlty = (this.quality ?? metadata.GetJpegMetadata().Quality).Clamp(1, 100);
this.subsample = this.subsample ?? (qlty >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420);
// Convert from a quality rating to a scaling factor.
@ -647,7 +647,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </exception>
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);
}
}
}
}

0
src/ImageSharp/Formats/Jpeg/JpegMetaData.cs → src/ImageSharp/Formats/Jpeg/JpegMetadata.cs

21
src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary>
/// Gets the jpeg format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="JpegMetadata"/>.</returns>
public static JpegMetadata GetJpegMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(JpegFormat.Instance);
}
}

21
src/ImageSharp/Formats/Png/MetadataExtensions.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary>
/// Gets the png format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="PngMetadata"/>.</returns>
public static PngMetadata GetPngMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(PngFormat.Instance);
}
}

16
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Png
where TPixel : struct, IPixel<TPixel>
{
var metadata = new ImageMetadata();
PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance);
PngMetadata pngMetadata = metadata.GetPngMetadata();
this.currentStream = stream;
this.currentStream.Skip(8);
Image<TPixel> image = null;
@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public IImageInfo Identify(Stream stream)
{
var metadata = new ImageMetadata();
PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance);
PngMetadata pngMetadata = metadata.GetPngMetadata();
this.currentStream = stream;
this.currentStream.Skip(8);
try
@ -658,8 +658,8 @@ namespace SixLabors.ImageSharp.Formats.Png
scanlineSpan,
rowSpan,
pngMetadata.HasTransparency,
pngMetadata.TransparentGray16.GetValueOrDefault(),
pngMetadata.TransparentGray8.GetValueOrDefault());
pngMetadata.TransparentL16.GetValueOrDefault(),
pngMetadata.TransparentL8.GetValueOrDefault());
break;
@ -742,8 +742,8 @@ namespace SixLabors.ImageSharp.Formats.Png
pixelOffset,
increment,
pngMetadata.HasTransparency,
pngMetadata.TransparentGray16.GetValueOrDefault(),
pngMetadata.TransparentGray8.GetValueOrDefault());
pngMetadata.TransparentL16.GetValueOrDefault(),
pngMetadata.TransparentL8.GetValueOrDefault());
break;
@ -837,11 +837,11 @@ namespace SixLabors.ImageSharp.Formats.Png
{
if (this.header.BitDepth == 16)
{
pngMetadata.TransparentGray16 = new Gray16(BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)));
pngMetadata.TransparentL16 = new L16(BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)));
}
else
{
pngMetadata.TransparentGray8 = new Gray8(ReadByteLittleEndian(alpha, 0));
pngMetadata.TransparentL8 = new L8(ReadByteLittleEndian(alpha, 0));
}
pngMetadata.HasTransparency = true;

30
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -199,16 +199,16 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.use16Bit)
{
// 16 bit grayscale
using (IMemoryOwner<Gray16> luminanceBuffer = this.memoryAllocator.Allocate<Gray16>(rowSpan.Length))
using (IMemoryOwner<L16> luminanceBuffer = this.memoryAllocator.Allocate<L16>(rowSpan.Length))
{
Span<Gray16> luminanceSpan = luminanceBuffer.GetSpan();
ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan);
PixelOperations<TPixel>.Instance.ToGray16(this.configuration, rowSpan, luminanceSpan);
Span<L16> luminanceSpan = luminanceBuffer.GetSpan();
ref L16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan);
PixelOperations<TPixel>.Instance.ToL16(this.configuration, rowSpan, luminanceSpan);
// Can't map directly to byte array as it's big-endian.
for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2)
{
Gray16 luminance = Unsafe.Add(ref luminanceRef, x);
L16 luminance = Unsafe.Add(ref luminanceRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue);
}
}
@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.bitDepth == 8)
{
// 8 bit grayscale
PixelOperations<TPixel>.Instance.ToGray8Bytes(
PixelOperations<TPixel>.Instance.ToL8Bytes(
this.configuration,
rowSpan,
rawScanlineSpan,
@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.Formats.Png
Span<byte> tempSpan = temp.GetSpan();
// We need to first create an array of luminance bytes then scale them down to the correct bit depth.
PixelOperations<TPixel>.Instance.ToGray8Bytes(
PixelOperations<TPixel>.Instance.ToL8Bytes(
this.configuration,
rowSpan,
tempSpan,
@ -622,11 +622,13 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="meta">The image metadata.</param>
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());
}
/// <summary>
@ -761,15 +763,15 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else if (pngMetadata.ColorType == PngColorType.Grayscale)
{
if (pngMetadata.TransparentGray16.HasValue && this.use16Bit)
if (pngMetadata.TransparentL16.HasValue && this.use16Bit)
{
BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetadata.TransparentGray16.Value.PackedValue);
BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetadata.TransparentL16.Value.PackedValue);
this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2);
}
else if (pngMetadata.TransparentGray8.HasValue)
else if (pngMetadata.TransparentL8.HasValue)
{
alpha.Clear();
alpha[1] = pngMetadata.TransparentGray8.Value.PackedValue;
alpha[1] = pngMetadata.TransparentL8.Value.PackedValue;
this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2);
}
}

8
src/ImageSharp/Formats/Png/PngMetaData.cs → src/ImageSharp/Formats/Png/PngMetadata.cs

@ -29,8 +29,8 @@ namespace SixLabors.ImageSharp.Formats.Png
this.Gamma = other.Gamma;
this.InterlaceMethod = other.InterlaceMethod;
this.HasTransparency = other.HasTransparency;
this.TransparentGray8 = other.TransparentGray8;
this.TransparentGray16 = other.TransparentGray16;
this.TransparentL8 = other.TransparentL8;
this.TransparentL16 = other.TransparentL16;
this.TransparentRgb24 = other.TransparentRgb24;
this.TransparentRgb48 = other.TransparentRgb48;
@ -77,13 +77,13 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Gets or sets the 8 bit grayscale transparent color.
/// This represents any color in an 8 bit grayscale encoded png that should be transparent.
/// </summary>
public Gray8? TransparentGray8 { get; set; }
public L8? TransparentL8 { get; set; }
/// <summary>
/// Gets or sets the 16 bit grayscale transparent color.
/// This represents any color in a 16 bit grayscale encoded png that should be transparent.
/// </summary>
public Gray16? TransparentGray16 { get; set; }
public L16? TransparentL16 { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the image contains a transparency chunk and markers were decoded.

111
src/ImageSharp/Formats/Png/PngScanlineProcessor.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;
@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Png
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
bool hasTrans,
Gray16 luminance16Trans,
Gray8 luminanceTrans)
L16 luminance16Trans,
L8 luminanceTrans)
where TPixel : struct, IPixel<TPixel>
{
TPixel pixel = default;
@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = 0, o = 0; x < header.Width; x++, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
pixel.FromGray16(new Gray16(luminance));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = 0; x < header.Width; x++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor);
pixel.FromGray8(new Gray8(luminance));
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -55,32 +55,28 @@ namespace SixLabors.ImageSharp.Formats.Png
if (header.BitDepth == 16)
{
Rgba64 rgba64 = default;
La32 source = default;
for (int x = 0, o = 0; x < header.Width; x++, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue;
source.L = luminance;
source.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue;
pixel.FromRgba64(rgba64);
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else
{
La16 source = default;
byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor);
Rgba32 rgba32 = default;
for (int x = 0; x < header.Width; x++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue;
source.L = luminance;
source.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue;
pixel.FromRgba32(rgba32);
pixel.FromLa16(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -93,8 +89,8 @@ namespace SixLabors.ImageSharp.Formats.Png
int pixelOffset,
int increment,
bool hasTrans,
Gray16 luminance16Trans,
Gray8 luminanceTrans)
L16 luminance16Trans,
L8 luminanceTrans)
where TPixel : struct, IPixel<TPixel>
{
TPixel pixel = default;
@ -109,7 +105,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
pixel.FromGray16(new Gray16(luminance));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -118,7 +114,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
pixel.FromGray8(new Gray8(luminance));
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -128,32 +124,28 @@ namespace SixLabors.ImageSharp.Formats.Png
if (header.BitDepth == 16)
{
Rgba64 rgba64 = default;
La32 source = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue;
source.L = luminance;
source.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue;
pixel.FromRgba64(rgba64);
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else
{
La16 source = default;
byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor);
Rgba32 rgba32 = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue;
source.L = luminance;
source.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue;
pixel.FromRgba32(rgba32);
pixel.FromLa16(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -173,35 +165,26 @@ namespace SixLabors.ImageSharp.Formats.Png
if (header.BitDepth == 16)
{
Rgba64 rgba64 = default;
La32 source = default;
for (int x = 0, o = 0; x < header.Width; x++, o += 4)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = alpha;
source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
pixel.FromRgba64(rgba64);
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else
{
Rgba32 rgba32 = default;
La16 source = default;
for (int x = 0; x < header.Width; x++)
{
int offset = x * bytesPerPixel;
byte luminance = Unsafe.Add(ref scanlineSpanRef, offset);
byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = alpha;
source.L = Unsafe.Add(ref scanlineSpanRef, offset);
source.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
pixel.FromRgba32(rgba32);
pixel.FromLa16(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -223,34 +206,26 @@ namespace SixLabors.ImageSharp.Formats.Png
if (header.BitDepth == 16)
{
Rgba64 rgba64 = default;
La32 source = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 4)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = alpha;
source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
pixel.FromRgba64(rgba64);
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else
{
Rgba32 rgba32 = default;
int offset = 0;
La16 source = default;
for (int x = pixelOffset; x < header.Width; x += increment)
{
byte luminance = Unsafe.Add(ref scanlineSpanRef, offset);
byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = alpha;
source.L = Unsafe.Add(ref scanlineSpanRef, offset);
source.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
pixel.FromRgba32(rgba32);
pixel.FromLa16(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
offset += bytesPerPixel;
}
@ -403,12 +378,12 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
Rgba32 rgba32 = default;
ReadOnlySpan<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(scanlineSpan);
ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span);
for (int x = 0; x < header.Width; x++)
{
ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x);
Rgba32 rgba32 = default;
rgba32.Rgb = rgb24;
rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue;
@ -576,4 +551,4 @@ namespace SixLabors.ImageSharp.Formats.Png
}
}
}
}
}

21
src/ImageSharp/Formats/Tga/MetadataExtensions.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Metadata;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Extension methods for the <see cref="ImageMetadata"/> type.
/// </summary>
public static partial class MetadataExtensions
{
/// <summary>
/// Gets the tga format specific metadata for the image.
/// </summary>
/// <param name="metadata">The metadata this method extends.</param>
/// <returns>The <see cref="TgaMetadata"/>.</returns>
public static TgaMetadata GetTgaMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(TgaFormat.Instance);
}
}

10
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<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
var image = Image.CreateUninitialized<TPixel>(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata);
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
if (this.fileHeader.ColorMapType is 1)
@ -301,7 +301,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
switch (colorMapPixelSizeInBytes)
{
case 1:
color.FromGray8(Unsafe.As<byte, Gray8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
color.FromL8(Unsafe.As<byte, L8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 2:
// Set alpha value to 1, to treat it as opaque for Bgra5551.
@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.currentStream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromGray8Bytes(
PixelOperations<TPixel>.Instance.FromL8Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
@ -467,7 +467,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
switch (bytesPerPixel)
{
case 1:
color.FromGray8(Unsafe.As<byte, Gray8>(ref bufferSpan[idx]));
color.FromL8(Unsafe.As<byte, L8>(ref bufferSpan[idx]));
break;
case 2:
// Set alpha value to 1, to treat it as opaque for Bgra5551.
@ -573,7 +573,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.currentStream.Read(buffer, 0, TgaFileHeader.Size);
this.fileHeader = TgaFileHeader.Parse(buffer);
this.metadata = new ImageMetadata();
this.tgaMetadata = this.metadata.GetFormatMetadata(TgaFormat.Instance);
this.tgaMetadata = this.metadata.GetTgaMetadata();
this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth;
// Bit at position 5 of the descriptor indicates, that the origin is top left instead of bottom right.

4
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
this.configuration = image.GetConfiguration();
ImageMetadata metadata = image.Metadata;
TgaMetadata tgaMetadata = metadata.GetFormatMetadata(TgaFormat.Instance);
TgaMetadata tgaMetadata = metadata.GetTgaMetadata();
this.bitsPerPixel = this.bitsPerPixel ?? tgaMetadata.BitsPerPixel;
TgaImageType imageType = this.compression is TgaCompression.RunLength ? TgaImageType.RleTrueColor : TgaImageType.TrueColor;
@ -251,7 +251,7 @@ namespace SixLabors.ImageSharp.Formats.Tga
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToGray8Bytes(
PixelOperations<TPixel>.Instance.ToL8Bytes(
this.configuration,
pixelSpan,
row.GetSpan(),

44
src/ImageSharp/Image.FromBytes.cs

@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data)
where TPixel : struct, IPixel<TPixel>
{
using (var stream = new MemoryStream(data))
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(config, stream);
}
@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, out IImageFormat format)
where TPixel : struct, IPixel<TPixel>
{
using (var stream = new MemoryStream(data))
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(config, stream, out format);
}
@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp
public static Image<TPixel> Load<TPixel>(byte[] data, IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
{
using (var stream = new MemoryStream(data))
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(stream, decoder);
}
@ -125,9 +125,9 @@ namespace SixLabors.ImageSharp
public static Image<TPixel> Load<TPixel>(Configuration config, byte[] data, IImageDecoder decoder)
where TPixel : struct, IPixel<TPixel>
{
using (var memoryStream = new MemoryStream(data))
using (var stream = new MemoryStream(data, 0, data.Length, false, true))
{
return Load<TPixel>(config, memoryStream, decoder);
return Load<TPixel>(config, stream, decoder);
}
}
@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The detected format.</param>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(byte[] data, out IImageFormat format) =>
Load(Configuration.Default, data, out format);
@ -279,52 +279,52 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="data">The byte array containing encoded image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(byte[] data, IImageDecoder decoder) => Load(Configuration.Default, data, decoder);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing encoded image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, byte[] data) => Load(config, data, out _);
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
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);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte array.
/// Load a new instance of <see cref="Image"/> from the given encoded byte array.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="data">The byte array containing image data.</param>
/// <param name="format">The mime type of the decoded image.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
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);
}
}
/// <summary>
/// Load a new instance of <see cref="Image{Rgba32}"/> from the given encoded byte span.
/// Load a new instance of <see cref="Image"/> from the given encoded byte span.
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data) => Load(Configuration.Default, data);
/// <summary>
@ -332,7 +332,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, IImageDecoder decoder) =>
Load(Configuration.Default, data, decoder);
@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The detected format.</param>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(ReadOnlySpan<byte> data, out IImageFormat format) =>
Load(Configuration.Default, data, out format);
@ -350,7 +350,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, ReadOnlySpan<byte> data) => Load(config, data, out _);
/// <summary>
@ -359,7 +359,7 @@ namespace SixLabors.ImageSharp
/// <param name="config">The Configuration.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="decoder">The decoder.</param>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static unsafe Image Load(
Configuration config,
ReadOnlySpan<byte> data,
@ -380,7 +380,7 @@ namespace SixLabors.ImageSharp
/// <param name="config">The configuration options.</param>
/// <param name="data">The byte span containing image data.</param>
/// <param name="format">The <see cref="IImageFormat"/> of the decoded image.</param>>
/// <returns>A new <see cref="Image"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static unsafe Image Load(
Configuration config,
ReadOnlySpan<byte> data,

22
src/ImageSharp/Image.FromFile.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;
@ -39,17 +39,17 @@ namespace SixLabors.ImageSharp
}
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(string path) => Load(Configuration.Default, path);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="format">The mime type of the decoded image.</param>
@ -60,18 +60,18 @@ namespace SixLabors.ImageSharp
public static Image Load(string path, out IImageFormat format) => Load(Configuration.Default, path, out format);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="config">The config for the decoder.</param>
/// <param name="path">The file path to the image.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, string path) => Load(config, path, out _);
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="config">The Configuration.</param>
/// <param name="path">The file path to the image.</param>
@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Configuration config, string path, IImageDecoder decoder)
{
using (Stream stream = config.FileSystem.OpenRead(path))
@ -89,14 +89,14 @@ namespace SixLabors.ImageSharp
}
/// <summary>
/// Create a new instance of the <see cref="Image{Rgba32}"/> class from the given file.
/// Create a new instance of the <see cref="Image"/> class from the given file.
/// </summary>
/// <param name="path">The file path to the image.</param>
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the stream is not readable nor seekable.
/// </exception>
/// <returns>A new <see cref="Image{Rgba32}"/>.</returns>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(string path, IImageDecoder decoder) => Load(Configuration.Default, path, decoder);
/// <summary>
@ -224,4 +224,4 @@ namespace SixLabors.ImageSharp
}
}
}
}
}

6
src/ImageSharp/Image.FromStream.cs

@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp
/// <param name="format">The format type of the decoded image.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <returns>A new <see cref="Image"/>.</returns>>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream, out IImageFormat format) => Load(Configuration.Default, stream, out format);
/// <summary>
@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream containing image information.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <returns>A new <see cref="Image"/>.</returns>>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream) => Load(Configuration.Default, stream);
/// <summary>
@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp
/// <param name="decoder">The decoder.</param>
/// <exception cref="NotSupportedException">Thrown if the stream is not readable.</exception>
/// <exception cref="UnknownImageFormatException">Image cannot be loaded.</exception>
/// <returns>A new <see cref="Image"/>.</returns>>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Load(Stream stream, IImageDecoder decoder) => Load(Configuration.Default, stream, decoder);
/// <summary>

4
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<ImageFrame> GetEnumerator() => this.NonGenericGetEnumerator();
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() => this.NonGenericGetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
/// <summary>
/// Implements <see cref="GetEnumerator"/>.

43
src/ImageSharp/ImageSharp.csproj

@ -77,15 +77,30 @@
<AutoGen>True</AutoGen>
<DependentUpon>Bgra32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\Generated\Gray8.PixelOperations.Generated.cs">
<Compile Update="PixelFormats\PixelImplementations\Generated\Bgra5551.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Gray8.PixelOperations.Generated.tt</DependentUpon>
<DependentUpon>Bgra5551.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\Generated\Gray16.PixelOperations.Generated.cs">
<Compile Update="PixelFormats\PixelImplementations\Generated\L8.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Gray16.PixelOperations.Generated.tt</DependentUpon>
<DependentUpon>L8.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\Generated\L16.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>L16.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\Generated\La16.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>La16.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\Generated\La32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>La32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\Generated\Rgb24.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
@ -152,13 +167,25 @@
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Bgra32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\Generated\Gray8.PixelOperations.Generated.tt">
<None Update="PixelFormats\PixelImplementations\Generated\Bgra5551.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Bgra5551.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\Generated\L8.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>L8.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\Generated\L16.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>L16.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\Generated\La16.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Gray8.PixelOperations.Generated.cs</LastGenOutput>
<LastGenOutput>La16.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\Generated\Gray16.PixelOperations.Generated.tt">
<None Update="PixelFormats\PixelImplementations\Generated\La32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Gray16.PixelOperations.Generated.cs</LastGenOutput>
<LastGenOutput>La32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\Generated\Rgb24.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>

18
src/ImageSharp/Image{TPixel}.cs

@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp
protected override ImageFrameCollection NonGenericFrameCollection => this.Frames;
/// <summary>
/// Gets the frames.
/// Gets the collection of image frames.
/// </summary>
public new ImageFrameCollection<TPixel> Frames { get; }
@ -166,8 +166,12 @@ namespace SixLabors.ImageSharp
{
this.EnsureNotDisposed();
IEnumerable<ImageFrame<TPixel>> clonedFrames =
this.Frames.Select<ImageFrame<TPixel>, ImageFrame<TPixel>>(x => x.Clone(configuration));
var clonedFrames = new ImageFrame<TPixel>[this.Frames.Count];
for (int i = 0; i < clonedFrames.Length; i++)
{
clonedFrames[i] = this.Frames[i].Clone(configuration);
}
return new Image<TPixel>(configuration, this.Metadata.DeepClone(), clonedFrames);
}
@ -181,8 +185,12 @@ namespace SixLabors.ImageSharp
{
this.EnsureNotDisposed();
IEnumerable<ImageFrame<TPixel2>> clonedFrames =
this.Frames.Select<ImageFrame<TPixel>, ImageFrame<TPixel2>>(x => x.CloneAs<TPixel2>(configuration));
var clonedFrames = new ImageFrame<TPixel2>[this.Frames.Count];
for (int i = 0; i < clonedFrames.Length; i++)
{
clonedFrames[i] = this.Frames[i].CloneAs<TPixel2>(configuration);
}
return new Image<TPixel2>(configuration, this.Metadata.DeepClone(), clonedFrames);
}

281
src/ImageSharp/MetaData/Profiles/Exif/ExifTags.cs

@ -1,281 +0,0 @@
// 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
{
/// <summary>
/// The collection if Image File Directory tags
/// </summary>
public static readonly ExifTag[] Ifd =
{
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
};
/// <summary>
/// The collection of Exif tags
/// </summary>
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
};
/// <summary>
/// The collection of GPS tags
/// </summary>
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
};
}
}

721
src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs

@ -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
{
/// <summary>
/// Represent the value of the EXIF profile.
/// </summary>
public sealed class ExifValue : IEquatable<ExifValue>, IDeepCloneable<ExifValue>
{
/// <summary>
/// Initializes a new instance of the <see cref="ExifValue"/> class.
/// </summary>
/// <param name="tag">The tag.</param>
/// <param name="dataType">The data type.</param>
/// <param name="value">The value.</param>
/// <param name="isArray">Whether the value is an array.</param>
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;
}
/// <summary>
/// Initializes a new instance of the <see cref="ExifValue"/> class
/// by making a copy from another exif value.
/// </summary>
/// <param name="other">The other exif value, where the clone should be made from.</param>
/// <exception cref="ArgumentNullException"><paramref name="other"/> is null.</exception>
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();
}
}
/// <summary>
/// Gets the data type of the exif value.
/// </summary>
public ExifDataType DataType { get; }
/// <summary>
/// Gets a value indicating whether the value is an array.
/// </summary>
public bool IsArray { get; }
/// <summary>
/// Gets the tag of the exif value.
/// </summary>
public ExifTag Tag { get; }
/// <summary>
/// Gets the value.
/// </summary>
public object Value { get; }
/// <summary>
/// Gets a value indicating whether the EXIF value has a value.
/// </summary>
internal bool HasValue
{
get
{
if (this.Value is null)
{
return false;
}
if (this.DataType == ExifDataType.Ascii)
{
return ((string)this.Value).Length > 0;
}
return true;
}
}
/// <summary>
/// Gets the length of the EXIF value
/// </summary>
internal int Length
{
get
{
if (this.Value is null)
{
return 4;
}
int size = (int)(GetSize(this.DataType) * this.NumberOfComponents);
return size < 4 ? 4 : size;
}
}
/// <summary>
/// Gets the number of components.
/// </summary>
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;
}
}
/// <summary>
/// Compares two <see cref="ExifValue"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="ExifValue"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="ExifValue"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(ExifValue left, ExifValue right) => ReferenceEquals(left, right) || left.Equals(right);
/// <summary>
/// Compares two <see cref="ExifValue"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="ExifValue"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="ExifValue"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(ExifValue left, ExifValue right) => !(left == right);
/// <inheritdoc />
public override bool Equals(object obj) => obj is ExifValue other && this.Equals(other);
/// <inheritdoc />
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);
}
/// <summary>
/// Clones the current value, overwriting the value.
/// </summary>
/// <param name="value">The value to overwrite.</param>
/// <returns><see cref="ExifValue"/></returns>
public ExifValue WithValue(object value)
{
this.CheckValue(value);
return new ExifValue(this.Tag, this.DataType, value, this.IsArray);
}
/// <inheritdoc/>
public override int GetHashCode()
{
return HashCode.Combine(this.Tag, this.DataType, this.Value);
}
/// <inheritdoc/>
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();
}
/// <inheritdoc/>
public ExifValue DeepClone() => new ExifValue(this);
/// <summary>
/// Creates a new <see cref="ExifValue"/>
/// </summary>
/// <param name="tag">The tag.</param>
/// <param name="value">The value.</param>
/// <returns>
/// The <see cref="ExifValue"/>.
/// </returns>
/// <exception cref="NotSupportedException">
/// Thrown if the tag is not supported.
/// </exception>
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();
}
}
/// <summary>
/// Gets the size in bytes of the given data type.
/// </summary>
/// <param name="dataType">The data type.</param>
/// <returns>
/// The <see cref="uint"/>.
/// </returns>
/// <exception cref="NotSupportedException">
/// Thrown if the type is unsupported.
/// </exception>
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());
}
}
/// <summary>
/// Returns an EXIF value with a numeric type for the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <param name="value">The value.</param>
/// <param name="isArray">Whether the value is an array.</param>
/// <returns>
/// The <see cref="ExifValue"/>.
/// </returns>
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);
}
/// <summary>
/// Checks the value type of the given object.
/// </summary>
/// <param name="value">The value to check.</param>
/// <exception cref="NotSupportedException">
/// Thrown if the object type is not supported.
/// </exception>
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();
}
}
/// <summary>
/// Converts the object value of this instance to its equivalent string representation
/// </summary>
/// <param name="value">The value</param>
/// <returns>The <see cref="string"/></returns>
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();
}
}
}
}

3
src/ImageSharp/MetaData/Profiles/Exif/README.md

@ -1,3 +0,0 @@
Adapted from Magick.NET:
https://github.com/dlemstra/Magick.NET/tree/784e23b1f5c824fc03d4b95d3387b3efe1ed510b/Magick.NET/Core/Profiles/Exif

0
src/ImageSharp/MetaData/FrameDecodingMode.cs → src/ImageSharp/Metadata/FrameDecodingMode.cs

0
src/ImageSharp/MetaData/ImageFrameMetaData.cs → src/ImageSharp/Metadata/ImageFrameMetadata.cs

0
src/ImageSharp/MetaData/ImageMetaData.cs → src/ImageSharp/Metadata/ImageMetadata.cs

0
src/ImageSharp/MetaData/PixelResolutionUnit.cs → src/ImageSharp/Metadata/PixelResolutionUnit.cs

BIN
src/ImageSharp/Metadata/Profiles/Exif/DC-008-Translation-2019-E.pdf

Binary file not shown.

0
src/ImageSharp/MetaData/Profiles/Exif/ExifConstants.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifConstants.cs

12
src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs → 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
/// <summary>
/// An 8-bit byte containing one 7-bit ASCII code. The final byte is terminated with NULL.
/// <remarks>
/// Although the standard defines ASCII this has commonly been ignored as
/// ASCII cannot properly encode text in many languages.
/// </remarks>
/// </summary>
Ascii = 2,
@ -64,13 +68,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
SignedRational = 10,
/// <summary>
/// A 32-bit floating point value.
/// A 32-bit single precision floating point value.
/// </summary>
SingleFloat = 11,
/// <summary>
/// A 64-bit floating point value.
/// A 64-bit double precision floating point value.
/// </summary>
DoubleFloat = 12
}
}
}

45
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
{
/// <summary>
/// Gets the size in bytes of the given data type.
/// </summary>
/// <param name="dataType">The data type.</param>
/// <returns>
/// The <see cref="uint"/>.
/// </returns>
/// <exception cref="NotSupportedException">
/// Thrown if the type is unsupported.
/// </exception>
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());
}
}
}
}

8
src/ImageSharp/MetaData/Profiles/Exif/ExifParts.cs → 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
/// <summary>
/// GPSTags
/// </summary>
GPSTags = 8,
GpsTags = 8,
/// <summary>
/// All
/// </summary>
All = IfdTags | ExifTags | GPSTags
All = IfdTags | ExifTags | GpsTags
}
}
}

130
src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs → 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
/// <summary>
/// The collection of EXIF values
/// </summary>
private List<ExifValue> values;
private List<IExifValue> values;
/// <summary>
/// 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<ExifValue>(other.Values.Count);
this.values = new List<IExifValue>(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
/// <summary>
/// Gets the values of this EXIF profile.
/// </summary>
public IReadOnlyList<ExifValue> Values
public IReadOnlyList<IExifValue> Values
{
get
{
@ -138,46 +138,13 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// <summary>
/// Returns the value with the specified tag.
/// </summary>
/// <param name="tag">The tag of the EXIF value.</param>
/// <returns>
/// The <see cref="ExifValue"/>.
/// </returns>
public ExifValue GetValue(ExifTag tag)
{
foreach (ExifValue exifValue in this.Values)
{
if (exifValue.Tag == tag)
{
return exifValue;
}
}
return null;
}
/// <summary>
/// Conditionally returns the value of the tag if it exists.
/// </summary>
/// <param name="tag">The tag of the EXIF value.</param>
/// <param name="value">The value of the tag, if found.</param>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
public bool TryGetValue(ExifTag tag, out ExifValue value)
/// <param name="tag">The tag of the exif value.</param>
/// <returns>The value with the specified tag.</returns>
/// <typeparam name="TValueType">The data type of the tag.</typeparam>
public IExifValue<TValueType> GetValue<TValueType>(ExifTag<TValueType> 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<TValueType>)value;
}
/// <summary>
@ -206,24 +173,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// <summary>
/// Sets the value of the specified tag.
/// </summary>
/// <param name="tag">The tag of the EXIF value.</param>
/// <param name="tag">The tag of the exif value.</param>
/// <param name="value">The value.</param>
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);
}
/// <typeparam name="TValueType">The data type of the tag.</typeparam>
public void SetValue<TValueType>(ExifTag<TValueType> tag, TValueType value)
=> this.SetValueInternal(tag, value);
/// <summary>
/// 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<byte>();
}
var writer = new ExifWriter(this.values, this.Parts);
@ -248,6 +202,50 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// <inheritdoc/>
public ExifProfile DeepClone() => new ExifProfile(this);
/// <summary>
/// Returns the value with the specified tag.
/// </summary>
/// <param name="tag">The tag of the exif value.</param>
/// <returns>The value with the specified tag.</returns>
internal IExifValue GetValueInternal(ExifTag tag)
{
foreach (IExifValue exifValue in this.Values)
{
if (exifValue.Tag == tag)
{
return exifValue;
}
}
return null;
}
/// <summary>
/// Sets the value of the specified tag.
/// </summary>
/// <param name="tag">The tag of the exif value.</param>
/// <param name="value">The value.</param>
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);
}
/// <summary>
/// Synchronizes the profiles with the specified metadata.
/// </summary>
@ -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<Rational> tag, double resolution)
{
ExifValue value = this.GetValue(tag);
IExifValue<Rational> 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<ExifValue>();
this.values = new List<IExifValue>();
return;
}
@ -301,4 +299,4 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
this.thumbnailLength = (int)reader.ThumbnailLength;
}
}
}
}

112
src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs → 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
/// <returns>
/// The <see cref="Collection{ExifValue}"/>.
/// </returns>
public List<ExifValue> ReadValues()
public List<IExifValue> ReadValues()
{
var values = new List<ExifValue>();
var values = new List<IExifValue>();
// 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<TDataType>(ExifDataType dataType, ReadOnlySpan<byte> data, ConverterMethod<TDataType> 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
/// </summary>
/// <param name="values">The values.</param>
/// <param name="index">The index.</param>
private void AddValues(List<ExifValue> values, uint index)
private void AddValues(List<IExifValue> 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<byte> 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<ExifTag>();
this.AddInvalidTag(new UnkownExifTag(tag));
return false;
}
this.invalidTags.Add(tag);
}
[MethodImpl(InliningOptions.ShortMethod)]
private TEnum ToEnum<TEnum>(int value, TEnum defaultValue)
where TEnum : struct, Enum
{
if (EnumHelper<TEnum>.IsDefined(value))
if (!exifValue.TrySetValue(value))
{
return Unsafe.As<int, TEnum>(ref value);
return false;
}
return defaultValue;
return true;
}
private void AddInvalidTag(ExifTag tag)
=> (this.invalidTags ?? (this.invalidTags = new List<ExifTag>())).Add(tag);
private bool TryReadSpan(int length, out ReadOnlySpan<byte> span)
{
if (this.RemainingLength < length)
@ -421,18 +394,18 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
private void GetThumbnail(uint offset)
{
var values = new List<ExifValue>();
var values = new List<IExifValue>();
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<TEnum>
where TEnum : struct, Enum
{
private static readonly int[] Values = Enum.GetValues(typeof(TEnum)).Cast<TEnum>()
.Select(e => Convert.ToInt32(e)).OrderBy(e => e).ToArray();
[MethodImpl(InliningOptions.ShortMethod)]
public static bool IsDefined(int value)
{
return Array.BinarySearch(Values, value) >= 0;
}
}
}
}

7
src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs → 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
/// </returns>
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;
}

275
src/ImageSharp/Metadata/Profiles/Exif/ExifTags.cs

@ -0,0 +1,275 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal static class ExifTags
{
public static ExifParts GetPart(ExifTag tag)
{
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;
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;
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;
}
}
}
}

238
src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

@ -18,24 +18,24 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// Which parts will be written.
/// </summary>
private readonly ExifParts allowedParts;
private readonly IList<ExifValue> values;
private readonly IList<IExifValue> values;
private List<int> dataOffsets;
private readonly List<int> ifdIndexes;
private readonly List<int> exifIndexes;
private readonly List<int> gpsIndexes;
private readonly List<IExifValue> ifdValues;
private readonly List<IExifValue> exifValues;
private readonly List<IExifValue> gpsValues;
/// <summary>
/// Initializes a new instance of the <see cref="ExifWriter"/> class.
/// </summary>
/// <param name="values">The values.</param>
/// <param name="allowedParts">The allowed parts.</param>
public ExifWriter(IList<ExifValue> values, ExifParts allowedParts)
public ExifWriter(IList<IExifValue> 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);
}
/// <summary>
@ -46,43 +46,29 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// </returns>
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<byte>();
}
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<byte>();
}
// 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<int> indexes, ExifTag tag)
private static IExifValue GetOffsetValue(List<IExifValue> ifdValues, List<IExifValue> 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<int> GetIndexes(ExifParts part, ExifTag[] tags)
private List<IExifValue> GetPartValues(ExifParts part)
{
if (((int)this.allowedParts & (int)part) == 0)
var result = new List<IExifValue>();
if (!EnumUtils.HasFlag(this.allowedParts, part))
{
return new List<int>();
return result;
}
var result = new List<int>();
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<int> 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<IExifValue> 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<byte> 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<byte> 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<int> indexes, Span<byte> destination, int offset)
private int WriteData(uint startIndex, List<IExifValue> values, Span<byte> 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<int> indexes, Span<byte> destination, int offset)
private int WriteHeaders(List<IExifValue> values, Span<byte> destination, int offset)
{
this.dataOffsets = new List<int>();
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<byte> destination, int offset)
private int WriteValue(IExifValue value, Span<byte> 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);
}
}
}

3
src/ImageSharp/Metadata/Profiles/Exif/README.md

@ -0,0 +1,3 @@
Adapted from Magick.NET:
https://github.com/dlemstra/Magick.NET

24
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the FaxProfile exif tag.
/// </summary>
public static ExifTag<byte> FaxProfile { get; } = new ExifTag<byte>(ExifTagValue.FaxProfile);
/// <summary>
/// Gets the ModeNumber exif tag.
/// </summary>
public static ExifTag<byte> ModeNumber { get; } = new ExifTag<byte>(ExifTagValue.ModeNumber);
/// <summary>
/// Gets the GPSAltitudeRef exif tag.
/// </summary>
public static ExifTag<byte> GPSAltitudeRef { get; } = new ExifTag<byte>(ExifTagValue.GPSAltitudeRef);
}
}

64
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the ClipPath exif tag.
/// </summary>
public static ExifTag<byte[]> ClipPath => new ExifTag<byte[]>(ExifTagValue.ClipPath);
/// <summary>
/// Gets the VersionYear exif tag.
/// </summary>
public static ExifTag<byte[]> VersionYear => new ExifTag<byte[]>(ExifTagValue.VersionYear);
/// <summary>
/// Gets the XMP exif tag.
/// </summary>
public static ExifTag<byte[]> XMP => new ExifTag<byte[]>(ExifTagValue.XMP);
/// <summary>
/// Gets the CFAPattern2 exif tag.
/// </summary>
public static ExifTag<byte[]> CFAPattern2 => new ExifTag<byte[]>(ExifTagValue.CFAPattern2);
/// <summary>
/// Gets the TIFFEPStandardID exif tag.
/// </summary>
public static ExifTag<byte[]> TIFFEPStandardID => new ExifTag<byte[]>(ExifTagValue.TIFFEPStandardID);
/// <summary>
/// Gets the XPTitle exif tag.
/// </summary>
public static ExifTag<byte[]> XPTitle => new ExifTag<byte[]>(ExifTagValue.XPTitle);
/// <summary>
/// Gets the XPComment exif tag.
/// </summary>
public static ExifTag<byte[]> XPComment => new ExifTag<byte[]>(ExifTagValue.XPComment);
/// <summary>
/// Gets the XPAuthor exif tag.
/// </summary>
public static ExifTag<byte[]> XPAuthor => new ExifTag<byte[]>(ExifTagValue.XPAuthor);
/// <summary>
/// Gets the XPKeywords exif tag.
/// </summary>
public static ExifTag<byte[]> XPKeywords => new ExifTag<byte[]>(ExifTagValue.XPKeywords);
/// <summary>
/// Gets the XPSubject exif tag.
/// </summary>
public static ExifTag<byte[]> XPSubject => new ExifTag<byte[]>(ExifTagValue.XPSubject);
/// <summary>
/// Gets the GPSVersionID exif tag.
/// </summary>
public static ExifTag<byte[]> GPSVersionID => new ExifTag<byte[]>(ExifTagValue.GPSVersionID);
}
}

29
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the PixelScale exif tag.
/// </summary>
public static ExifTag<double[]> PixelScale { get; } = new ExifTag<double[]>(ExifTagValue.PixelScale);
/// <summary>
/// Gets the IntergraphMatrix exif tag.
/// </summary>
public static ExifTag<double[]> IntergraphMatrix { get; } = new ExifTag<double[]>(ExifTagValue.IntergraphMatrix);
/// <summary>
/// Gets the ModelTiePoint exif tag.
/// </summary>
public static ExifTag<double[]> ModelTiePoint { get; } = new ExifTag<double[]>(ExifTagValue.ModelTiePoint);
/// <summary>
/// Gets the ModelTransform exif tag.
/// </summary>
public static ExifTag<double[]> ModelTransform { get; } = new ExifTag<double[]>(ExifTagValue.ModelTransform);
}
}

114
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the SubfileType exif tag.
/// </summary>
public static ExifTag<uint> SubfileType { get; } = new ExifTag<uint>(ExifTagValue.SubfileType);
/// <summary>
/// Gets the SubIFDOffset exif tag.
/// </summary>
public static ExifTag<uint> SubIFDOffset { get; } = new ExifTag<uint>(ExifTagValue.SubIFDOffset);
/// <summary>
/// Gets the GPSIFDOffset exif tag.
/// </summary>
public static ExifTag<uint> GPSIFDOffset { get; } = new ExifTag<uint>(ExifTagValue.GPSIFDOffset);
/// <summary>
/// Gets the T4Options exif tag.
/// </summary>
public static ExifTag<uint> T4Options { get; } = new ExifTag<uint>(ExifTagValue.T4Options);
/// <summary>
/// Gets the T6Options exif tag.
/// </summary>
public static ExifTag<uint> T6Options { get; } = new ExifTag<uint>(ExifTagValue.T6Options);
/// <summary>
/// Gets the XClipPathUnits exif tag.
/// </summary>
public static ExifTag<uint> XClipPathUnits { get; } = new ExifTag<uint>(ExifTagValue.XClipPathUnits);
/// <summary>
/// Gets the YClipPathUnits exif tag.
/// </summary>
public static ExifTag<uint> YClipPathUnits { get; } = new ExifTag<uint>(ExifTagValue.YClipPathUnits);
/// <summary>
/// Gets the ProfileType exif tag.
/// </summary>
public static ExifTag<uint> ProfileType { get; } = new ExifTag<uint>(ExifTagValue.ProfileType);
/// <summary>
/// Gets the CodingMethods exif tag.
/// </summary>
public static ExifTag<uint> CodingMethods { get; } = new ExifTag<uint>(ExifTagValue.CodingMethods);
/// <summary>
/// Gets the T82ptions exif tag.
/// </summary>
public static ExifTag<uint> T82ptions { get; } = new ExifTag<uint>(ExifTagValue.T82ptions);
/// <summary>
/// Gets the JPEGInterchangeFormat exif tag.
/// </summary>
public static ExifTag<uint> JPEGInterchangeFormat { get; } = new ExifTag<uint>(ExifTagValue.JPEGInterchangeFormat);
/// <summary>
/// Gets the JPEGInterchangeFormatLength exif tag.
/// </summary>
public static ExifTag<uint> JPEGInterchangeFormatLength { get; } = new ExifTag<uint>(ExifTagValue.JPEGInterchangeFormatLength);
/// <summary>
/// Gets the MDFileTag exif tag.
/// </summary>
public static ExifTag<uint> MDFileTag { get; } = new ExifTag<uint>(ExifTagValue.MDFileTag);
/// <summary>
/// Gets the StandardOutputSensitivity exif tag.
/// </summary>
public static ExifTag<uint> StandardOutputSensitivity { get; } = new ExifTag<uint>(ExifTagValue.StandardOutputSensitivity);
/// <summary>
/// Gets the RecommendedExposureIndex exif tag.
/// </summary>
public static ExifTag<uint> RecommendedExposureIndex { get; } = new ExifTag<uint>(ExifTagValue.RecommendedExposureIndex);
/// <summary>
/// Gets the ISOSpeed exif tag.
/// </summary>
public static ExifTag<uint> ISOSpeed { get; } = new ExifTag<uint>(ExifTagValue.ISOSpeed);
/// <summary>
/// Gets the ISOSpeedLatitudeyyy exif tag.
/// </summary>
public static ExifTag<uint> ISOSpeedLatitudeyyy { get; } = new ExifTag<uint>(ExifTagValue.ISOSpeedLatitudeyyy);
/// <summary>
/// Gets the ISOSpeedLatitudezzz exif tag.
/// </summary>
public static ExifTag<uint> ISOSpeedLatitudezzz { get; } = new ExifTag<uint>(ExifTagValue.ISOSpeedLatitudezzz);
/// <summary>
/// Gets the FaxRecvParams exif tag.
/// </summary>
public static ExifTag<uint> FaxRecvParams { get; } = new ExifTag<uint>(ExifTagValue.FaxRecvParams);
/// <summary>
/// Gets the FaxRecvTime exif tag.
/// </summary>
public static ExifTag<uint> FaxRecvTime { get; } = new ExifTag<uint>(ExifTagValue.FaxRecvTime);
/// <summary>
/// Gets the ImageNumber exif tag.
/// </summary>
public static ExifTag<uint> ImageNumber { get; } = new ExifTag<uint>(ExifTagValue.ImageNumber);
}
}

69
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the FreeOffsets exif tag.
/// </summary>
public static ExifTag<uint[]> FreeOffsets { get; } = new ExifTag<uint[]>(ExifTagValue.FreeOffsets);
/// <summary>
/// Gets the FreeByteCounts exif tag.
/// </summary>
public static ExifTag<uint[]> FreeByteCounts { get; } = new ExifTag<uint[]>(ExifTagValue.FreeByteCounts);
/// <summary>
/// Gets the ColorResponseUnit exif tag.
/// </summary>
public static ExifTag<uint[]> ColorResponseUnit { get; } = new ExifTag<uint[]>(ExifTagValue.ColorResponseUnit);
/// <summary>
/// Gets the TileOffsets exif tag.
/// </summary>
public static ExifTag<uint[]> TileOffsets { get; } = new ExifTag<uint[]>(ExifTagValue.TileOffsets);
/// <summary>
/// Gets the SMinSampleValue exif tag.
/// </summary>
public static ExifTag<uint[]> SMinSampleValue { get; } = new ExifTag<uint[]>(ExifTagValue.SMinSampleValue);
/// <summary>
/// Gets the SMaxSampleValue exif tag.
/// </summary>
public static ExifTag<uint[]> SMaxSampleValue { get; } = new ExifTag<uint[]>(ExifTagValue.SMaxSampleValue);
/// <summary>
/// Gets the JPEGQTables exif tag.
/// </summary>
public static ExifTag<uint[]> JPEGQTables { get; } = new ExifTag<uint[]>(ExifTagValue.JPEGQTables);
/// <summary>
/// Gets the JPEGDCTables exif tag.
/// </summary>
public static ExifTag<uint[]> JPEGDCTables { get; } = new ExifTag<uint[]>(ExifTagValue.JPEGDCTables);
/// <summary>
/// Gets the JPEGACTables exif tag.
/// </summary>
public static ExifTag<uint[]> JPEGACTables { get; } = new ExifTag<uint[]>(ExifTagValue.JPEGACTables);
/// <summary>
/// Gets the StripRowCounts exif tag.
/// </summary>
public static ExifTag<uint[]> StripRowCounts { get; } = new ExifTag<uint[]>(ExifTagValue.StripRowCounts);
/// <summary>
/// Gets the IntergraphRegisters exif tag.
/// </summary>
public static ExifTag<uint[]> IntergraphRegisters { get; } = new ExifTag<uint[]>(ExifTagValue.IntergraphRegisters);
/// <summary>
/// Gets the TimeZoneOffset exif tag.
/// </summary>
public static ExifTag<uint[]> TimeZoneOffset { get; } = new ExifTag<uint[]>(ExifTagValue.TimeZoneOffset);
}
}

51
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the ImageWidth exif tag.
/// </summary>
public static ExifTag<Number> ImageWidth { get; } = new ExifTag<Number>(ExifTagValue.ImageWidth);
/// <summary>
/// Gets the ImageLength exif tag.
/// </summary>
public static ExifTag<Number> ImageLength { get; } = new ExifTag<Number>(ExifTagValue.ImageLength);
/// <summary>
/// Gets the TileWidth exif tag.
/// </summary>
public static ExifTag<Number> TileWidth { get; } = new ExifTag<Number>(ExifTagValue.TileWidth);
/// <summary>
/// Gets the TileLength exif tag.
/// </summary>
public static ExifTag<Number> TileLength { get; } = new ExifTag<Number>(ExifTagValue.TileLength);
/// <summary>
/// Gets the BadFaxLines exif tag.
/// </summary>
public static ExifTag<Number> BadFaxLines { get; } = new ExifTag<Number>(ExifTagValue.BadFaxLines);
/// <summary>
/// Gets the ConsecutiveBadFaxLines exif tag.
/// </summary>
public static ExifTag<Number> ConsecutiveBadFaxLines { get; } = new ExifTag<Number>(ExifTagValue.ConsecutiveBadFaxLines);
/// <summary>
/// Gets the PixelXDimension exif tag.
/// </summary>
public static ExifTag<Number> PixelXDimension { get; } = new ExifTag<Number>(ExifTagValue.PixelXDimension);
/// <summary>
/// Gets the PixelYDimension exif tag.
/// </summary>
public static ExifTag<Number> PixelYDimension { get; } = new ExifTag<Number>(ExifTagValue.PixelYDimension);
}
}

26
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the StripOffsets exif tag.
/// </summary>
public static ExifTag<Number[]> StripOffsets { get; } = new ExifTag<Number[]>(ExifTagValue.StripOffsets);
/// <summary>
/// Gets the TileByteCounts exif tag.
/// </summary>
public static ExifTag<Number[]> TileByteCounts { get; } = new ExifTag<Number[]>(ExifTagValue.TileByteCounts);
/// <summary>
/// Gets the ImageLayer exif tag.
/// </summary>
public static ExifTag<Number[]> ImageLayer { get; } = new ExifTag<Number[]>(ExifTagValue.ImageLayer);
}
}

176
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the XPosition exif tag.
/// </summary>
public static ExifTag<Rational> XPosition { get; } = new ExifTag<Rational>(ExifTagValue.XPosition);
/// <summary>
/// Gets the YPosition exif tag.
/// </summary>
public static ExifTag<Rational> YPosition { get; } = new ExifTag<Rational>(ExifTagValue.YPosition);
/// <summary>
/// Gets the XResolution exif tag.
/// </summary>
public static ExifTag<Rational> XResolution { get; } = new ExifTag<Rational>(ExifTagValue.XResolution);
/// <summary>
/// Gets the YResolution exif tag.
/// </summary>
public static ExifTag<Rational> YResolution { get; } = new ExifTag<Rational>(ExifTagValue.YResolution);
/// <summary>
/// Gets the BatteryLevel exif tag.
/// </summary>
public static ExifTag<Rational> BatteryLevel { get; } = new ExifTag<Rational>(ExifTagValue.BatteryLevel);
/// <summary>
/// Gets the ExposureTime exif tag.
/// </summary>
public static ExifTag<Rational> ExposureTime { get; } = new ExifTag<Rational>(ExifTagValue.ExposureTime);
/// <summary>
/// Gets the FNumber exif tag.
/// </summary>
public static ExifTag<Rational> FNumber { get; } = new ExifTag<Rational>(ExifTagValue.FNumber);
/// <summary>
/// Gets the MDScalePixel exif tag.
/// </summary>
public static ExifTag<Rational> MDScalePixel { get; } = new ExifTag<Rational>(ExifTagValue.MDScalePixel);
/// <summary>
/// Gets the CompressedBitsPerPixel exif tag.
/// </summary>
public static ExifTag<Rational> CompressedBitsPerPixel { get; } = new ExifTag<Rational>(ExifTagValue.CompressedBitsPerPixel);
/// <summary>
/// Gets the ApertureValue exif tag.
/// </summary>
public static ExifTag<Rational> ApertureValue { get; } = new ExifTag<Rational>(ExifTagValue.ApertureValue);
/// <summary>
/// Gets the MaxApertureValue exif tag.
/// </summary>
public static ExifTag<Rational> MaxApertureValue { get; } = new ExifTag<Rational>(ExifTagValue.MaxApertureValue);
/// <summary>
/// Gets the SubjectDistance exif tag.
/// </summary>
public static ExifTag<Rational> SubjectDistance { get; } = new ExifTag<Rational>(ExifTagValue.SubjectDistance);
/// <summary>
/// Gets the FocalLength exif tag.
/// </summary>
public static ExifTag<Rational> FocalLength { get; } = new ExifTag<Rational>(ExifTagValue.FocalLength);
/// <summary>
/// Gets the FlashEnergy2 exif tag.
/// </summary>
public static ExifTag<Rational> FlashEnergy2 { get; } = new ExifTag<Rational>(ExifTagValue.FlashEnergy2);
/// <summary>
/// Gets the FocalPlaneXResolution2 exif tag.
/// </summary>
public static ExifTag<Rational> FocalPlaneXResolution2 { get; } = new ExifTag<Rational>(ExifTagValue.FocalPlaneXResolution2);
/// <summary>
/// Gets the FocalPlaneYResolution2 exif tag.
/// </summary>
public static ExifTag<Rational> FocalPlaneYResolution2 { get; } = new ExifTag<Rational>(ExifTagValue.FocalPlaneYResolution2);
/// <summary>
/// Gets the ExposureIndex2 exif tag.
/// </summary>
public static ExifTag<Rational> ExposureIndex2 { get; } = new ExifTag<Rational>(ExifTagValue.ExposureIndex2);
/// <summary>
/// Gets the Humidity exif tag.
/// </summary>
public static ExifTag<Rational> Humidity { get; } = new ExifTag<Rational>(ExifTagValue.Humidity);
/// <summary>
/// Gets the Pressure exif tag.
/// </summary>
public static ExifTag<Rational> Pressure { get; } = new ExifTag<Rational>(ExifTagValue.Pressure);
/// <summary>
/// Gets the Acceleration exif tag.
/// </summary>
public static ExifTag<Rational> Acceleration { get; } = new ExifTag<Rational>(ExifTagValue.Acceleration);
/// <summary>
/// Gets the FlashEnergy exif tag.
/// </summary>
public static ExifTag<Rational> FlashEnergy { get; } = new ExifTag<Rational>(ExifTagValue.FlashEnergy);
/// <summary>
/// Gets the FocalPlaneXResolution exif tag.
/// </summary>
public static ExifTag<Rational> FocalPlaneXResolution { get; } = new ExifTag<Rational>(ExifTagValue.FocalPlaneXResolution);
/// <summary>
/// Gets the FocalPlaneYResolution exif tag.
/// </summary>
public static ExifTag<Rational> FocalPlaneYResolution { get; } = new ExifTag<Rational>(ExifTagValue.FocalPlaneYResolution);
/// <summary>
/// Gets the ExposureIndex exif tag.
/// </summary>
public static ExifTag<Rational> ExposureIndex { get; } = new ExifTag<Rational>(ExifTagValue.ExposureIndex);
/// <summary>
/// Gets the DigitalZoomRatio exif tag.
/// </summary>
public static ExifTag<Rational> DigitalZoomRatio { get; } = new ExifTag<Rational>(ExifTagValue.DigitalZoomRatio);
/// <summary>
/// Gets the LensInfo exif tag.
/// </summary>
public static ExifTag<Rational> LensInfo { get; } = new ExifTag<Rational>(ExifTagValue.LensInfo);
/// <summary>
/// Gets the GPSAltitude exif tag.
/// </summary>
public static ExifTag<Rational> GPSAltitude { get; } = new ExifTag<Rational>(ExifTagValue.GPSAltitude);
/// <summary>
/// Gets the GPSDOP exif tag.
/// </summary>
public static ExifTag<Rational> GPSDOP { get; } = new ExifTag<Rational>(ExifTagValue.GPSDOP);
/// <summary>
/// Gets the GPSSpeed exif tag.
/// </summary>
public static ExifTag<Rational> GPSSpeed { get; } = new ExifTag<Rational>(ExifTagValue.GPSSpeed);
/// <summary>
/// Gets the GPSTrack exif tag.
/// </summary>
public static ExifTag<Rational> GPSTrack { get; } = new ExifTag<Rational>(ExifTagValue.GPSTrack);
/// <summary>
/// Gets the GPSImgDirection exif tag.
/// </summary>
public static ExifTag<Rational> GPSImgDirection { get; } = new ExifTag<Rational>(ExifTagValue.GPSImgDirection);
/// <summary>
/// Gets the GPSDestBearing exif tag.
/// </summary>
public static ExifTag<Rational> GPSDestBearing { get; } = new ExifTag<Rational>(ExifTagValue.GPSDestBearing);
/// <summary>
/// Gets the GPSDestDistance exif tag.
/// </summary>
public static ExifTag<Rational> GPSDestDistance { get; } = new ExifTag<Rational>(ExifTagValue.GPSDestDistance);
}
}

56
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the WhitePoint exif tag.
/// </summary>
public static ExifTag<Rational[]> WhitePoint { get; } = new ExifTag<Rational[]>(ExifTagValue.WhitePoint);
/// <summary>
/// Gets the PrimaryChromaticities exif tag.
/// </summary>
public static ExifTag<Rational[]> PrimaryChromaticities { get; } = new ExifTag<Rational[]>(ExifTagValue.PrimaryChromaticities);
/// <summary>
/// Gets the YCbCrCoefficients exif tag.
/// </summary>
public static ExifTag<Rational[]> YCbCrCoefficients { get; } = new ExifTag<Rational[]>(ExifTagValue.YCbCrCoefficients);
/// <summary>
/// Gets the ReferenceBlackWhite exif tag.
/// </summary>
public static ExifTag<Rational[]> ReferenceBlackWhite { get; } = new ExifTag<Rational[]>(ExifTagValue.ReferenceBlackWhite);
/// <summary>
/// Gets the GPSLatitude exif tag.
/// </summary>
public static ExifTag<Rational[]> GPSLatitude { get; } = new ExifTag<Rational[]>(ExifTagValue.GPSLatitude);
/// <summary>
/// Gets the GPSLongitude exif tag.
/// </summary>
public static ExifTag<Rational[]> GPSLongitude { get; } = new ExifTag<Rational[]>(ExifTagValue.GPSLongitude);
/// <summary>
/// Gets the GPSTimestamp exif tag.
/// </summary>
public static ExifTag<Rational[]> GPSTimestamp { get; } = new ExifTag<Rational[]>(ExifTagValue.GPSTimestamp);
/// <summary>
/// Gets the GPSDestLatitude exif tag.
/// </summary>
public static ExifTag<Rational[]> GPSDestLatitude { get; } = new ExifTag<Rational[]>(ExifTagValue.GPSDestLatitude);
/// <summary>
/// Gets the GPSDestLongitude exif tag.
/// </summary>
public static ExifTag<Rational[]> GPSDestLongitude { get; } = new ExifTag<Rational[]>(ExifTagValue.GPSDestLongitude);
}
}

239
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the OldSubfileType exif tag.
/// </summary>
public static ExifTag<ushort> OldSubfileType { get; } = new ExifTag<ushort>(ExifTagValue.OldSubfileType);
/// <summary>
/// Gets the Compression exif tag.
/// </summary>
public static ExifTag<ushort> Compression { get; } = new ExifTag<ushort>(ExifTagValue.Compression);
/// <summary>
/// Gets the PhotometricInterpretation exif tag.
/// </summary>
public static ExifTag<ushort> PhotometricInterpretation { get; } = new ExifTag<ushort>(ExifTagValue.PhotometricInterpretation);
/// <summary>
/// Gets the Thresholding exif tag.
/// </summary>
public static ExifTag<ushort> Thresholding { get; } = new ExifTag<ushort>(ExifTagValue.Thresholding);
/// <summary>
/// Gets the CellWidth exif tag.
/// </summary>
public static ExifTag<ushort> CellWidth { get; } = new ExifTag<ushort>(ExifTagValue.CellWidth);
/// <summary>
/// Gets the CellLength exif tag.
/// </summary>
public static ExifTag<ushort> CellLength { get; } = new ExifTag<ushort>(ExifTagValue.CellLength);
/// <summary>
/// Gets the FillOrder exif tag.
/// </summary>
public static ExifTag<ushort> FillOrder { get; } = new ExifTag<ushort>(ExifTagValue.FillOrder);
/// <summary>
/// Gets the Orientation exif tag.
/// </summary>
public static ExifTag<ushort> Orientation { get; } = new ExifTag<ushort>(ExifTagValue.Orientation);
/// <summary>
/// Gets the SamplesPerPixel exif tag.
/// </summary>
public static ExifTag<ushort> SamplesPerPixel { get; } = new ExifTag<ushort>(ExifTagValue.SamplesPerPixel);
/// <summary>
/// Gets the PlanarConfiguration exif tag.
/// </summary>
public static ExifTag<ushort> PlanarConfiguration { get; } = new ExifTag<ushort>(ExifTagValue.PlanarConfiguration);
/// <summary>
/// Gets the GrayResponseUnit exif tag.
/// </summary>
public static ExifTag<ushort> GrayResponseUnit { get; } = new ExifTag<ushort>(ExifTagValue.GrayResponseUnit);
/// <summary>
/// Gets the ResolutionUnit exif tag.
/// </summary>
public static ExifTag<ushort> ResolutionUnit { get; } = new ExifTag<ushort>(ExifTagValue.ResolutionUnit);
/// <summary>
/// Gets the CleanFaxData exif tag.
/// </summary>
public static ExifTag<ushort> CleanFaxData { get; } = new ExifTag<ushort>(ExifTagValue.CleanFaxData);
/// <summary>
/// Gets the InkSet exif tag.
/// </summary>
public static ExifTag<ushort> InkSet { get; } = new ExifTag<ushort>(ExifTagValue.InkSet);
/// <summary>
/// Gets the NumberOfInks exif tag.
/// </summary>
public static ExifTag<ushort> NumberOfInks { get; } = new ExifTag<ushort>(ExifTagValue.NumberOfInks);
/// <summary>
/// Gets the DotRange exif tag.
/// </summary>
public static ExifTag<ushort> DotRange { get; } = new ExifTag<ushort>(ExifTagValue.DotRange);
/// <summary>
/// Gets the Indexed exif tag.
/// </summary>
public static ExifTag<ushort> Indexed { get; } = new ExifTag<ushort>(ExifTagValue.Indexed);
/// <summary>
/// Gets the OPIProxy exif tag.
/// </summary>
public static ExifTag<ushort> OPIProxy { get; } = new ExifTag<ushort>(ExifTagValue.OPIProxy);
/// <summary>
/// Gets the JPEGProc exif tag.
/// </summary>
public static ExifTag<ushort> JPEGProc { get; } = new ExifTag<ushort>(ExifTagValue.JPEGProc);
/// <summary>
/// Gets the JPEGRestartInterval exif tag.
/// </summary>
public static ExifTag<ushort> JPEGRestartInterval { get; } = new ExifTag<ushort>(ExifTagValue.JPEGRestartInterval);
/// <summary>
/// Gets the YCbCrPositioning exif tag.
/// </summary>
public static ExifTag<ushort> YCbCrPositioning { get; } = new ExifTag<ushort>(ExifTagValue.YCbCrPositioning);
/// <summary>
/// Gets the Rating exif tag.
/// </summary>
public static ExifTag<ushort> Rating { get; } = new ExifTag<ushort>(ExifTagValue.Rating);
/// <summary>
/// Gets the RatingPercent exif tag.
/// </summary>
public static ExifTag<ushort> RatingPercent { get; } = new ExifTag<ushort>(ExifTagValue.RatingPercent);
/// <summary>
/// Gets the ExposureProgram exif tag.
/// </summary>
public static ExifTag<ushort> ExposureProgram { get; } = new ExifTag<ushort>(ExifTagValue.ExposureProgram);
/// <summary>
/// Gets the Interlace exif tag.
/// </summary>
public static ExifTag<ushort> Interlace { get; } = new ExifTag<ushort>(ExifTagValue.Interlace);
/// <summary>
/// Gets the SelfTimerMode exif tag.
/// </summary>
public static ExifTag<ushort> SelfTimerMode { get; } = new ExifTag<ushort>(ExifTagValue.SelfTimerMode);
/// <summary>
/// Gets the SensitivityType exif tag.
/// </summary>
public static ExifTag<ushort> SensitivityType { get; } = new ExifTag<ushort>(ExifTagValue.SensitivityType);
/// <summary>
/// Gets the MeteringMode exif tag.
/// </summary>
public static ExifTag<ushort> MeteringMode { get; } = new ExifTag<ushort>(ExifTagValue.MeteringMode);
/// <summary>
/// Gets the LightSource exif tag.
/// </summary>
public static ExifTag<ushort> LightSource { get; } = new ExifTag<ushort>(ExifTagValue.LightSource);
/// <summary>
/// Gets the FocalPlaneResolutionUnit2 exif tag.
/// </summary>
public static ExifTag<ushort> FocalPlaneResolutionUnit2 { get; } = new ExifTag<ushort>(ExifTagValue.FocalPlaneResolutionUnit2);
/// <summary>
/// Gets the SensingMethod2 exif tag.
/// </summary>
public static ExifTag<ushort> SensingMethod2 { get; } = new ExifTag<ushort>(ExifTagValue.SensingMethod2);
/// <summary>
/// Gets the Flash exif tag.
/// </summary>
public static ExifTag<ushort> Flash { get; } = new ExifTag<ushort>(ExifTagValue.Flash);
/// <summary>
/// Gets the ColorSpace exif tag.
/// </summary>
public static ExifTag<ushort> ColorSpace { get; } = new ExifTag<ushort>(ExifTagValue.ColorSpace);
/// <summary>
/// Gets the FocalPlaneResolutionUnit exif tag.
/// </summary>
public static ExifTag<ushort> FocalPlaneResolutionUnit { get; } = new ExifTag<ushort>(ExifTagValue.FocalPlaneResolutionUnit);
/// <summary>
/// Gets the SensingMethod exif tag.
/// </summary>
public static ExifTag<ushort> SensingMethod { get; } = new ExifTag<ushort>(ExifTagValue.SensingMethod);
/// <summary>
/// Gets the CustomRendered exif tag.
/// </summary>
public static ExifTag<ushort> CustomRendered { get; } = new ExifTag<ushort>(ExifTagValue.CustomRendered);
/// <summary>
/// Gets the ExposureMode exif tag.
/// </summary>
public static ExifTag<ushort> ExposureMode { get; } = new ExifTag<ushort>(ExifTagValue.ExposureMode);
/// <summary>
/// Gets the WhiteBalance exif tag.
/// </summary>
public static ExifTag<ushort> WhiteBalance { get; } = new ExifTag<ushort>(ExifTagValue.WhiteBalance);
/// <summary>
/// Gets the FocalLengthIn35mmFilm exif tag.
/// </summary>
public static ExifTag<ushort> FocalLengthIn35mmFilm { get; } = new ExifTag<ushort>(ExifTagValue.FocalLengthIn35mmFilm);
/// <summary>
/// Gets the SceneCaptureType exif tag.
/// </summary>
public static ExifTag<ushort> SceneCaptureType { get; } = new ExifTag<ushort>(ExifTagValue.SceneCaptureType);
/// <summary>
/// Gets the GainControl exif tag.
/// </summary>
public static ExifTag<ushort> GainControl { get; } = new ExifTag<ushort>(ExifTagValue.GainControl);
/// <summary>
/// Gets the Contrast exif tag.
/// </summary>
public static ExifTag<ushort> Contrast { get; } = new ExifTag<ushort>(ExifTagValue.Contrast);
/// <summary>
/// Gets the Saturation exif tag.
/// </summary>
public static ExifTag<ushort> Saturation { get; } = new ExifTag<ushort>(ExifTagValue.Saturation);
/// <summary>
/// Gets the Sharpness exif tag.
/// </summary>
public static ExifTag<ushort> Sharpness { get; } = new ExifTag<ushort>(ExifTagValue.Sharpness);
/// <summary>
/// Gets the SubjectDistanceRange exif tag.
/// </summary>
public static ExifTag<ushort> SubjectDistanceRange { get; } = new ExifTag<ushort>(ExifTagValue.SubjectDistanceRange);
/// <summary>
/// Gets the GPSDifferential exif tag.
/// </summary>
public static ExifTag<ushort> GPSDifferential { get; } = new ExifTag<ushort>(ExifTagValue.GPSDifferential);
}
}

114
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the BitsPerSample exif tag.
/// </summary>
public static ExifTag<ushort[]> BitsPerSample { get; } = new ExifTag<ushort[]>(ExifTagValue.BitsPerSample);
/// <summary>
/// Gets the MinSampleValue exif tag.
/// </summary>
public static ExifTag<ushort[]> MinSampleValue { get; } = new ExifTag<ushort[]>(ExifTagValue.MinSampleValue);
/// <summary>
/// Gets the MaxSampleValue exif tag.
/// </summary>
public static ExifTag<ushort[]> MaxSampleValue { get; } = new ExifTag<ushort[]>(ExifTagValue.MaxSampleValue);
/// <summary>
/// Gets the GrayResponseCurve exif tag.
/// </summary>
public static ExifTag<ushort[]> GrayResponseCurve { get; } = new ExifTag<ushort[]>(ExifTagValue.GrayResponseCurve);
/// <summary>
/// Gets the ColorMap exif tag.
/// </summary>
public static ExifTag<ushort[]> ColorMap { get; } = new ExifTag<ushort[]>(ExifTagValue.ColorMap);
/// <summary>
/// Gets the ExtraSamples exif tag.
/// </summary>
public static ExifTag<ushort[]> ExtraSamples { get; } = new ExifTag<ushort[]>(ExifTagValue.ExtraSamples);
/// <summary>
/// Gets the PageNumber exif tag.
/// </summary>
public static ExifTag<ushort[]> PageNumber { get; } = new ExifTag<ushort[]>(ExifTagValue.PageNumber);
/// <summary>
/// Gets the TransferFunction exif tag.
/// </summary>
public static ExifTag<ushort[]> TransferFunction { get; } = new ExifTag<ushort[]>(ExifTagValue.TransferFunction);
/// <summary>
/// Gets the Predictor exif tag.
/// </summary>
public static ExifTag<ushort[]> Predictor { get; } = new ExifTag<ushort[]>(ExifTagValue.Predictor);
/// <summary>
/// Gets the HalftoneHints exif tag.
/// </summary>
public static ExifTag<ushort[]> HalftoneHints { get; } = new ExifTag<ushort[]>(ExifTagValue.HalftoneHints);
/// <summary>
/// Gets the SampleFormat exif tag.
/// </summary>
public static ExifTag<ushort[]> SampleFormat { get; } = new ExifTag<ushort[]>(ExifTagValue.SampleFormat);
/// <summary>
/// Gets the TransferRange exif tag.
/// </summary>
public static ExifTag<ushort[]> TransferRange { get; } = new ExifTag<ushort[]>(ExifTagValue.TransferRange);
/// <summary>
/// Gets the DefaultImageColor exif tag.
/// </summary>
public static ExifTag<ushort[]> DefaultImageColor { get; } = new ExifTag<ushort[]>(ExifTagValue.DefaultImageColor);
/// <summary>
/// Gets the JPEGLosslessPredictors exif tag.
/// </summary>
public static ExifTag<ushort[]> JPEGLosslessPredictors { get; } = new ExifTag<ushort[]>(ExifTagValue.JPEGLosslessPredictors);
/// <summary>
/// Gets the JPEGPointTransforms exif tag.
/// </summary>
public static ExifTag<ushort[]> JPEGPointTransforms { get; } = new ExifTag<ushort[]>(ExifTagValue.JPEGPointTransforms);
/// <summary>
/// Gets the YCbCrSubsampling exif tag.
/// </summary>
public static ExifTag<ushort[]> YCbCrSubsampling { get; } = new ExifTag<ushort[]>(ExifTagValue.YCbCrSubsampling);
/// <summary>
/// Gets the CFARepeatPatternDim exif tag.
/// </summary>
public static ExifTag<ushort[]> CFARepeatPatternDim { get; } = new ExifTag<ushort[]>(ExifTagValue.CFARepeatPatternDim);
/// <summary>
/// Gets the IntergraphPacketData exif tag.
/// </summary>
public static ExifTag<ushort[]> IntergraphPacketData { get; } = new ExifTag<ushort[]>(ExifTagValue.IntergraphPacketData);
/// <summary>
/// Gets the ISOSpeedRatings exif tag.
/// </summary>
public static ExifTag<ushort[]> ISOSpeedRatings { get; } = new ExifTag<ushort[]>(ExifTagValue.ISOSpeedRatings);
/// <summary>
/// Gets the SubjectArea exif tag.
/// </summary>
public static ExifTag<ushort[]> SubjectArea { get; } = new ExifTag<ushort[]>(ExifTagValue.SubjectArea);
/// <summary>
/// Gets the SubjectLocation exif tag.
/// </summary>
public static ExifTag<ushort[]> SubjectLocation { get; } = new ExifTag<ushort[]>(ExifTagValue.SubjectLocation);
}
}

41
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the ShutterSpeedValue exif tag.
/// </summary>
public static ExifTag<SignedRational> ShutterSpeedValue { get; } = new ExifTag<SignedRational>(ExifTagValue.ShutterSpeedValue);
/// <summary>
/// Gets the BrightnessValue exif tag.
/// </summary>
public static ExifTag<SignedRational> BrightnessValue { get; } = new ExifTag<SignedRational>(ExifTagValue.BrightnessValue);
/// <summary>
/// Gets the ExposureBiasValue exif tag.
/// </summary>
public static ExifTag<SignedRational> ExposureBiasValue { get; } = new ExifTag<SignedRational>(ExifTagValue.ExposureBiasValue);
/// <summary>
/// Gets the AmbientTemperature exif tag.
/// </summary>
public static ExifTag<SignedRational> AmbientTemperature { get; } = new ExifTag<SignedRational>(ExifTagValue.AmbientTemperature);
/// <summary>
/// Gets the WaterDepth exif tag.
/// </summary>
public static ExifTag<SignedRational> WaterDepth { get; } = new ExifTag<SignedRational>(ExifTagValue.WaterDepth);
/// <summary>
/// Gets the CameraElevationAngle exif tag.
/// </summary>
public static ExifTag<SignedRational> CameraElevationAngle { get; } = new ExifTag<SignedRational>(ExifTagValue.CameraElevationAngle);
}
}

16
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the Decode exif tag.
/// </summary>
public static ExifTag<SignedRational[]> Decode { get; } = new ExifTag<SignedRational[]>(ExifTagValue.Decode);
}
}

279
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the ImageDescription exif tag.
/// </summary>
public static ExifTag<string> ImageDescription { get; } = new ExifTag<string>(ExifTagValue.ImageDescription);
/// <summary>
/// Gets the Make exif tag.
/// </summary>
public static ExifTag<string> Make { get; } = new ExifTag<string>(ExifTagValue.Make);
/// <summary>
/// Gets the Model exif tag.
/// </summary>
public static ExifTag<string> Model { get; } = new ExifTag<string>(ExifTagValue.Model);
/// <summary>
/// Gets the Software exif tag.
/// </summary>
public static ExifTag<string> Software { get; } = new ExifTag<string>(ExifTagValue.Software);
/// <summary>
/// Gets the DateTime exif tag.
/// </summary>
public static ExifTag<string> DateTime { get; } = new ExifTag<string>(ExifTagValue.DateTime);
/// <summary>
/// Gets the Artist exif tag.
/// </summary>
public static ExifTag<string> Artist { get; } = new ExifTag<string>(ExifTagValue.Artist);
/// <summary>
/// Gets the HostComputer exif tag.
/// </summary>
public static ExifTag<string> HostComputer { get; } = new ExifTag<string>(ExifTagValue.HostComputer);
/// <summary>
/// Gets the Copyright exif tag.
/// </summary>
public static ExifTag<string> Copyright { get; } = new ExifTag<string>(ExifTagValue.Copyright);
/// <summary>
/// Gets the DocumentName exif tag.
/// </summary>
public static ExifTag<string> DocumentName { get; } = new ExifTag<string>(ExifTagValue.DocumentName);
/// <summary>
/// Gets the PageName exif tag.
/// </summary>
public static ExifTag<string> PageName { get; } = new ExifTag<string>(ExifTagValue.PageName);
/// <summary>
/// Gets the InkNames exif tag.
/// </summary>
public static ExifTag<string> InkNames { get; } = new ExifTag<string>(ExifTagValue.InkNames);
/// <summary>
/// Gets the TargetPrinter exif tag.
/// </summary>
public static ExifTag<string> TargetPrinter { get; } = new ExifTag<string>(ExifTagValue.TargetPrinter);
/// <summary>
/// Gets the ImageID exif tag.
/// </summary>
public static ExifTag<string> ImageID { get; } = new ExifTag<string>(ExifTagValue.ImageID);
/// <summary>
/// Gets the MDLabName exif tag.
/// </summary>
public static ExifTag<string> MDLabName { get; } = new ExifTag<string>(ExifTagValue.MDLabName);
/// <summary>
/// Gets the MDSampleInfo exif tag.
/// </summary>
public static ExifTag<string> MDSampleInfo { get; } = new ExifTag<string>(ExifTagValue.MDSampleInfo);
/// <summary>
/// Gets the MDPrepDate exif tag.
/// </summary>
public static ExifTag<string> MDPrepDate { get; } = new ExifTag<string>(ExifTagValue.MDPrepDate);
/// <summary>
/// Gets the MDPrepTime exif tag.
/// </summary>
public static ExifTag<string> MDPrepTime { get; } = new ExifTag<string>(ExifTagValue.MDPrepTime);
/// <summary>
/// Gets the MDFileUnits exif tag.
/// </summary>
public static ExifTag<string> MDFileUnits => new ExifTag<string>(ExifTagValue.MDFileUnits);
/// <summary>
/// Gets the SEMInfo exif tag.
/// </summary>
public static ExifTag<string> SEMInfo { get; } = new ExifTag<string>(ExifTagValue.SEMInfo);
/// <summary>
/// Gets the SpectralSensitivity exif tag.
/// </summary>
public static ExifTag<string> SpectralSensitivity { get; } = new ExifTag<string>(ExifTagValue.SpectralSensitivity);
/// <summary>
/// Gets the DateTimeOriginal exif tag.
/// </summary>
public static ExifTag<string> DateTimeOriginal { get; } = new ExifTag<string>(ExifTagValue.DateTimeOriginal);
/// <summary>
/// Gets the DateTimeDigitized exif tag.
/// </summary>
public static ExifTag<string> DateTimeDigitized { get; } = new ExifTag<string>(ExifTagValue.DateTimeDigitized);
/// <summary>
/// Gets the SubsecTime exif tag.
/// </summary>
public static ExifTag<string> SubsecTime { get; } = new ExifTag<string>(ExifTagValue.SubsecTime);
/// <summary>
/// Gets the SubsecTimeOriginal exif tag.
/// </summary>
public static ExifTag<string> SubsecTimeOriginal { get; } = new ExifTag<string>(ExifTagValue.SubsecTimeOriginal);
/// <summary>
/// Gets the SubsecTimeDigitized exif tag.
/// </summary>
public static ExifTag<string> SubsecTimeDigitized { get; } = new ExifTag<string>(ExifTagValue.SubsecTimeDigitized);
/// <summary>
/// Gets the RelatedSoundFile exif tag.
/// </summary>
public static ExifTag<string> RelatedSoundFile { get; } = new ExifTag<string>(ExifTagValue.RelatedSoundFile);
/// <summary>
/// Gets the FaxSubaddress exif tag.
/// </summary>
public static ExifTag<string> FaxSubaddress { get; } = new ExifTag<string>(ExifTagValue.FaxSubaddress);
/// <summary>
/// Gets the OffsetTime exif tag.
/// </summary>
public static ExifTag<string> OffsetTime { get; } = new ExifTag<string>(ExifTagValue.OffsetTime);
/// <summary>
/// Gets the OffsetTimeOriginal exif tag.
/// </summary>
public static ExifTag<string> OffsetTimeOriginal { get; } = new ExifTag<string>(ExifTagValue.OffsetTimeOriginal);
/// <summary>
/// Gets the OffsetTimeDigitized exif tag.
/// </summary>
public static ExifTag<string> OffsetTimeDigitized { get; } = new ExifTag<string>(ExifTagValue.OffsetTimeDigitized);
/// <summary>
/// Gets the SecurityClassification exif tag.
/// </summary>
public static ExifTag<string> SecurityClassification { get; } = new ExifTag<string>(ExifTagValue.SecurityClassification);
/// <summary>
/// Gets the ImageHistory exif tag.
/// </summary>
public static ExifTag<string> ImageHistory { get; } = new ExifTag<string>(ExifTagValue.ImageHistory);
/// <summary>
/// Gets the ImageUniqueID exif tag.
/// </summary>
public static ExifTag<string> ImageUniqueID { get; } = new ExifTag<string>(ExifTagValue.ImageUniqueID);
/// <summary>
/// Gets the OwnerName exif tag.
/// </summary>
public static ExifTag<string> OwnerName { get; } = new ExifTag<string>(ExifTagValue.OwnerName);
/// <summary>
/// Gets the SerialNumber exif tag.
/// </summary>
public static ExifTag<string> SerialNumber { get; } = new ExifTag<string>(ExifTagValue.SerialNumber);
/// <summary>
/// Gets the LensMake exif tag.
/// </summary>
public static ExifTag<string> LensMake { get; } = new ExifTag<string>(ExifTagValue.LensMake);
/// <summary>
/// Gets the LensModel exif tag.
/// </summary>
public static ExifTag<string> LensModel { get; } = new ExifTag<string>(ExifTagValue.LensModel);
/// <summary>
/// Gets the LensSerialNumber exif tag.
/// </summary>
public static ExifTag<string> LensSerialNumber { get; } = new ExifTag<string>(ExifTagValue.LensSerialNumber);
/// <summary>
/// Gets the GDALMetadata exif tag.
/// </summary>
public static ExifTag<string> GDALMetadata { get; } = new ExifTag<string>(ExifTagValue.GDALMetadata);
/// <summary>
/// Gets the GDALNoData exif tag.
/// </summary>
public static ExifTag<string> GDALNoData { get; } = new ExifTag<string>(ExifTagValue.GDALNoData);
/// <summary>
/// Gets the GPSLatitudeRef exif tag.
/// </summary>
public static ExifTag<string> GPSLatitudeRef { get; } = new ExifTag<string>(ExifTagValue.GPSLatitudeRef);
/// <summary>
/// Gets the GPSLongitudeRef exif tag.
/// </summary>
public static ExifTag<string> GPSLongitudeRef { get; } = new ExifTag<string>(ExifTagValue.GPSLongitudeRef);
/// <summary>
/// Gets the GPSSatellites exif tag.
/// </summary>
public static ExifTag<string> GPSSatellites { get; } = new ExifTag<string>(ExifTagValue.GPSSatellites);
/// <summary>
/// Gets the GPSStatus exif tag.
/// </summary>
public static ExifTag<string> GPSStatus { get; } = new ExifTag<string>(ExifTagValue.GPSStatus);
/// <summary>
/// Gets the GPSMeasureMode exif tag.
/// </summary>
public static ExifTag<string> GPSMeasureMode { get; } = new ExifTag<string>(ExifTagValue.GPSMeasureMode);
/// <summary>
/// Gets the GPSSpeedRef exif tag.
/// </summary>
public static ExifTag<string> GPSSpeedRef { get; } = new ExifTag<string>(ExifTagValue.GPSSpeedRef);
/// <summary>
/// Gets the GPSTrackRef exif tag.
/// </summary>
public static ExifTag<string> GPSTrackRef { get; } = new ExifTag<string>(ExifTagValue.GPSTrackRef);
/// <summary>
/// Gets the GPSImgDirectionRef exif tag.
/// </summary>
public static ExifTag<string> GPSImgDirectionRef { get; } = new ExifTag<string>(ExifTagValue.GPSImgDirectionRef);
/// <summary>
/// Gets the GPSMapDatum exif tag.
/// </summary>
public static ExifTag<string> GPSMapDatum { get; } = new ExifTag<string>(ExifTagValue.GPSMapDatum);
/// <summary>
/// Gets the GPSDestLatitudeRef exif tag.
/// </summary>
public static ExifTag<string> GPSDestLatitudeRef { get; } = new ExifTag<string>(ExifTagValue.GPSDestLatitudeRef);
/// <summary>
/// Gets the GPSDestLongitudeRef exif tag.
/// </summary>
public static ExifTag<string> GPSDestLongitudeRef { get; } = new ExifTag<string>(ExifTagValue.GPSDestLongitudeRef);
/// <summary>
/// Gets the GPSDestBearingRef exif tag.
/// </summary>
public static ExifTag<string> GPSDestBearingRef { get; } = new ExifTag<string>(ExifTagValue.GPSDestBearingRef);
/// <summary>
/// Gets the GPSDestDistanceRef exif tag.
/// </summary>
public static ExifTag<string> GPSDestDistanceRef { get; } = new ExifTag<string>(ExifTagValue.GPSDestDistanceRef);
/// <summary>
/// Gets the GPSDateStamp exif tag.
/// </summary>
public static ExifTag<string> GPSDateStamp { get; } = new ExifTag<string>(ExifTagValue.GPSDateStamp);
}
}

94
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
{
/// <content/>
public abstract partial class ExifTag
{
/// <summary>
/// Gets the JPEGTables exif tag.
/// </summary>
public static ExifTag<byte[]> JPEGTables { get; } = new ExifTag<byte[]>(ExifTagValue.JPEGTables);
/// <summary>
/// Gets the OECF exif tag.
/// </summary>
public static ExifTag<byte[]> OECF { get; } = new ExifTag<byte[]>(ExifTagValue.OECF);
/// <summary>
/// Gets the ExifVersion exif tag.
/// </summary>
public static ExifTag<byte[]> ExifVersion { get; } = new ExifTag<byte[]>(ExifTagValue.ExifVersion);
/// <summary>
/// Gets the ComponentsConfiguration exif tag.
/// </summary>
public static ExifTag<byte[]> ComponentsConfiguration { get; } = new ExifTag<byte[]>(ExifTagValue.ComponentsConfiguration);
/// <summary>
/// Gets the MakerNote exif tag.
/// </summary>
public static ExifTag<byte[]> MakerNote { get; } = new ExifTag<byte[]>(ExifTagValue.MakerNote);
/// <summary>
/// Gets the UserComment exif tag.
/// </summary>
public static ExifTag<byte[]> UserComment { get; } = new ExifTag<byte[]>(ExifTagValue.UserComment);
/// <summary>
/// Gets the FlashpixVersion exif tag.
/// </summary>
public static ExifTag<byte[]> FlashpixVersion { get; } = new ExifTag<byte[]>(ExifTagValue.FlashpixVersion);
/// <summary>
/// Gets the SpatialFrequencyResponse exif tag.
/// </summary>
public static ExifTag<byte[]> SpatialFrequencyResponse { get; } = new ExifTag<byte[]>(ExifTagValue.SpatialFrequencyResponse);
/// <summary>
/// Gets the SpatialFrequencyResponse2 exif tag.
/// </summary>
public static ExifTag<byte[]> SpatialFrequencyResponse2 { get; } = new ExifTag<byte[]>(ExifTagValue.SpatialFrequencyResponse2);
/// <summary>
/// Gets the Noise exif tag.
/// </summary>
public static ExifTag<byte[]> Noise { get; } = new ExifTag<byte[]>(ExifTagValue.Noise);
/// <summary>
/// Gets the CFAPattern exif tag.
/// </summary>
public static ExifTag<byte[]> CFAPattern { get; } = new ExifTag<byte[]>(ExifTagValue.CFAPattern);
/// <summary>
/// Gets the DeviceSettingDescription exif tag.
/// </summary>
public static ExifTag<byte[]> DeviceSettingDescription { get; } = new ExifTag<byte[]>(ExifTagValue.DeviceSettingDescription);
/// <summary>
/// Gets the ImageSourceData exif tag.
/// </summary>
public static ExifTag<byte[]> ImageSourceData { get; } = new ExifTag<byte[]>(ExifTagValue.ImageSourceData);
/// <summary>
/// Gets the GPSProcessingMethod exif tag.
/// </summary>
public static ExifTag<byte[]> GPSProcessingMethod { get; } = new ExifTag<byte[]>(ExifTagValue.GPSProcessingMethod);
/// <summary>
/// Gets the GPSAreaInformation exif tag.
/// </summary>
public static ExifTag<byte[]> GPSAreaInformation { get; } = new ExifTag<byte[]>(ExifTagValue.GPSAreaInformation);
/// <summary>
/// Gets the FileSource exif tag.
/// </summary>
public static ExifTag<byte> FileSource { get; } = new ExifTag<byte>(ExifTagValue.FileSource);
/// <summary>
/// Gets the ImageDescription exif tag.
/// </summary>
public static ExifTag<byte> SceneType { get; } = new ExifTag<byte>(ExifTagValue.SceneType);
}
}

70
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
{
/// <summary>
/// Class that represents an exif tag from the Exif standard 2.31.
/// </summary>
public abstract partial class ExifTag : IEquatable<ExifTag>
{
private readonly ushort value;
internal ExifTag(ushort value) => this.value = value;
/// <summary>
/// Converts the specified <see cref="ExifTag"/> to a <see cref="ushort"/>.
/// </summary>
/// <param name="tag">The <see cref="ExifTag"/> to convert.</param>
public static explicit operator ushort(ExifTag tag) => tag?.value ?? (ushort)ExifTagValue.Unknown;
/// <summary>
/// Determines whether the specified <see cref="ExifTag"/> instances are considered equal.
/// </summary>
/// <param name="left">The first <see cref="ExifTag"/> to compare.</param>
/// <param name="right"> The second <see cref="ExifTag"/> to compare.</param>
public static bool operator ==(ExifTag left, ExifTag right) => Equals(left, right);
/// <summary>
/// Determines whether the specified <see cref="ExifTag"/> instances are not considered equal.
/// </summary>
/// <param name="left">The first <see cref="ExifTag"/> to compare.</param>
/// <param name="right"> The second <see cref="ExifTag"/> to compare.</param>
public static bool operator !=(ExifTag left, ExifTag right) => !Equals(left, right);
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj is ExifTag value)
{
return this.Equals(value);
}
return false;
}
/// <inheritdoc/>
public bool Equals(ExifTag other)
{
if (other is null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return this.value == other.value;
}
/// <inheritdoc/>
public override int GetHashCode() => this.value.GetHashCode();
/// <inheritdoc/>
public override string ToString() => ((ExifTagValue)this.value).ToString();
}
}

11
src/ImageSharp/MetaData/Profiles/Exif/ExifTag.cs → 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
{
/// <summary>
/// All exif tags from the Exif standard 2.2
/// Descriptions from: <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html"/>
/// All exif tags from the Exif standard 2.31.
/// </summary>
public enum ExifTag
internal enum ExifTagValue
{
/// <summary>
/// Unknown
@ -1539,6 +1538,6 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// <summary>
/// GPSDifferential
/// </summary>
GPSDifferential = 0x001E
GPSDifferential = 0x001E,
}
}
}

17
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
{
/// <summary>
/// Class that represents an exif tag from the Exif standard 2.31 with <typeparamref name="TValueType"/> as the data type of the tag.
/// </summary>
/// <typeparam name="TValueType">The data type of the tag.</typeparam>
public sealed class ExifTag<TValueType> : ExifTag
{
internal ExifTag(ExifTagValue value)
: base((ushort)value)
{
}
}
}

13
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)
{
}
}
}

55
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<TValueType> : ExifValue, IExifValue<TValueType[]>
{
protected ExifArrayValue(ExifTag<TValueType[]> tag)
: base(tag)
{
}
protected ExifArrayValue(ExifTagValue tag)
: base(tag)
{
}
internal ExifArrayValue(ExifArrayValue<TValueType> 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;
}
}
}

47
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<byte>
{
public ExifByte(ExifTag<byte> 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);
}
}

66
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<byte>
{
public ExifByteArray(ExifTag<byte[]> 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;
}
}
}

48
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<double>
{
public ExifDouble(ExifTag<double> 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);
}
}

27
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<double>
{
public ExifDoubleArray(ExifTag<double[]> 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);
}
}

43
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<float>
{
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);
}
}

22
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<float>
{
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);
}
}

53
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<uint>
{
public ExifLong(ExifTag<uint> 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);
}
}

27
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<uint>
{
public ExifLongArray(ExifTag<uint[]> 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);
}
}

74
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<Number>
{
public ExifNumber(ExifTag<Number> 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);
}
}

43
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<Number>
{
public ExifNumberArray(ExifTag<Number[]> 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);
}
}

54
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<Rational>
{
public ExifRational(ExifTag<Rational> 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);
}
}

73
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<Rational>
{
public ExifRationalArray(ExifTag<Rational[]> 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;
}
}
}

61
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<ushort>
{
public ExifShort(ExifTag<ushort> 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);
}
}

105
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<ushort>
{
public ExifShortArray(ExifTag<ushort[]> 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;
}
}
}

48
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<sbyte>
{
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);
}
}

22
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<sbyte>
{
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);
}
}

26
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<int>
{
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);
}
}

22
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<int>
{
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);
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save