Browse Source

Add PngTransparentColorBehavior enum

pull/1012/head
Brian Popow 6 years ago
parent
commit
ec3656ff7a
  1. 5
      src/ImageSharp/Formats/Png/IPngEncoderOptions.cs
  2. 2
      src/ImageSharp/Formats/Png/PngEncoder.cs
  3. 15
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  4. 4
      src/ImageSharp/Formats/Png/PngEncoderOptions.cs
  5. 22
      src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs
  6. 8
      tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

5
src/ImageSharp/Formats/Png/IPngEncoderOptions.cs

@ -70,8 +70,9 @@ namespace SixLabors.ImageSharp.Formats.Png
PngChunkFilter? ChunkFilter { get; } PngChunkFilter? ChunkFilter { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether fully transparent pixels should be converted to black pixels. /// Gets a value indicating whether fully transparent pixels that may contain R, G, B values which are not 0,
/// should be converted to transparent black, which can yield in better compression in some cases.
/// </summary> /// </summary>
bool MakeTransparentBlack { get; } PngTransparentColorBehavior TransparentColorBehavior { get; }
} }
} }

2
src/ImageSharp/Formats/Png/PngEncoder.cs

@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public bool IgnoreMetadata { get; set; } public bool IgnoreMetadata { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public bool MakeTransparentBlack { get; set; } public PngTransparentColorBehavior TransparentColorBehavior { get; set; }
/// <summary> /// <summary>
/// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>. /// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.

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

@ -145,10 +145,11 @@ namespace SixLabors.ImageSharp.Formats.Png
PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance);
PngEncoderOptionsHelpers.AdjustOptions<TPixel>(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel); PngEncoderOptionsHelpers.AdjustOptions<TPixel>(this.options, pngMetadata, out this.use16Bit, out this.bytesPerPixel);
Image<TPixel> clonedImage = null; Image<TPixel> clonedImage = null;
if (this.options.MakeTransparentBlack) bool clearTransparency = this.options.TransparentColorBehavior == PngTransparentColorBehavior.Clear;
if (clearTransparency)
{ {
clonedImage = image.Clone(); clonedImage = image.Clone();
MakeTransparentPixelsBlack(clonedImage); ClearTransparentPixels(clonedImage);
} }
IndexedImageFrame<TPixel> quantized = this.CreateQuantizedImage(image, clonedImage); IndexedImageFrame<TPixel> quantized = this.CreateQuantizedImage(image, clonedImage);
@ -162,7 +163,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.WritePhysicalChunk(stream, metadata); this.WritePhysicalChunk(stream, metadata);
this.WriteExifChunk(stream, metadata); this.WriteExifChunk(stream, metadata);
this.WriteTextChunks(stream, pngMetadata); this.WriteTextChunks(stream, pngMetadata);
this.WriteDataChunks(this.options.MakeTransparentBlack ? clonedImage : image, quantized, stream); this.WriteDataChunks(clearTransparency ? clonedImage : image, quantized, stream);
this.WriteEndChunk(stream); this.WriteEndChunk(stream);
stream.Flush(); stream.Flush();
@ -190,11 +191,11 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
/// <summary> /// <summary>
/// Makes transparent pixels black. /// Convert transparent pixels, to transparent black pixels, which can yield to better compression in some cases.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The type of the pixel.</typeparam> /// <typeparam name="TPixel">The type of the pixel.</typeparam>
/// <param name="image">The cloned image where the transparent pixels will be changed.</param> /// <param name="image">The cloned image where the transparent pixels will be changed.</param>
private static void MakeTransparentPixelsBlack<TPixel>(Image<TPixel> image) private static void ClearTransparentPixels<TPixel>(Image<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
Rgba32 rgba32 = default; Rgba32 rgba32 = default;
@ -207,7 +208,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (rgba32.A == 0) if (rgba32.A == 0)
{ {
span[x].FromRgba32(Color.Black); span[x].FromRgba32(Color.Transparent);
} }
} }
} }
@ -224,7 +225,7 @@ namespace SixLabors.ImageSharp.Formats.Png
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
IndexedImageFrame<TPixel> quantized; IndexedImageFrame<TPixel> quantized;
if (this.options.MakeTransparentBlack) if (this.options.TransparentColorBehavior == PngTransparentColorBehavior.Clear)
{ {
quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage); quantized = PngEncoderOptionsHelpers.CreateQuantizedFrame(this.options, clonedImage);
this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, quantized); this.bitDepth = PngEncoderOptionsHelpers.CalculateBitDepth(this.options, quantized);

4
src/ImageSharp/Formats/Png/PngEncoderOptions.cs

@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.InterlaceMethod = source.InterlaceMethod; this.InterlaceMethod = source.InterlaceMethod;
this.ChunkFilter = source.ChunkFilter; this.ChunkFilter = source.ChunkFilter;
this.IgnoreMetadata = source.IgnoreMetadata; this.IgnoreMetadata = source.IgnoreMetadata;
this.MakeTransparentBlack = source.MakeTransparentBlack; this.TransparentColorBehavior = source.TransparentColorBehavior;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -68,6 +68,6 @@ namespace SixLabors.ImageSharp.Formats.Png
public bool IgnoreMetadata { get; set; } public bool IgnoreMetadata { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public bool MakeTransparentBlack { get; set; } public PngTransparentColorBehavior TransparentColorBehavior { get; set; }
} }
} }

22
src/ImageSharp/Formats/Png/PngTransparentColorBehavior.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the GNU Affero General Public License, Version 3.
namespace SixLabors.ImageSharp.Formats.Png
{
/// <summary>
/// Enum indicating how the transparency should be handled on encoding.
/// </summary>
public enum PngTransparentColorBehavior
{
/// <summary>
/// Converts fully transparent pixels that may contain R, G, B values which are not 0,
/// to transparent black, which can yield in better compression in some cases.
/// </summary>
Clear,
/// <summary>
/// The transparency will be kept as is.
/// </summary>
Preserve
}
}

8
tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs

@ -392,17 +392,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[Theory] [Theory]
[InlineData(PngColorType.Palette)] [InlineData(PngColorType.Palette)]
[InlineData(PngColorType.Rgb)]
[InlineData(PngColorType.RgbWithAlpha)] [InlineData(PngColorType.RgbWithAlpha)]
[InlineData(PngColorType.Grayscale)]
[InlineData(PngColorType.GrayscaleWithAlpha)] [InlineData(PngColorType.GrayscaleWithAlpha)]
public void Encode_WithMakeTransparentBlackOption_Works(PngColorType colorType) public void Encode_WithPngTransparentColorBehaviorClear_Works(PngColorType colorType)
{ {
// arrange // arrange
var image = new Image<Rgba32>(50, 50); var image = new Image<Rgba32>(50, 50);
var encoder = new PngEncoder() var encoder = new PngEncoder()
{ {
MakeTransparentBlack = true, TransparentColorBehavior = PngTransparentColorBehavior.Clear,
ColorType = colorType ColorType = colorType
}; };
Rgba32 rgba32 = Color.Blue; Rgba32 rgba32 = Color.Blue;
@ -442,7 +440,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
if (y > 25) if (y > 25)
{ {
expectedColor = Color.Black; expectedColor = Color.Transparent;
} }
for (int x = 0; x < actual.Width; x++) for (int x = 0; x < actual.Width; x++)

Loading…
Cancel
Save