Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cbfdaa7
Update ErrorDiffuser.cs
JimBobSquarePants Feb 11, 2020
3a96474
Merge branch 'master' into js/quantization-tweaks
JimBobSquarePants Feb 13, 2020
a75d833
Refactor dithering and quantizers.
JimBobSquarePants Feb 14, 2020
0509886
Cleanup and fix tests.
JimBobSquarePants Feb 14, 2020
98b98ca
Update EuclideanPixelMap{TPixel}.cs
JimBobSquarePants Feb 14, 2020
305a1c9
Make dither parallel and add benchmarks.
JimBobSquarePants Feb 15, 2020
c98ea13
Add bounded quantization and update namings.
JimBobSquarePants Feb 15, 2020
54450a3
Fix Color.Transparent to match spec.
JimBobSquarePants Feb 15, 2020
f921df1
Handle transparent pixels with Octree
JimBobSquarePants Feb 15, 2020
1a8005a
Merge branch 'master' into js/quantization-tweaks
JimBobSquarePants Feb 15, 2020
66a735e
Update WuFrameQuantizer{TPixel}.cs
JimBobSquarePants Feb 15, 2020
e535d1d
Add dither scaling and simplify API.
JimBobSquarePants Feb 16, 2020
860aebf
Add ditherscale to palette API
JimBobSquarePants Feb 16, 2020
259f7c4
Fix tests
JimBobSquarePants Feb 16, 2020
8af7620
Update benchmarks results
JimBobSquarePants Feb 16, 2020
cce7a53
Use different comparer on CI NETFX
JimBobSquarePants Feb 16, 2020
9ee7530
Add some environment output confirmation.
JimBobSquarePants Feb 16, 2020
2484a0c
Add more detail to threshold exceptions.
JimBobSquarePants Feb 16, 2020
c6e6a4c
Skip tests on CI NETFX
JimBobSquarePants Feb 16, 2020
5c46dd8
Fix localization issue with DitheringScale
brianpopow Feb 16, 2020
b9069de
Merge branch 'master' into js/quantization-tweaks
JimBobSquarePants Feb 18, 2020
4dffc17
Refactor to inline based on feedback.
JimBobSquarePants Feb 19, 2020
1bd4704
Update DitherExtensions.cs
JimBobSquarePants Feb 19, 2020
429872d
Update equality check and add ests. Fix #1116
JimBobSquarePants Feb 20, 2020
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
28 changes: 23 additions & 5 deletions src/ImageSharp/Advanced/AotCompilerTools.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -82,6 +83,7 @@ private static void Seed<TPixel>()
// This is we actually call all the individual methods you need to seed.
AotCompileOctreeQuantizer<TPixel>();
AotCompileWuQuantizer<TPixel>();
AotCompilePaletteQuantizer<TPixel>();
AotCompileDithering<TPixel>();
AotCompilePixelOperations<TPixel>();

Expand Down Expand Up @@ -109,7 +111,7 @@ private static void Seed<TPixel>()
private static void AotCompileOctreeQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
using (var test = new OctreeFrameQuantizer<TPixel>(Configuration.Default, new OctreeQuantizer(false)))
using (var test = new OctreeFrameQuantizer<TPixel>(Configuration.Default, new OctreeQuantizer().Options))
{
test.AotGetPalette();
}
Expand All @@ -122,9 +124,25 @@ private static void AotCompileOctreeQuantizer<TPixel>()
private static void AotCompileWuQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
using (var test = new WuFrameQuantizer<TPixel>(Configuration.Default, new WuQuantizer(false)))
using (var test = new WuFrameQuantizer<TPixel>(Configuration.Default, new WuQuantizer().Options))
{
test.QuantizeFrame(new ImageFrame<TPixel>(Configuration.Default, 1, 1));
var frame = new ImageFrame<TPixel>(Configuration.Default, 1, 1);
test.QuantizeFrame(frame, frame.Bounds());
test.AotGetPalette();
}
}

/// <summary>
/// This method pre-seeds the PaletteQuantizer in the AoT compiler for iOS.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
private static void AotCompilePaletteQuantizer<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
using (var test = (PaletteFrameQuantizer<TPixel>)new PaletteQuantizer(Array.Empty<Color>()).CreateFrameQuantizer<TPixel>(Configuration.Default))
{
var frame = new ImageFrame<TPixel>(Configuration.Default, 1, 1);
test.QuantizeFrame(frame, frame.Bounds());
test.AotGetPalette();
}
}
Expand All @@ -136,11 +154,11 @@ private static void AotCompileWuQuantizer<TPixel>()
private static void AotCompileDithering<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
var test = new FloydSteinbergDiffuser();
var test = new FloydSteinbergDither();
TPixel pixel = default;
using (var image = new ImageFrame<TPixel>(Configuration.Default, 1, 1))
{
test.Dither(image, pixel, pixel, 0, 0, 0, 0, 0);
test.Dither(image, default, pixel, pixel, 0, 0, 0, 0);
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/ImageSharp/Color/Color.NamedColors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace SixLabors.ImageSharp
{
/// <content>
/// Contains static named color values.
/// <see href="https://www.w3.org/TR/css-color-3/"/>
/// </content>
public readonly partial struct Color
{
Expand Down Expand Up @@ -719,9 +720,9 @@ public readonly partial struct Color
public static readonly Color Tomato = FromRgba(255, 99, 71, 255);

/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #00000000.
/// </summary>
public static readonly Color Transparent = FromRgba(255, 255, 255, 0);
public static readonly Color Transparent = FromRgba(0, 0, 0, 0);

/// <summary>
/// Represents a <see paramref="Color"/> matching the W3C definition that has an hex value of #40E0D0.
Expand Down
53 changes: 27 additions & 26 deletions src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Processors.Quantization;

namespace SixLabors.ImageSharp.Formats.Bmp
Expand Down Expand Up @@ -87,7 +88,7 @@ public BmpEncoderCore(IBmpEncoderOptions options, MemoryAllocator memoryAllocato
this.memoryAllocator = memoryAllocator;
this.bitsPerPixel = options.BitsPerPixel;
this.writeV4Header = options.SupportTransparency;
this.quantizer = options.Quantizer ?? new OctreeQuantizer(dither: true, maxColors: 256);
this.quantizer = options.Quantizer ?? KnownQuantizers.Octree;
}

/// <summary>
Expand Down Expand Up @@ -335,36 +336,36 @@ private void Write8Bit<TPixel>(Stream stream, ImageFrame<TPixel> image)
private void Write8BitColor<TPixel>(Stream stream, ImageFrame<TPixel> image, Span<byte> colorPalette)
where TPixel : struct, IPixel<TPixel>
{
using (IQuantizedFrame<TPixel> quantized = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration, 256).QuantizeFrame(image))
using IFrameQuantizer<TPixel> quantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration);
using IQuantizedFrame<TPixel> quantized = quantizer.QuantizeFrame(image, image.Bounds());

ReadOnlySpan<TPixel> quantizedColors = quantized.Palette.Span;
var color = default(Rgba32);

// TODO: Use bulk conversion here for better perf
int idx = 0;
foreach (TPixel quantizedColor in quantizedColors)
{
ReadOnlySpan<TPixel> quantizedColors = quantized.Palette.Span;
var color = default(Rgba32);
quantizedColor.ToRgba32(ref color);
colorPalette[idx] = color.B;
colorPalette[idx + 1] = color.G;
colorPalette[idx + 2] = color.R;

// TODO: Use bulk conversion here for better perf
int idx = 0;
foreach (TPixel quantizedColor in quantizedColors)
{
quantizedColor.ToRgba32(ref color);
colorPalette[idx] = color.B;
colorPalette[idx + 1] = color.G;
colorPalette[idx + 2] = color.R;

// Padding byte, always 0.
colorPalette[idx + 3] = 0;
idx += 4;
}
// Padding byte, always 0.
colorPalette[idx + 3] = 0;
idx += 4;
}

stream.Write(colorPalette);

stream.Write(colorPalette);
for (int y = image.Height - 1; y >= 0; y--)
{
ReadOnlySpan<byte> pixelSpan = quantized.GetRowSpan(y);
stream.Write(pixelSpan);

for (int y = image.Height - 1; y >= 0; y--)
for (int i = 0; i < this.padding; i++)
{
ReadOnlySpan<byte> pixelSpan = quantized.GetRowSpan(y);
stream.Write(pixelSpan);

for (int i = 0; i < this.padding; i++)
{
stream.WriteByte(0);
}
stream.WriteByte(0);
}
}
}
Expand Down
26 changes: 15 additions & 11 deletions src/ImageSharp/Formats/Gif/GifEncoderCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal sealed class GifEncoderCore
/// <summary>
/// Configuration bound to the encoding operation.
/// </summary>
private Configuration configuration;
private readonly Configuration configuration;

/// <summary>
/// A reusable buffer used to reduce allocations.
Expand Down Expand Up @@ -84,7 +84,7 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream)
IQuantizedFrame<TPixel> quantized;
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration))
{
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame);
quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds());
}

// Get the number of bits.
Expand Down Expand Up @@ -144,13 +144,10 @@ private void EncodeGlobal<TPixel>(Image<TPixel> image, IQuantizedFrame<TPixel> q
}
else
{
using (IFrameQuantizer<TPixel> paletteFrameQuantizer =
new PaletteFrameQuantizer<TPixel>(this.configuration, this.quantizer.Diffuser, quantized.Palette))
using (IFrameQuantizer<TPixel> paletteFrameQuantizer = new PaletteFrameQuantizer<TPixel>(this.configuration, this.quantizer.Options, quantized.Palette))
using (IQuantizedFrame<TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()))
{
using (IQuantizedFrame<TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame))
{
this.WriteImageData(paletteQuantized, stream);
}
this.WriteImageData(paletteQuantized, stream);
}
}
}
Expand All @@ -171,16 +168,23 @@ private void EncodeLocal<TPixel>(Image<TPixel> image, IQuantizedFrame<TPixel> qu
if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength
&& frameMetadata.ColorTableLength > 0)
{
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration, frameMetadata.ColorTableLength))
var options = new QuantizerOptions
{
Dither = this.quantizer.Options.Dither,
DitherScale = this.quantizer.Options.DitherScale,
MaxColors = frameMetadata.ColorTableLength
};

using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration, options))
{
quantized = frameQuantizer.QuantizeFrame(frame);
quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds());
}
}
else
{
using (IFrameQuantizer<TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer<TPixel>(this.configuration))
{
quantized = frameQuantizer.QuantizeFrame(frame);
quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds());
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions src/ImageSharp/Formats/Png/PngEncoderOptionsHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ public static IQuantizedFrame<TPixel> CreateQuantizedFrame<TPixel>(
// 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));
var maxColors = ImageMaths.GetColorCountForBitDepth(bits);
options.Quantizer = new WuQuantizer(new QuantizerOptions { MaxColors = maxColors });
}

// 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);
ImageFrame<TPixel> frame = image.Frames.RootFrame;
return frameQuantizer.QuantizeFrame(frame, frame.Bounds());
}
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using SixLabors.ImageSharp.Processing.Processors.Binarization;
using SixLabors.ImageSharp.Processing.Processors.Dithering;

namespace SixLabors.ImageSharp.Processing
Expand All @@ -19,8 +18,8 @@ public static class BinaryDitherExtensions
/// <param name="dither">The ordered ditherer.</param>
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext
BinaryDither(this IImageProcessingContext source, IOrderedDither dither) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither));
BinaryDither(this IImageProcessingContext source, IDither dither) =>
BinaryDither(source, dither, Color.White, Color.Black);

/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
Expand All @@ -32,10 +31,10 @@ public static IImageProcessingContext
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryDither(
this IImageProcessingContext source,
IOrderedDither dither,
IDither dither,
Color upperColor,
Color lowerColor) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither, upperColor, lowerColor));
source.ApplyProcessor(new PaletteDitherProcessor(dither, new[] { upperColor, lowerColor }));

/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
Expand All @@ -48,9 +47,9 @@ public static IImageProcessingContext BinaryDither(
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryDither(
this IImageProcessingContext source,
IOrderedDither dither,
IDither dither,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither), rectangle);
BinaryDither(source, dither, Color.White, Color.Black, rectangle);

/// <summary>
/// Dithers the image reducing it to two colors using ordered dithering.
Expand All @@ -65,10 +64,10 @@ public static IImageProcessingContext BinaryDither(
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
public static IImageProcessingContext BinaryDither(
this IImageProcessingContext source,
IOrderedDither dither,
IDither dither,
Color upperColor,
Color lowerColor,
Rectangle rectangle) =>
source.ApplyProcessor(new BinaryOrderedDitherProcessor(dither, upperColor, lowerColor), rectangle);
source.ApplyProcessor(new PaletteDitherProcessor(dither, new[] { upperColor, lowerColor }), rectangle);
}
}
}
Loading