diff --git a/src/ImageProcessorCore/ImageExtensions.cs b/src/ImageProcessorCore/ImageExtensions.cs index 509500349..420132236 100644 --- a/src/ImageProcessorCore/ImageExtensions.cs +++ b/src/ImageProcessorCore/ImageExtensions.cs @@ -10,6 +10,7 @@ namespace ImageProcessorCore using Formats; + using ImageProcessorCore.Quantizers; using ImageProcessorCore.Samplers; /// @@ -51,6 +52,53 @@ namespace ImageProcessorCore /// Thrown if the stream is null. public static void SaveAsGif(this ImageBase source, Stream stream, int quality = 256) => new GifEncoder() { Quality = quality }.Encode(source, stream); + /// + /// Returns a 1x1 pixel Base64 encoded gif from the given image containing a single dominant color. + /// + /// + /// The idea and code is based on the article at + /// + /// The image this method extends. + /// The + public static string ToBase64GifPixelString(this Image source) + { + // Leave the original image intact + using (Image temp = new Image(source)) + { + Bgra32 color = new OctreeQuantizer().Quantize(temp.Resize(250, 250), 1).Palette[0]; + + byte[] gif = { + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, // Header + 0x01, 0x00, 0x01, 0x00, 0x80, 0x01, 0x00, // Logical Screen Descriptor + color.R, color.G, color.B, 0x00, 0x00, 0x00, // Global Color Table + 0x2C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, // Image Descriptor + 0x02, 0x02, 0x44, 0x01, 0x00 // Image Data + }; + + return "data:image/gif;base64," + Convert.ToBase64String(gif); + } + } + + /// + /// Returns a 3x3 pixel Base64 encoded gif from the given image. + /// + /// + /// The idea and code is based on the article at + /// + /// The image this method extends. + /// The + public static string ToBase64GifString(this Image source) + { + // Leave the original image intact + using (Image temp = new Image(source)) + using (MemoryStream stream = new MemoryStream()) + { + temp.Resize(3, 3).SaveAsGif(stream); + stream.Flush(); + return "data:image/gif;base64," + Convert.ToBase64String(stream.ToArray()); + } + } + /// /// Applies the collection of processors to the image. /// This method does not resize the target image. diff --git a/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs b/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs index 116399ccf..488e57038 100644 --- a/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs +++ b/tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs @@ -17,6 +17,32 @@ namespace ImageProcessorCore.Tests public class EncoderDecoderTests : FileTestBase { + [Fact] + public void ImageCanEncodeToDominantPixel() + { + if (!Directory.Exists("TestOutput/Dominant")) + { + Directory.CreateDirectory("TestOutput/Dominant"); + } + + foreach (string file in Files) + { + using (FileStream stream = File.OpenRead(file)) + { + Stopwatch watch = Stopwatch.StartNew(); + using (Image image = new Image(stream)) + { + string filename = "TestOutput/Dominant/" + Path.GetFileNameWithoutExtension(file) + ".txt"; + string filename2 = "TestOutput/Dominant/Pixel-" + Path.GetFileNameWithoutExtension(file) + ".txt"; + File.WriteAllText(filename, image.ToBase64GifString()); + File.WriteAllText(filename2, image.ToBase64GifPixelString()); + } + + Trace.WriteLine($"{watch.ElapsedMilliseconds}ms"); + } + } + } + [Fact] public void DecodeThenEncodeImageFromStreamShouldSucceed() {