mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
431 changed files with 5390 additions and 3626 deletions
@ -0,0 +1,105 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
using SixLabors.ImageSharp.Memory; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Primitives; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Extension methods for <see cref="Buffer2D{T}"/>.
|
||||
|
/// TODO: One day rewrite all this to use SIMD intrinsics. There's a lot of scope for improvement.
|
||||
|
/// </summary>
|
||||
|
internal static class Buffer2DUtils |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Computes the sum of vectors in <paramref name="targetRow"/> weighted by the kernel weight values.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
||||
|
/// <param name="kernel">The 1D convolution kernel.</param>
|
||||
|
/// <param name="sourcePixels">The source frame.</param>
|
||||
|
/// <param name="targetRow">The target row.</param>
|
||||
|
/// <param name="row">The current row.</param>
|
||||
|
/// <param name="column">The current column.</param>
|
||||
|
/// <param name="minRow">The minimum working area row.</param>
|
||||
|
/// <param name="maxRow">The maximum working area row.</param>
|
||||
|
/// <param name="minColumn">The minimum working area column.</param>
|
||||
|
/// <param name="maxColumn">The maximum working area column.</param>
|
||||
|
public static void Convolve4<TPixel>( |
||||
|
Span<Complex64> kernel, |
||||
|
Buffer2D<TPixel> sourcePixels, |
||||
|
Span<ComplexVector4> targetRow, |
||||
|
int row, |
||||
|
int column, |
||||
|
int minRow, |
||||
|
int maxRow, |
||||
|
int minColumn, |
||||
|
int maxColumn) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
ComplexVector4 vector = default; |
||||
|
int kernelLength = kernel.Length; |
||||
|
int radiusY = kernelLength >> 1; |
||||
|
int sourceOffsetColumnBase = column + minColumn; |
||||
|
ref Complex64 baseRef = ref MemoryMarshal.GetReference(kernel); |
||||
|
|
||||
|
for (int i = 0; i < kernelLength; i++) |
||||
|
{ |
||||
|
int offsetY = (row + i - radiusY).Clamp(minRow, maxRow); |
||||
|
int offsetX = sourceOffsetColumnBase.Clamp(minColumn, maxColumn); |
||||
|
Span<TPixel> sourceRowSpan = sourcePixels.GetRowSpan(offsetY); |
||||
|
var currentColor = sourceRowSpan[offsetX].ToVector4(); |
||||
|
|
||||
|
vector.Sum(Unsafe.Add(ref baseRef, i) * currentColor); |
||||
|
} |
||||
|
|
||||
|
targetRow[column] = vector; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Computes the sum of vectors in <paramref name="targetRow"/> weighted by the kernel weight values.
|
||||
|
/// </summary>
|
||||
|
/// <param name="kernel">The 1D convolution kernel.</param>
|
||||
|
/// <param name="sourceValues">The source frame.</param>
|
||||
|
/// <param name="targetRow">The target row.</param>
|
||||
|
/// <param name="row">The current row.</param>
|
||||
|
/// <param name="column">The current column.</param>
|
||||
|
/// <param name="minRow">The minimum working area row.</param>
|
||||
|
/// <param name="maxRow">The maximum working area row.</param>
|
||||
|
/// <param name="minColumn">The minimum working area column.</param>
|
||||
|
/// <param name="maxColumn">The maximum working area column.</param>
|
||||
|
public static void Convolve4( |
||||
|
Span<Complex64> kernel, |
||||
|
Buffer2D<ComplexVector4> sourceValues, |
||||
|
Span<ComplexVector4> targetRow, |
||||
|
int row, |
||||
|
int column, |
||||
|
int minRow, |
||||
|
int maxRow, |
||||
|
int minColumn, |
||||
|
int maxColumn) |
||||
|
{ |
||||
|
ComplexVector4 vector = default; |
||||
|
int kernelLength = kernel.Length; |
||||
|
int radiusX = kernelLength >> 1; |
||||
|
int sourceOffsetColumnBase = column + minColumn; |
||||
|
|
||||
|
int offsetY = row.Clamp(minRow, maxRow); |
||||
|
ref ComplexVector4 sourceRef = ref MemoryMarshal.GetReference(sourceValues.GetRowSpan(offsetY)); |
||||
|
ref Complex64 baseRef = ref MemoryMarshal.GetReference(kernel); |
||||
|
|
||||
|
for (int x = 0; x < kernelLength; x++) |
||||
|
{ |
||||
|
int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(minColumn, maxColumn); |
||||
|
vector.Sum(Unsafe.Add(ref baseRef, x) * Unsafe.Add(ref sourceRef, offsetX)); |
||||
|
} |
||||
|
|
||||
|
targetRow[column] = vector; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
File diff suppressed because it is too large
@ -0,0 +1,57 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Png |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The helper methods for <see cref="PngEncoderCore"/> class.
|
||||
|
/// </summary>
|
||||
|
internal static class PngEncoderHelpers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Packs the given 8 bit array into and array of <paramref name="bits"/> depths.
|
||||
|
/// </summary>
|
||||
|
/// <param name="source">The source span in 8 bits.</param>
|
||||
|
/// <param name="result">The resultant span in <paramref name="bits"/>.</param>
|
||||
|
/// <param name="bits">The bit depth.</param>
|
||||
|
/// <param name="scale">The scaling factor.</param>
|
||||
|
public static void ScaleDownFrom8BitArray(ReadOnlySpan<byte> source, Span<byte> result, int bits, float scale = 1) |
||||
|
{ |
||||
|
ref byte sourceRef = ref MemoryMarshal.GetReference(source); |
||||
|
ref byte resultRef = ref MemoryMarshal.GetReference(result); |
||||
|
|
||||
|
int shift = 8 - bits; |
||||
|
byte mask = (byte)(0xFF >> shift); |
||||
|
byte shift0 = (byte)shift; |
||||
|
int v = 0; |
||||
|
int resultOffset = 0; |
||||
|
|
||||
|
for (int i = 0; i < source.Length; i++) |
||||
|
{ |
||||
|
int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask; |
||||
|
v |= value << shift; |
||||
|
|
||||
|
if (shift == 0) |
||||
|
{ |
||||
|
shift = shift0; |
||||
|
Unsafe.Add(ref resultRef, resultOffset) = (byte)v; |
||||
|
resultOffset++; |
||||
|
v = 0; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
shift -= bits; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (shift != shift0) |
||||
|
{ |
||||
|
Unsafe.Add(ref resultRef, resultOffset) = (byte)v; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Png |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The options structure for the <see cref="PngEncoderCore"/>.
|
||||
|
/// </summary>
|
||||
|
internal class PngEncoderOptions : IPngEncoderOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="PngEncoderOptions"/> class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="source">The source.</param>
|
||||
|
public PngEncoderOptions(IPngEncoderOptions source) |
||||
|
{ |
||||
|
this.BitDepth = source.BitDepth; |
||||
|
this.ColorType = source.ColorType; |
||||
|
|
||||
|
// Specification recommends default filter method None for paletted images and Paeth for others.
|
||||
|
this.FilterMethod = source.FilterMethod ?? (source.ColorType == PngColorType.Palette |
||||
|
? PngFilterMethod.None |
||||
|
: PngFilterMethod.Paeth); |
||||
|
this.CompressionLevel = source.CompressionLevel; |
||||
|
this.TextCompressionThreshold = source.TextCompressionThreshold; |
||||
|
this.Gamma = source.Gamma; |
||||
|
this.Quantizer = source.Quantizer; |
||||
|
this.Threshold = source.Threshold; |
||||
|
this.InterlaceMethod = source.InterlaceMethod; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the number of bits per sample or per palette index (not per pixel).
|
||||
|
/// Not all values are allowed for all <see cref="P:SixLabors.ImageSharp.Formats.Png.IPngEncoderOptions.ColorType" /> values.
|
||||
|
/// </summary>
|
||||
|
public PngBitDepth? BitDepth { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the color type.
|
||||
|
/// </summary>
|
||||
|
public PngColorType? ColorType { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the filter method.
|
||||
|
/// </summary>
|
||||
|
public PngFilterMethod? FilterMethod { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the compression level 1-9.
|
||||
|
/// <remarks>Defaults to 6.</remarks>
|
||||
|
/// </summary>
|
||||
|
public int CompressionLevel { get; } |
||||
|
|
||||
|
/// <inheritdoc/>
|
||||
|
public int TextCompressionThreshold { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the gamma value, that will be written the image.
|
||||
|
/// </summary>
|
||||
|
/// <value>
|
||||
|
/// The gamma value of the image.
|
||||
|
/// </value>
|
||||
|
public float? Gamma { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the quantizer for reducing the color count.
|
||||
|
/// </summary>
|
||||
|
public IQuantizer Quantizer { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the transparency threshold.
|
||||
|
/// </summary>
|
||||
|
public byte Threshold { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets a value indicating whether this instance should write an Adam7 interlaced image.
|
||||
|
/// </summary>
|
||||
|
public PngInterlaceMode? InterlaceMethod { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,152 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using SixLabors.ImageSharp.Advanced; |
||||
|
using SixLabors.ImageSharp.PixelFormats; |
||||
|
using SixLabors.ImageSharp.Processing.Processors.Quantization; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Png |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// The helper methods for the PNG encoder options.
|
||||
|
/// </summary>
|
||||
|
internal static class PngEncoderOptionsHelpers |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Adjusts the options.
|
||||
|
/// </summary>
|
||||
|
/// <param name="options">The options.</param>
|
||||
|
/// <param name="pngMetadata">The PNG metadata.</param>
|
||||
|
/// <param name="use16Bit">if set to <c>true</c> [use16 bit].</param>
|
||||
|
/// <param name="bytesPerPixel">The bytes per pixel.</param>
|
||||
|
public static void AdjustOptions( |
||||
|
PngEncoderOptions options, |
||||
|
PngMetadata pngMetadata, |
||||
|
out bool use16Bit, |
||||
|
out int bytesPerPixel) |
||||
|
{ |
||||
|
// Always take the encoder options over the metadata values.
|
||||
|
options.Gamma = options.Gamma ?? pngMetadata.Gamma; |
||||
|
options.ColorType = options.ColorType ?? pngMetadata.ColorType; |
||||
|
options.BitDepth = options.BitDepth ?? pngMetadata.BitDepth; |
||||
|
options.InterlaceMethod = options.InterlaceMethod ?? pngMetadata.InterlaceMethod; |
||||
|
|
||||
|
use16Bit = options.BitDepth == PngBitDepth.Bit16; |
||||
|
bytesPerPixel = CalculateBytesPerPixel(options.ColorType, use16Bit); |
||||
|
|
||||
|
// Ensure we are not allowing impossible combinations.
|
||||
|
if (!PngConstants.ColorTypes.ContainsKey(options.ColorType.Value)) |
||||
|
{ |
||||
|
throw new NotSupportedException("Color type is not supported or not valid."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates the quantized frame.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
||||
|
/// <param name="options">The options.</param>
|
||||
|
/// <param name="image">The image.</param>
|
||||
|
public static IQuantizedFrame<TPixel> CreateQuantizedFrame<TPixel>( |
||||
|
PngEncoderOptions options, |
||||
|
Image<TPixel> image) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
if (options.ColorType != PngColorType.Palette) |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
byte bits = (byte)options.BitDepth; |
||||
|
if (Array.IndexOf(PngConstants.ColorTypes[options.ColorType.Value], bits) == -1) |
||||
|
{ |
||||
|
throw new NotSupportedException("Bit depth is not supported or not valid."); |
||||
|
} |
||||
|
|
||||
|
// Use the metadata to determine what quantization depth to use if no quantizer has been set.
|
||||
|
if (options.Quantizer is null) |
||||
|
{ |
||||
|
options.Quantizer = new WuQuantizer(ImageMaths.GetColorCountForBitDepth(bits)); |
||||
|
} |
||||
|
|
||||
|
// Create quantized frame returning the palette and set the bit depth.
|
||||
|
using (IFrameQuantizer<TPixel> frameQuantizer = options.Quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())) |
||||
|
{ |
||||
|
return frameQuantizer.QuantizeFrame(image.Frames.RootFrame); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Calculates the bit depth value.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TPixel">The type of the pixel.</typeparam>
|
||||
|
/// <param name="options">The options.</param>
|
||||
|
/// <param name="image">The image.</param>
|
||||
|
/// <param name="quantizedFrame">The quantized frame.</param>
|
||||
|
public static byte CalculateBitDepth<TPixel>( |
||||
|
PngEncoderOptions options, |
||||
|
Image<TPixel> image, |
||||
|
IQuantizedFrame<TPixel> quantizedFrame) |
||||
|
where TPixel : struct, IPixel<TPixel> |
||||
|
{ |
||||
|
byte bitDepth; |
||||
|
if (options.ColorType == PngColorType.Palette) |
||||
|
{ |
||||
|
byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantizedFrame.Palette.Length).Clamp(1, 8); |
||||
|
byte bits = Math.Max((byte)options.BitDepth, quantizedBits); |
||||
|
|
||||
|
// Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk
|
||||
|
// We check again for the bit depth as the bit depth of the color palette from a given quantizer might not
|
||||
|
// be within the acceptable range.
|
||||
|
if (bits == 3) |
||||
|
{ |
||||
|
bits = 4; |
||||
|
} |
||||
|
else if (bits >= 5 && bits <= 7) |
||||
|
{ |
||||
|
bits = 8; |
||||
|
} |
||||
|
|
||||
|
bitDepth = bits; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
bitDepth = (byte)options.BitDepth; |
||||
|
} |
||||
|
|
||||
|
if (Array.IndexOf(PngConstants.ColorTypes[options.ColorType.Value], bitDepth) == -1) |
||||
|
{ |
||||
|
throw new NotSupportedException("Bit depth is not supported or not valid."); |
||||
|
} |
||||
|
|
||||
|
return bitDepth; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Calculates the correct number of bytes per pixel for the given color type.
|
||||
|
/// </summary>
|
||||
|
/// <returns>Bytes per pixel.</returns>
|
||||
|
private static int CalculateBytesPerPixel(PngColorType? pngColorType, bool use16Bit) |
||||
|
{ |
||||
|
switch (pngColorType) |
||||
|
{ |
||||
|
case PngColorType.Grayscale: |
||||
|
return use16Bit ? 2 : 1; |
||||
|
|
||||
|
case PngColorType.GrayscaleWithAlpha: |
||||
|
return use16Bit ? 4 : 2; |
||||
|
|
||||
|
case PngColorType.Palette: |
||||
|
return 1; |
||||
|
|
||||
|
case PngColorType.Rgb: |
||||
|
return use16Bit ? 6 : 3; |
||||
|
|
||||
|
// PngColorType.RgbWithAlpha
|
||||
|
default: |
||||
|
return use16Bit ? 8 : 4; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,143 @@ |
|||||
|
// Copyright (c) Six Labors and contributors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Png |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Stores text data contained in the iTXt, tEXt, and zTXt chunks.
|
||||
|
/// Used for conveying textual information associated with the image, like the name of the author,
|
||||
|
/// the copyright information, the date, where the image was created, or some other information.
|
||||
|
/// </summary>
|
||||
|
public readonly struct PngTextData : IEquatable<PngTextData> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="PngTextData"/> struct.
|
||||
|
/// </summary>
|
||||
|
/// <param name="keyword">The keyword of the property.</param>
|
||||
|
/// <param name="value">The value of the property.</param>
|
||||
|
/// <param name="languageTag">An optional language tag.</param>
|
||||
|
/// <param name="translatedKeyword">A optional translated keyword.</param>
|
||||
|
public PngTextData(string keyword, string value, string languageTag, string translatedKeyword) |
||||
|
{ |
||||
|
Guard.NotNullOrWhiteSpace(keyword, nameof(keyword)); |
||||
|
|
||||
|
// No leading or trailing whitespace is allowed in keywords.
|
||||
|
this.Keyword = keyword.Trim(); |
||||
|
this.Value = value; |
||||
|
this.LanguageTag = languageTag; |
||||
|
this.TranslatedKeyword = translatedKeyword; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the keyword of this <see cref="PngTextData"/> which indicates
|
||||
|
/// the type of information represented by the text string as described in https://www.w3.org/TR/PNG/#11keywords.
|
||||
|
/// </summary>
|
||||
|
/// <example>
|
||||
|
/// Typical properties are the author, copyright information or other meta information.
|
||||
|
/// </example>
|
||||
|
public string Keyword { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the value of this <see cref="PngTextData"/>.
|
||||
|
/// </summary>
|
||||
|
public string Value { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets an optional language tag defined in https://www.w3.org/TR/PNG/#2-RFC-3066 indicates the human language used by the translated keyword and the text.
|
||||
|
/// If the first word is two or three letters long, it is an ISO language code https://www.w3.org/TR/PNG/#2-ISO-639.
|
||||
|
/// </summary>
|
||||
|
/// <example>
|
||||
|
/// Examples: cn, en-uk, no-bok, x-klingon, x-KlInGoN.
|
||||
|
/// </example>
|
||||
|
public string LanguageTag { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets an optional translated keyword, should contain a translation of the keyword into the language indicated by the language tag.
|
||||
|
/// </summary>
|
||||
|
public string TranslatedKeyword { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Compares two <see cref="PngTextData"/> objects. The result specifies whether the values
|
||||
|
/// of the properties of the two <see cref="PngTextData"/> objects are equal.
|
||||
|
/// </summary>
|
||||
|
/// <param name="left">
|
||||
|
/// The <see cref="PngTextData"/> on the left side of the operand.
|
||||
|
/// </param>
|
||||
|
/// <param name="right">
|
||||
|
/// The <see cref="PngTextData"/> on the right side of the operand.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
||||
|
/// </returns>
|
||||
|
public static bool operator ==(PngTextData left, PngTextData right) |
||||
|
{ |
||||
|
return left.Equals(right); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Compares two <see cref="PngTextData"/> objects. The result specifies whether the values
|
||||
|
/// of the properties of the two <see cref="PngTextData"/> objects are unequal.
|
||||
|
/// </summary>
|
||||
|
/// <param name="left">
|
||||
|
/// The <see cref="PngTextData"/> on the left side of the operand.
|
||||
|
/// </param>
|
||||
|
/// <param name="right">
|
||||
|
/// The <see cref="PngTextData"/> on the right side of the operand.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
||||
|
/// </returns>
|
||||
|
public static bool operator !=(PngTextData left, PngTextData right) |
||||
|
{ |
||||
|
return !(left == right); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Indicates whether this instance and a specified object are equal.
|
||||
|
/// </summary>
|
||||
|
/// <param name="obj">
|
||||
|
/// The object to compare with the current instance.
|
||||
|
/// </param>
|
||||
|
/// <returns>
|
||||
|
/// true if <paramref name="obj"/> and this instance are the same type and represent the
|
||||
|
/// same value; otherwise, false.
|
||||
|
/// </returns>
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
return obj is PngTextData other && this.Equals(other); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the hash code for this instance.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// A 32-bit signed integer that is the hash code for this instance.
|
||||
|
/// </returns>
|
||||
|
public override int GetHashCode() => HashCode.Combine(this.Keyword, this.Value, this.LanguageTag, this.TranslatedKeyword); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Returns the fully qualified type name of this instance.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// A <see cref="T:System.String"/> containing a fully qualified type name.
|
||||
|
/// </returns>
|
||||
|
public override string ToString() => $"PngTextData [ Name={this.Keyword}, Value={this.Value} ]"; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Indicates whether the current object is equal to another object of the same type.
|
||||
|
/// </summary>
|
||||
|
/// <returns>
|
||||
|
/// True if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
|
||||
|
/// </returns>
|
||||
|
/// <param name="other">An object to compare with this object.</param>
|
||||
|
public bool Equals(PngTextData other) |
||||
|
{ |
||||
|
return this.Keyword.Equals(other.Keyword) |
||||
|
&& this.Value.Equals(other.Value) |
||||
|
&& this.LanguageTag.Equals(other.LanguageTag) |
||||
|
&& this.TranslatedKeyword.Equals(other.TranslatedKeyword); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue