Browse Source

Add 32bit bitmap support plus cleanup.

Former-commit-id: 398e93818c9c9e901b125b7daa7a345fcc8d2787
Former-commit-id: 9aba9f2e190fc8a986e16d632a58ebc94fda2d5b
Former-commit-id: fd99bf7129eb85360cae9484cccac3241af0681e
af/merge-core
James South 10 years ago
parent
commit
b4abafebc4
  1. 20
      README.md
  2. 23
      src/ImageProcessorCore/Formats/Bmp/BmpBitsPerPixel.cs
  3. 2
      src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs
  4. 128
      src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs
  5. 205
      src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs
  6. 8
      src/ImageProcessorCore/IImage.cs
  7. 7
      src/ImageProcessorCore/Image.cs
  8. 11
      tests/ImageProcessorCore.Tests/Colors/ColorConversionTests.cs
  9. 5
      tests/ImageProcessorCore.Tests/Colors/ColorSpacialTransformTests.cs
  10. 11
      tests/ImageProcessorCore.Tests/Colors/ColorTests.cs
  11. 14
      tests/ImageProcessorCore.Tests/FileTestBase.cs
  12. 51
      tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs
  13. 37
      tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs
  14. 39
      tests/ImageProcessorCore.Tests/Formats/PngTests.cs
  15. 2
      tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs
  16. 2
      tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

20
README.md

@ -51,13 +51,14 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
###What works so far/ What is planned?
- Encoding/decoding of image formats (plugable), progressive required
- [x] jpeg (Includes Subsampling, Progressive required)
- [x] bmp (More bmp format saving support required, 24bit just now)
- [x] png (Need updating for saving indexed support)
- [x] gif
- [x] Jpeg (Includes Subsampling. Progressive writing required)
- [x] Bmp (Read: 32bit, 24bit, 16 bit. Write: 32bit, 24bit just now)
- [x] Png (Read: TrueColor, Grayscale, Indexed. Write: True color, Indexed just now)
- [x] Gif (Includes animated)
- [ ] Tiff
- Quantizers (IQuantizer with alpha channel support + thresholding)
- [x] Octree
- [x] Wu
- [x] Xiaolin Wu
- [x] Palette
- Basic color structs with implicit operators. Vector backed. [#260](https://github.com/JimBobSquarePants/ImageProcessor/issues/260)
- [x] Color - Float based, premultiplied alpha, No limit to r, g, b, a values allowing for a fuller color range.
@ -68,8 +69,8 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] HSV
- [x] HSL
- [x] YCbCr
- Basic shape primitives (Unfinished and could possible be updated by using Vector2, Vector3, etc)
- [x] Rectangle
- Basic shape primitives (Vector backed)
- [x] Rectangle (Doesn't contain all System.Drawing methods)
- [x] Size
- [x] Point
- [x] Ellipse
@ -122,7 +123,7 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] RobertsCross
- [x] Scharr
- [x] Sobel
- Blurring/ Sharpening
- Blurring/Sharpening
- [x] Gaussian blur
- [x] Gaussian sharpening
- [x] Box Blur
@ -143,10 +144,11 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [ ] Pattern brush (Need help) [#264](https://github.com/JimBobSquarePants/ImageProcessor/issues/264)
- [ ] Elliptical brush (Need help) [#264](https://github.com/JimBobSquarePants/ImageProcessor/issues/264)
- [ ] Gradient brush (vignette? Need help) [#264](https://github.com/JimBobSquarePants/ImageProcessor/issues/264)
- Metadata
- [ ] EXIF (In progress but there's a lot of quirks in parsing EXIF. [#78](https://github.com/JimBobSquarePants/ImageProcessor/issues/78))
- Other stuff I haven't thought of.
###What might never happen
- Exif manipulation - There's a lot of quirks in parsing EXIF and I'd need a ton of help to get it all coded. [#78](https://github.com/JimBobSquarePants/ImageProcessor/issues/78)
- Font support (Depends on new System.Text stuff) I don't know where to start coding this so if you have any pointers please chip in.
###API Changes

23
src/ImageProcessorCore/Formats/Bmp/BmpBitsPerPixel.cs

@ -0,0 +1,23 @@
// <copyright file="BmpBitsPerPixel.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Formats
{
/// <summary>
/// Enumerates the available bits per pixel for bitmap.
/// </summary>
public enum BmpBitsPerPixel
{
/// <summary>
/// 24 bits per pixel. Each pixel consists of 3 bytes.
/// </summary>
Pixel24 = 3,
/// <summary>
/// 32 bits per pixel. Each pixel consists of 4 bytes.
/// </summary>
Pixel32 = 4,
}
}

2
src/ImageProcessorCore/Formats/Bmp/BmpDecoderCore.cs

@ -12,7 +12,7 @@ namespace ImageProcessorCore.Formats
/// <summary>
/// Performs the bmp decoding operation.
/// </summary>
internal class BmpDecoderCore
internal sealed class BmpDecoderCore
{
/// <summary>
/// The mask for the red part of the color for 16 bit rgb bitmaps.

128
src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs

@ -26,6 +26,11 @@ namespace ImageProcessorCore.Formats
/// <inheritdoc/>
public string Extension => "bmp";
/// <summary>
/// Gets or sets the number of bits per pixel.
/// </summary>
public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24;
/// <inheritdoc/>
public bool IsSupportedFileExtension(string extension)
{
@ -40,127 +45,8 @@ namespace ImageProcessorCore.Formats
/// <inheritdoc/>
public void Encode(ImageBase image, Stream stream)
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
int rowWidth = image.Width;
int amount = (image.Width * 3) % 4;
if (amount != 0)
{
rowWidth += 4 - amount;
}
using (BinaryWriter writer = new BinaryWriter(stream))
{
BmpFileHeader fileHeader = new BmpFileHeader
{
Type = 19778, // BM
Offset = 54,
FileSize = 54 + (image.Height * rowWidth * 3)
};
WriteHeader(writer, fileHeader);
BmpInfoHeader infoHeader = new BmpInfoHeader
{
HeaderSize = 40,
Height = image.Height,
Width = image.Width,
BitsPerPixel = 24,
Planes = 1,
Compression = BmpCompression.RGB,
ImageSize = image.Height * rowWidth * 3,
ClrUsed = 0,
ClrImportant = 0
};
WriteInfo(writer, infoHeader);
this.WriteImage(writer, image);
writer.Flush();
}
}
/// <summary>
/// Writes the pixel data to the binary stream.
/// </summary>
/// <param name="writer">
/// The <see cref="BinaryWriter"/> containing the stream to write to.
/// </param>
/// <param name="image">
/// The <see cref="ImageBase"/> containing pixel data.
/// </param>
private void WriteImage(BinaryWriter writer, ImageBase image)
{
// TODO: Add more compression formats.
int amount = (image.Width * 3) % 4;
if (amount != 0)
{
amount = 4 - amount;
}
for (int y = image.Height - 1; y >= 0; y--)
{
for (int x = 0; x < image.Width; x++)
{
// Limit the output range and multiply out from our floating point.
// Convert back to b-> g-> r-> a order.
// Convert to non-premultiplied color.
Bgra32 color = Color.ToNonPremultiplied(image[x, y]);
// Allocate 1 array instead of allocating 3.
writer.Write(new[] { color.B, color.G, color.R });
}
// Pad
for (int i = 0; i < amount; i++)
{
writer.Write((byte)0);
}
}
}
/// <summary>
/// Writes the bitmap header data to the binary stream.
/// </summary>
/// <param name="writer">
/// The <see cref="BinaryWriter"/> containing the stream to write to.
/// </param>
/// <param name="fileHeader">
/// The <see cref="BmpFileHeader"/> containing the header data.
/// </param>
private static void WriteHeader(BinaryWriter writer, BmpFileHeader fileHeader)
{
writer.Write(fileHeader.Type);
writer.Write(fileHeader.FileSize);
writer.Write(fileHeader.Reserved);
writer.Write(fileHeader.Offset);
}
/// <summary>
/// Writes the bitmap information to the binary stream.
/// </summary>
/// <param name="writer">
/// The <see cref="BinaryWriter"/> containing the stream to write to.
/// </param>
/// <param name="infoHeader">
/// The <see cref="BmpFileHeader"/> containing the detailed information about the image.
/// </param>
private static void WriteInfo(BinaryWriter writer, BmpInfoHeader infoHeader)
{
writer.Write(infoHeader.HeaderSize);
writer.Write(infoHeader.Width);
writer.Write(infoHeader.Height);
writer.Write(infoHeader.Planes);
writer.Write(infoHeader.BitsPerPixel);
writer.Write((int)infoHeader.Compression);
writer.Write(infoHeader.ImageSize);
writer.Write(infoHeader.XPelsPerMeter);
writer.Write(infoHeader.YPelsPerMeter);
writer.Write(infoHeader.ClrUsed);
writer.Write(infoHeader.ClrImportant);
BmpEncoderCore encoder = new BmpEncoderCore();
encoder.Encode(image, stream, this.BitsPerPixel);
}
}
}

205
src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs

@ -0,0 +1,205 @@
// <copyright file="BmpEncoderCore.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Formats
{
using System;
using System.IO;
using ImageProcessorCore.IO;
/// <summary>
/// Image encoder for writing an image to a stream as a Windows bitmap.
/// </summary>
/// <remarks>The encoder can currently only write 24-bit rgb images to streams.</remarks>
internal sealed class BmpEncoderCore
{
/// <summary>
/// The number of bits per pixel.
/// </summary>
private BmpBitsPerPixel bmpBitsPerPixel;
/// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageBase"/>.
/// </summary>
/// <param name="image">The <see cref="ImageBase"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
/// <param name="bitsPerPixel">The <see cref="BmpBitsPerPixel"/></param>
public void Encode(ImageBase image, Stream stream, BmpBitsPerPixel bitsPerPixel)
{
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.bmpBitsPerPixel = bitsPerPixel;
int rowWidth = image.Width;
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4;
if (amount != 0)
{
rowWidth += 4 - amount;
}
using (EndianBinaryWriter writer = new EndianBinaryWriter(EndianBitConverter.Little, stream))
{
int bpp = (int)this.bmpBitsPerPixel;
BmpFileHeader fileHeader = new BmpFileHeader
{
Type = 19778, // BM
Offset = 54,
FileSize = 54 + (image.Height * rowWidth * bpp)
};
BmpInfoHeader infoHeader = new BmpInfoHeader
{
HeaderSize = 40,
Height = image.Height,
Width = image.Width,
BitsPerPixel = (short)(8 * bpp),
Planes = 1,
ImageSize = image.Height * rowWidth * bpp,
ClrUsed = 0,
ClrImportant = 0
};
WriteHeader(writer, fileHeader);
this.WriteInfo(writer, infoHeader);
this.WriteImage(writer, image);
writer.Flush();
}
}
/// <summary>
/// Writes the bitmap header data to the binary stream.
/// </summary>
/// <param name="writer">
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
/// </param>
/// <param name="fileHeader">
/// The <see cref="BmpFileHeader"/> containing the header data.
/// </param>
private static void WriteHeader(EndianBinaryWriter writer, BmpFileHeader fileHeader)
{
writer.Write(fileHeader.Type);
writer.Write(fileHeader.FileSize);
writer.Write(fileHeader.Reserved);
writer.Write(fileHeader.Offset);
}
/// <summary>
/// Writes the bitmap information to the binary stream.
/// </summary>
/// <param name="writer">
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
/// </param>
/// <param name="infoHeader">
/// The <see cref="BmpFileHeader"/> containing the detailed information about the image.
/// </param>
private void WriteInfo(EndianBinaryWriter writer, BmpInfoHeader infoHeader)
{
writer.Write(infoHeader.HeaderSize);
writer.Write(infoHeader.Width);
writer.Write(infoHeader.Height);
writer.Write(infoHeader.Planes);
writer.Write(infoHeader.BitsPerPixel);
writer.Write((int)infoHeader.Compression);
writer.Write(infoHeader.ImageSize);
writer.Write(infoHeader.XPelsPerMeter);
writer.Write(infoHeader.YPelsPerMeter);
writer.Write(infoHeader.ClrUsed);
writer.Write(infoHeader.ClrImportant);
}
/// <summary>
/// Writes the pixel data to the binary stream.
/// </summary>
/// <param name="writer">
/// The <see cref="EndianBinaryWriter"/> containing the stream to write to.
/// </param>
/// <param name="image">
/// The <see cref="ImageBase"/> containing pixel data.
/// </param>
private void WriteImage(EndianBinaryWriter writer, ImageBase image)
{
// TODO: Add more compression formats.
int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4;
if (amount != 0)
{
amount = 4 - amount;
}
switch (this.bmpBitsPerPixel)
{
case BmpBitsPerPixel.Pixel32:
this.Write32bit(writer, image, amount);
break;
case BmpBitsPerPixel.Pixel24:
this.Write24bit(writer, image, amount);
break;
}
}
/// <summary>
/// Writes the 32bit color palette to the stream.
/// </summary>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="image">The <see cref="ImageBase"/> containing pixel data.</param>
/// <param name="amount">The amount to pad each row by.</param>
private void Write32bit(EndianBinaryWriter writer, ImageBase image, int amount)
{
for (int y = image.Height - 1; y >= 0; y--)
{
for (int x = 0; x < image.Width; x++)
{
// Limit the output range and multiply out from our floating point.
// Convert back to b-> g-> r-> a order.
// Convert to non-premultiplied color.
Bgra32 color = Color.ToNonPremultiplied(image[x, y]);
// We can take advantage of BGRA here
writer.Write(color.Bgra);
}
// Pad
for (int i = 0; i < amount; i++)
{
writer.Write((byte)0);
}
}
}
/// <summary>
/// Writes the 24bit color palette to the stream.
/// </summary>
/// <param name="writer">The <see cref="EndianBinaryWriter"/> containing the stream to write to.</param>
/// <param name="image">The <see cref="ImageBase"/> containing pixel data.</param>
/// <param name="amount">The amount to pad each row by.</param>
private void Write24bit(EndianBinaryWriter writer, ImageBase image, int amount)
{
for (int y = image.Height - 1; y >= 0; y--)
{
for (int x = 0; x < image.Width; x++)
{
// Limit the output range and multiply out from our floating point.
// Convert back to b-> g-> r-> a order.
// Convert to non-premultiplied color.
Bgra32 color = Color.ToNonPremultiplied(image[x, y]);
// Allocate 1 array instead of allocating 3.
writer.Write(new[] { color.B, color.G, color.R });
}
// Pad
for (int i = 0; i < amount; i++)
{
writer.Write((byte)0);
}
}
}
}
}

8
src/ImageProcessorCore/IImage.cs

@ -91,5 +91,13 @@ namespace ImageProcessorCore
/// <param name="format">The format to save the image as.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
void Save(Stream stream, IImageFormat format);
/// <summary>
/// Saves the image to the given stream using the given image encoder.
/// </summary>
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="ArgumentNullException">Thrown if the stream is null.</exception>
void Save(Stream stream, IImageEncoder encoder);
}
}

7
src/ImageProcessorCore/Image.cs

@ -216,6 +216,13 @@ namespace ImageProcessorCore
format.Encoder.Encode(this, stream);
}
/// <inheritdoc/>
public void Save(Stream stream, IImageEncoder encoder)
{
Guard.NotNull(stream, nameof(stream));
encoder.Encode(this, stream);
}
/// <summary>
/// Loads the image from the given stream.
/// </summary>

11
tests/ImageProcessorCore.Tests/Colors/ColorConversionTests.cs

@ -1,12 +1,7 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ColorConversionTests.cs" company="James Jackson-South">
// Copyright © James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// <copyright file="ColorConversionTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Test conversion between the various color structs.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessorCore.Tests
{

5
tests/ImageProcessorCore.Tests/Colors/ColorSpacialTransformTests.cs

@ -1,3 +1,8 @@
// <copyright file="MultiplyTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using Xunit;

11
tests/ImageProcessorCore.Tests/Colors/ColorTests.cs

@ -1,12 +1,7 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ColorTests.cs" company="James Jackson-South">
// Copyright © James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// <copyright file="ColorTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Tests the <see cref="Color" /> struct.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System.Numerics;

14
tests/ImageProcessorCore.Tests/Processors/ProcessorTestBase.cs → tests/ImageProcessorCore.Tests/FileTestBase.cs

@ -1,9 +1,7 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ProcessorTestBase.cs" company="James Jackson-South">
// Copyright © James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// <copyright file="FileTestBase.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessorCore.Tests
{
@ -12,14 +10,14 @@ namespace ImageProcessorCore.Tests
using Xunit;
/// <summary>
/// The processor test base.
/// The test base class for reading and writing to files.
/// </summary>
public abstract class ProcessorTestBase
public abstract class FileTestBase
{
/// <summary>
/// The collection of image files to test against.
/// </summary>
public static readonly List<string> Files = new List<string>
protected static readonly List<string> Files = new List<string>
{
//"TestImages/Formats/Jpg/Floorplan.jpeg", // Perf: Enable for local testing only
"TestImages/Formats/Jpg/Calliphora.jpg",

51
tests/ImageProcessorCore.Tests/Formats/BitmapTests.cs

@ -0,0 +1,51 @@
// <copyright file="BitmapTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.Diagnostics;
using System.IO;
using Formats;
using Xunit;
public class BitmapTests : FileTestBase
{
[Fact]
public void BitmapCanEncodeDifferentBitRates()
{
if (!Directory.Exists("TestOutput/Encode/Bitmap"))
{
Directory.CreateDirectory("TestOutput/Encode/Bitmap");
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Stopwatch watch = Stopwatch.StartNew();
Image image = new Image(stream);
string encodeFilename = "TestOutput/Encode/Bitmap/" + "24-" + Path.GetFileNameWithoutExtension(file) + ".bmp";
using (FileStream output = File.OpenWrite(encodeFilename))
{
image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel24 });
}
encodeFilename = "TestOutput/Encode/Bitmap/" + "32-" + Path.GetFileNameWithoutExtension(file) + ".bmp";
using (FileStream output = File.OpenWrite(encodeFilename))
{
image.Save(output, new BmpEncoder { BitsPerPixel = BmpBitsPerPixel.Pixel32 });
}
Trace.WriteLine($"{file} : {watch.ElapsedMilliseconds}ms");
}
}
}
}
}

37
tests/ImageProcessorCore.Tests/Processors/Formats/EncoderDecoderTests.cs → tests/ImageProcessorCore.Tests/Formats/EncoderDecoderTests.cs

@ -1,4 +1,9 @@
namespace ImageProcessorCore.Tests
// <copyright file="EncoderDecoderTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.Diagnostics;
using System.IO;
@ -10,7 +15,7 @@
using ImageProcessorCore.Quantizers;
public class EncoderDecoderTests : ProcessorTestBase
public class EncoderDecoderTests : FileTestBase
{
[Fact]
public void DecodeThenEncodeImageFromStreamShouldSucceed()
@ -20,11 +25,6 @@
Directory.CreateDirectory("TestOutput/Encode");
}
//foreach (FileInfo file in new DirectoryInfo("TestOutput/Encode").GetFiles())
//{
// file.Delete();
//}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
@ -85,29 +85,6 @@
}
}
[Fact]
public void ImageCanSaveIndexedPng()
{
if (!Directory.Exists("TestOutput/Indexed"))
{
Directory.CreateDirectory("TestOutput/Indexed");
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"TestOutput/Indexed/{Path.GetFileNameWithoutExtension(file)}.png"))
{
image.Quality = 256;
image.Save(output, new PngFormat());
}
}
}
}
[Fact]
public void ImageCanConvertFormat()
{

39
tests/ImageProcessorCore.Tests/Formats/PngTests.cs

@ -0,0 +1,39 @@
// <copyright file="PngTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Formats;
using Xunit;
public class PngTests : FileTestBase
{
[Fact]
public void ImageCanSaveIndexedPng()
{
if (!Directory.Exists("TestOutput/Encode/Png"))
{
Directory.CreateDirectory("TestOutput/Encode/Png");
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"TestOutput/Encode/Png/{Path.GetFileNameWithoutExtension(file)}.png"))
{
image.Quality = 256;
image.Save(output, new PngFormat());
}
}
}
}
}
}

2
tests/ImageProcessorCore.Tests/Processors/Filters/FilterTests.cs

@ -8,7 +8,7 @@ namespace ImageProcessorCore.Tests
using Xunit;
public class FilterTests : ProcessorTestBase
public class FilterTests : FileTestBase
{
public static readonly TheoryData<string, IImageProcessor> Filters = new TheoryData<string, IImageProcessor>
{

2
tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

@ -8,7 +8,7 @@
using Xunit;
using Filters;
public class SamplerTests : ProcessorTestBase
public class SamplerTests : FileTestBase
{
public static readonly TheoryData<string, IResampler> ReSamplers =
new TheoryData<string, IResampler>

Loading…
Cancel
Save