Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PngWriteDefines to Magick.NET #1661

Merged
merged 38 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c25d699
Added BitDepth property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
63b2d7f
Added ColorType property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
4f74d61
Added CompressionLevel property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
fc08b0b
Added PngCompressionFilter enum to the project.
rubenscordeirobr Jun 27, 2024
adc3ac7
Added CompressionFilter property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
41441eb
Added PngCompressionStrategy enum to the project.
rubenscordeirobr Jun 27, 2024
14113e2
Added CompressionStrategy property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
8baa9e6
Added PngChunkFlags enum to the project
rubenscordeirobr Jun 27, 2024
6c05dd2
Added ExcludeChunks property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
46cdc87
Added IncludeChunks property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
930a559
Added IgnoreCrc property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
9c98585
Added PreserveiCCP IgnoreCrc property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
878b8c2
Added the All enum value to PngChunkFlags.
rubenscordeirobr Jun 27, 2024
11bb787
Added the PreserveColorMap property to PngWriteDefines.
rubenscordeirobr Jun 27, 2024
8102e44
Added SuppressMessage attribute to PngChunkFlags enum to align with …
rubenscordeirobr Jun 27, 2024
96d4037
Update XML comments and remove extra blank line to resolve StyleCop w…
rubenscordeirobr Jun 27, 2024
debe7dd
Updated PngChunkFlags enum
rubenscordeirobr Jun 27, 2024
ce9a02b
Updated PngChunkFlags enum for ARM processor compatibility.
rubenscordeirobr Jun 27, 2024
1a1ef28
Fixed indentation error SA1137 in PngChunkFlags
rubenscordeirobr Jun 27, 2024
49e3bd8
Added PngColorType enum to the project.
rubenscordeirobr Jun 30, 2024
79f703a
Added GetPngColorTypeValue private method to PngWriteDefines.
rubenscordeirobr Jun 30, 2024
b229418
Added ValidateBitDepth private method to PngWriteDefines.
rubenscordeirobr Jun 30, 2024
9762c7a
Organize and update defines in PngWriteDefines
rubenscordeirobr Jun 30, 2024
258741a
Removed IncludeChunks property in PngWriteDefines.
rubenscordeirobr Jun 30, 2024
2181c5e
Renamed the ThreCompressionStrategy class to ThreCompressionStrategyP…
rubenscordeirobr Jun 30, 2024
5e594a7
Renamed the method ShouldSetTheDefineNull to ShouldNotSetTheDefineWhe…
rubenscordeirobr Jun 30, 2024
151b6b4
Updated numeric values in PngWriteDefinesTests
rubenscordeirobr Jun 30, 2024
94ef9c8
Added previously missing documentation for RGBMatte property in PngWr…
rubenscordeirobr Jun 30, 2024
6251a4a
Renamed method, from ShouldSetTheDefine ShouldSetTheDefineWhenSetToTr…
rubenscordeirobr Jul 2, 2024
d922381
Removed ValidateBitDepth method from PngWriteDefines class.
rubenscordeirobr Jul 2, 2024
a1abba6
Fix typo in class name within PngWriteDefinesTests.
rubenscordeirobr Jul 7, 2024
a2c7cf6
Removed IgnoreCrc property in PngWriteDefines.
rubenscordeirobr Jul 13, 2024
6e2aeb9
Re-add IncludeChunks property to PngWriteDefines that was previously …
rubenscordeirobr Jul 13, 2024
55bcd61
Remove PngColorType enum and use int instead.
rubenscordeirobr Jul 13, 2024
8f6f3b2
Added ShouldThrowExceptionWhenColorTypeIsInvalid test in PngWriteDefi…
rubenscordeirobr Jul 13, 2024
2d255f7
Split test for invalid ColorType in PngWriteDefines
rubenscordeirobr Jul 16, 2024
7a955c7
Removed unnecessary comment in PngWriteDefines.
rubenscordeirobr Jul 16, 2024
41d1031
Fixed palette color mapping in PngWriteDefines.
rubenscordeirobr Jul 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions src/Magick.NET/Formats/Png/PngChunkFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
// Licensed under the Apache License, Version 2.0.

using System;

namespace ImageMagick.Formats;

/// <summary>
/// Specifies the chunks to be included or excluded in the PNG image.
/// This is a flags enumeration, allowing a bitwise combination of its member values.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "The lowercase names are consistent with the naming conventions of PNG chunk types as defined in the PNG specification.")]
dlemstra marked this conversation as resolved.
Show resolved Hide resolved
[Flags]
public enum PngChunkFlags
{
/// <summary>
/// No chunks specified.
/// </summary>
None = 0,

/// <summary>
/// Include or exclude all chunks.
/// </summary>
All = bKGD | cHRM | EXIF | gAMA | iCCP | iTXt | sRGB | tEXt | zCCP | zTXt | date,

/// <summary>
/// Include or exclude bKGD chunk.
/// </summary>
bKGD = 1,

/// <summary>
/// Include or exclude cHRM chunk.
/// </summary>
cHRM = 2,

/// <summary>
/// Include or exclude EXIF chunk.
/// </summary>
EXIF = 4,

/// <summary>
/// Include or exclude gAMA chunk.
/// </summary>
gAMA = 8,

/// <summary>
/// Include or exclude iCCP chunk.
/// </summary>
iCCP = 16,

/// <summary>
/// Include or exclude iTXt chunk.
/// </summary>
iTXt = 32,

/// <summary>
/// Include or exclude sRGB chunk.
/// </summary>
sRGB = 64,

/// <summary>
/// Include or exclude tEXt chunk.
/// </summary>
tEXt = 128,

/// <summary>
/// Include or exclude zCCP chunk.
/// </summary>
zCCP = 256,

/// <summary>
/// Include or exclude zTXt chunk.
/// </summary>
zTXt = 512,

/// <summary>
/// Include or exclude date chunk.
/// </summary>
date = 1024,
}
35 changes: 35 additions & 0 deletions src/Magick.NET/Formats/Png/PngCompressionFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
// Licensed under the Apache License, Version 2.0.

namespace ImageMagick.Formats;

/// <summary>
/// Specifies the PNG compression filter.
/// </summary>
public enum PngCompressionFilter
{
/// <summary>
/// 0 - None: No filter.
/// </summary>
None,

/// <summary>
/// Sub: Subtracts the value of the pixel to the left.
/// </summary>
Sub,

/// <summary>
/// Up: Subtracts the value of the pixel above.
/// </summary>
Up,

/// <summary>
/// Average: Uses the average of the left and above pixels.
/// </summary>
Average,

/// <summary>
/// Paeth: A predictive filter using the Paeth algorithm.
/// </summary>
Paeth,
}
60 changes: 60 additions & 0 deletions src/Magick.NET/Formats/Png/PngCompressionStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
// Licensed under the Apache License, Version 2.0.

namespace ImageMagick.Formats;

/// <summary>
/// Specifies the PNG compression strategy.
/// </summary>
public enum PngCompressionStrategy
{
/// <summary>
/// Use the Huffman compression.
/// </summary>
HuffmanOnly,

/// <summary>
/// Compression algorithm with filtering.
/// </summary>
Filtered,

/// <summary>
/// Use the Run-Length Encoding compression.
/// </summary>
RLE,

/// <summary>
/// Use a fixed strategy for compression.
/// </summary>
Fixed,

/// <summary>
/// Use the default compression strategy.
/// </summary>
Default,

/// <summary>
/// Adaptive filtering is used when quality is greater than 50 and the image does not have a color map; otherwise, no filtering is used.
/// </summary>
Adaptive,

/// <summary>
/// Adaptive filtering with minimum-sum-of-absolute-values is used.
/// </summary>
AdaptiveMinimumSum,

/// <summary>
/// LOCO color transformation (intrapixel differencing) and adaptive filtering with minimum-sum-of-absolute-values are used. Only applicable if the output is MNG.
/// </summary>
LOCO,

/// <summary>
/// The zlib Z_RLE compression strategy (or the Z_HUFFMAN_ONLY strategy when compression level is 0) is used with adaptive PNG filtering.
/// </summary>
ZRLEAdaptive,

/// <summary>
/// The zlib Z_RLE compression strategy (or the Z_HUFFMAN_ONLY strategy when compression level is 0) is used with no PNG filtering.
/// </summary>
ZRLENoFilter,
}
127 changes: 127 additions & 0 deletions src/Magick.NET/Formats/Png/PngWriteDefines.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Collections.Generic;

namespace ImageMagick.Formats;

/// <summary>
/// Class for defines that are used when a <see cref="MagickFormat.Png"/> image is written.
/// </summary>
public sealed class PngWriteDefines : IWriteDefines
{
/// <summary>
/// Gets or sets the bit depth for the PNG image.
/// Valid values: 1, 2, 4, 8, 16.
/// </summary>
/// <exception cref="ArgumentException"> Thrown when the bit depth is invalid for the given color type.</exception>
public uint? BitDepth { get; set; }

/// <summary>
/// Gets or sets the color type of the image.
/// </summary>
/// <exception cref="ArgumentException">Thrown when the color type is invalid or unsupported.</exception>
public ColorType? ColorType { get; set; }

/// <summary>
/// Gets or sets the compression filter for the PNG image.
/// For compression level 0 (quality value less than 10), the Huffman-only strategy is used, which is fastest but not necessarily the worst compression.
/// </summary>
public PngCompressionFilter? CompressionFilter { get; set; }

/// <summary>
/// Gets or sets the compression level for the PNG image.
/// The compression level ranges from 0 to 9, where 0 indicates no compression and 9 indicates maximum compression.
/// For compression level 0 (quality value less than 10), the Huffman-only strategy is used, which is the fastest but not necessarily the worst compression.
/// </summary>
public uint? CompressionLevel { get; set; }

/// <summary>
/// Gets or sets the compression strategy for the PNG image.
/// </summary>
public PngCompressionStrategy? CompressionStrategy { get; set; }

/// <summary>
/// Gets or sets the chunks to be excluded.
/// </summary>
public PngChunkFlags? ExcludeChunks { get; set; }

/// <summary>
/// Gets or sets the chunks to be included.
/// </summary>
public PngChunkFlags? IncludeChunks { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the iCCP chunk should be preserved when writing the image.
/// </summary>
public bool PreserveiCCP { get; set; }

/// <summary>
/// Gets or sets a value indicating whether ColorMap should be preserve when writing the image.
/// </summary>
public bool PreserveColorMap { get; set; }

/// <summary>
/// Gets the format where the defines are for.
/// </summary>
public MagickFormat Format
=> MagickFormat.Png;

/// <summary>
/// Gets the defines that should be set as a define on an image.
/// </summary>
public IEnumerable<IDefine> Defines
{
get
{
if (BitDepth.HasValue)
yield return new MagickDefine(Format, "bit-depth", BitDepth.Value);

if (ColorType.HasValue)
{
var colorTypeValue = GetPngColorTypeValue(ColorType.Value);
yield return new MagickDefine(Format, "color-type", (int)colorTypeValue);
}

if (CompressionFilter.HasValue)
yield return new MagickDefine(Format, "compression-filter", (int)CompressionFilter.Value);

if (CompressionLevel.HasValue)
yield return new MagickDefine(Format, "compression-level", CompressionLevel.Value);

if (CompressionStrategy.HasValue)
yield return new MagickDefine(Format, "compression-strategy", (int)CompressionStrategy.Value);

if (ExcludeChunks.HasValue)
yield return new MagickDefine(Format, "exclude-chunks", EnumHelper.ConvertFlags(ExcludeChunks.Value));

if (IncludeChunks.HasValue)
yield return new MagickDefine(Format, "include-chunks", EnumHelper.ConvertFlags(IncludeChunks.Value));

if (PreserveiCCP)
yield return new MagickDefine(Format, "preserve-iCCP", PreserveiCCP);

if (PreserveColorMap)
yield return new MagickDefine(Format, "preserve-colormap", PreserveColorMap);
}
}

private int GetPngColorTypeValue(ColorType colorType)
{
// 0 - Grayscale
// 2 - RGB (TrueColor)
// 3 - Indexed color type (Palette or PaletteAlpha)
// 4 - Grayscale with alpha (GrayscaleAlpha)
// 6 - RGB with alpha (TrueColorAlpha)
return colorType switch
{
ImageMagick.ColorType.Grayscale => 0,
ImageMagick.ColorType.TrueColor => 2,
ImageMagick.ColorType.Palette or ImageMagick.ColorType.PaletteAlpha => 3,
ImageMagick.ColorType.GrayscaleAlpha => 4,
ImageMagick.ColorType.TrueColorAlpha => 6,
_ => throw new ArgumentException($"Unsupported color type: {colorType}"),
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright Dirk Lemstra https://github.com/dlemstra/Magick.NET.
// Licensed under the Apache License, Version 2.0.

using ImageMagick;
using ImageMagick.Formats;
using Xunit;

namespace Magick.NET.Tests;

public partial class PngWriteDefinesTests
{
public class TheBitDepthProperty
{
[Fact]
public void ShouldSetTheDefine()
{
using var image = new MagickImage();
image.Settings.SetDefines(new PngWriteDefines
{
BitDepth = 8U,
});

Assert.Equal("8", image.Settings.GetDefine(MagickFormat.Png, "bit-depth"));
}

[Fact]
public void ShouldNotSetTheDefineWhenNull()
{
using var image = new MagickImage();
image.Settings.SetDefines(new PngWriteDefines
{
BitDepth = null,
});

Assert.Null(image.Settings.GetDefine(MagickFormat.Png, "bit-depth"));
}
}
}
Loading