diff --git a/README.md b/README.md
index 98336a1ed..75b30ff22 100644
--- a/README.md
+++ b/README.md
@@ -3,17 +3,17 @@
## This branch contains the new cross platform version: ImageProcessorCore.
---
-#ImageProcessor Needs Your Help
+## ImageProcessor Needs Your Help
-### ImageProcessor is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. If the project is to survive we need more contribution from the community at large. There are several issues, most notably [#324](https://github.com/JimBobSquarePants/ImageProcessor/issues/324) that we cannot possibly solve on our own.
+**ImageProcessor is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. If the project is to survive we need more contribution from the community at large. There are several issues, most notably [#264](https://github.com/JimBobSquarePants/ImageProcessor/issues/264) that we cannot possibly solve on our own.**
-### We, and we believe many others in the community at large want a first-class 2D imaging library with a simple API that is not simply a wrapper round an existing library. We want it to have a low contribution bar which we believe can only happen if the library is written in C#. We want it to be written to cover as many use cases as possible. We want to write the same code once and have it work on any platform supporting CoreFX.
+**We, and we believe many others in the community at large want a first-class 2D imaging library with a simple API that is not simply a wrapper round an existing library. We want it to have a low contribution bar which we believe can only happen if the library is written in C#. We want it to be written to cover as many use cases as possible. We want to write the same code once and have it work on any platform supporting CoreFX.**
-### With your help we can make all that a reality.
+**With your help we can make all that a reality.**
-### If you can donate any time to improve on the project, be it helping with documentation, tests or contributing code please do.
+**If you can donate any time to improve on the project, be it helping with documentation, tests or contributing code please do.**
-### Thankyou for reading this.
+**Thankyou for reading this**
---
This is a complete rewrite from the ground up to allow the processing of images without the use of `System.Drawing` using a cross-platform class library. It's still in early stages but progress has been pretty quick.
@@ -50,8 +50,8 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
###What works so far/ What is planned?
-- Encoding/decoding of image formats (plugable)
- - [x] jpeg (Includes progressive)
+- 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
@@ -69,7 +69,7 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] Size
- [x] Point
- [x] Ellipse
-- Resampling algorithms. (Performance improvements?)
+- Resampling algorithms. (Optional gamma correction, Performance improvements?)
- [x] Box
- [x] Bicubic
- [x] Lanczos3
@@ -94,10 +94,20 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] BlackWhite
- [x] Greyscale BT709
- [x] Greyscale BT601
+ - [x] Hue
+ - [x] Saturation
- [x] Lomograph
- [x] Polaroid
- [x] Kodachrome
- [x] Sepia
+ - [x] Achromatomaly
+ - [x] Achromatopsia
+ - [x] Deuteranomaly
+ - [x] Deuteranopia
+ - [x] Protanomaly
+ - [x] Protanopia
+ - [x] Tritanomaly
+ - [x] Tritanopia
- Edge Detection
- [x] Kayyali
- [x] Kirsch
@@ -119,12 +129,11 @@ git clone https://github.com/JimBobSquarePants/ImageProcessor
- [x] BackgroundColor
- [x] Brightness
- [x] Pixelate
- - [x] Saturation
- - [x] Hue
- [x] Blend
- [ ] Mask
- [x] Vignette
- [x] Glow
+ - [x] Threshold
- Effects
- [ ] Path brush (Need help) [#264](https://github.com/JimBobSquarePants/ImageProcessor/issues/264)
- [ ] Pattern brush (Need help) [#264](https://github.com/JimBobSquarePants/ImageProcessor/issues/264)
@@ -142,7 +151,7 @@ With this version the API will change dramatically. Without the constraints of `
Image methods are also fluent which allow chaining much like the `ImageFactory` class in the Framework version.
-Here's an example of the code required to resize an image using the default Robidoux resampler then turn the colors into their greyscale equivalent using the BT709 standard matrix.
+Here's an example of the code required to resize an image using the default Bicubic resampler then turn the colors into their greyscale equivalent using the BT709 standard matrix.
```csharp
using (FileStream stream = File.OpenRead("foo.jpg"))
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
index 4d71616ed..5771e2167 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegDecoderCore.cs.REMOVED.git-id
@@ -1 +1 @@
-4b32515bda4abce4bd01c9ad019ce9a581b1c56f
\ No newline at end of file
+23454141b1a1c974ca0881ae725b6f4ce4d8786b
\ No newline at end of file
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegEncoder.cs b/src/ImageProcessorCore/Formats/Jpg/JpegEncoder.cs
index 8c2509514..87d9d6be1 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegEncoder.cs
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegEncoder.cs
@@ -19,15 +19,22 @@ namespace ImageProcessorCore.Formats
private int quality = 75;
///
- /// The subsamples used to encode the image.
+ /// The subsamples scheme used to encode the image.
///
private JpegSubsample subsample = JpegSubsample.Ratio420;
- private bool subsampleSet = false;
+
+ ///
+ /// Whether subsampling has been specifically set.
+ ///
+ private bool subsampleSet;
///
/// Gets or sets the quality, that will be used to encode the image. Quality
/// index must be between 0 and 100 (compression from max to min).
///
+ ///
+ /// If the quality is less than or equal to 80, the subsampling ratio will switch to
+ ///
/// The quality of the jpg image from 0 to 100.
public int Quality
{
@@ -42,7 +49,11 @@ namespace ImageProcessorCore.Formats
public JpegSubsample Subsample
{
get { return this.subsample; }
- set { this.subsample = value; subsampleSet = true; }
+ set
+ {
+ this.subsample = value;
+ this.subsampleSet = true;
+ }
}
///
@@ -73,10 +84,14 @@ namespace ImageProcessorCore.Formats
Guard.NotNull(stream, nameof(stream));
JpegEncoderCore encode = new JpegEncoderCore();
- if(subsampleSet)
+ if (this.subsampleSet)
+ {
encode.Encode(stream, image, this.Quality, this.Subsample);
+ }
else
- encode.Encode(stream, image, this.Quality, this.Quality >= 80 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420);
+ {
+ encode.Encode(stream, image, this.Quality, this.Quality >= 80 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420);
+ }
}
}
}
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs b/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs
index be5fe09ab..a8c18d264 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegEncoderCore.cs
@@ -1,4 +1,9 @@
-namespace ImageProcessorCore.Formats
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessorCore.Formats
{
using System;
using System.IO;
diff --git a/src/ImageProcessorCore/Formats/Jpg/JpegSubsample.cs b/src/ImageProcessorCore/Formats/Jpg/JpegSubsample.cs
index 20b884b05..6098f6377 100644
--- a/src/ImageProcessorCore/Formats/Jpg/JpegSubsample.cs
+++ b/src/ImageProcessorCore/Formats/Jpg/JpegSubsample.cs
@@ -1,8 +1,25 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
namespace ImageProcessorCore.Formats
{
+ ///
+ /// Enumerates the chroma subsampling method applied to the image.
+ ///
public enum JpegSubsample
{
+ ///
+ /// High Quality - Each of the three Y'CbCr components have the same sample rate,
+ /// thus there is no chroma subsampling.
+ ///
Ratio444,
- Ratio420,
+
+ ///
+ /// Medium Quality - The horizontal sampling is halved and the Cb and Cr channels are only
+ /// sampled on each alternate line.
+ ///
+ Ratio420
}
}
diff --git a/src/ImageProcessorCore/Samplers/IImageSampler.cs b/src/ImageProcessorCore/Samplers/IImageSampler.cs
index 4cd1912cd..e826db95f 100644
--- a/src/ImageProcessorCore/Samplers/IImageSampler.cs
+++ b/src/ImageProcessorCore/Samplers/IImageSampler.cs
@@ -10,5 +10,9 @@ namespace ImageProcessorCore.Samplers
///
public interface IImageSampler : IImageProcessor
{
+ ///
+ /// Gets or sets a value indicating whether to compand the value on processing.
+ ///
+ bool Compand { get; set; }
}
}
diff --git a/src/ImageProcessorCore/Samplers/ImageSampler.cs b/src/ImageProcessorCore/Samplers/ImageSampler.cs
index a78105ec3..5a15f9966 100644
--- a/src/ImageProcessorCore/Samplers/ImageSampler.cs
+++ b/src/ImageProcessorCore/Samplers/ImageSampler.cs
@@ -11,5 +11,7 @@ namespace ImageProcessorCore.Samplers
///
public abstract class ImageSampler : ParallelImageProcessor, IImageSampler
{
+ ///
+ public virtual bool Compand { get; set; } = false;
}
}
diff --git a/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs b/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs
index 97cba15e2..542050ecd 100644
--- a/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs
+++ b/src/ImageProcessorCore/Samplers/ImageSamplerExtensions.cs
@@ -93,7 +93,22 @@ namespace ImageProcessorCore.Samplers
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
public static Image Resize(this Image source, int width, int height, ProgressEventHandler progressHandler = null)
{
- return Resize(source, width, height, new BicubicResampler(), progressHandler);
+ return Resize(source, width, height, new BicubicResampler(), false, progressHandler);
+ }
+
+ ///
+ /// Resizes an image to the given width and height.
+ ///
+ /// The image to resize.
+ /// The target image width.
+ /// The target image height.
+ /// Whether to compress and expand the image color-space to gamma correct the image during processing.
+ /// A delegate which is called as progress is made processing the image.
+ /// The
+ /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
+ public static Image Resize(this Image source, int width, int height, bool compand, ProgressEventHandler progressHandler = null)
+ {
+ return Resize(source, width, height, new BicubicResampler(), compand, progressHandler);
}
///
@@ -103,12 +118,13 @@ namespace ImageProcessorCore.Samplers
/// The target image width.
/// The target image height.
/// The to perform the resampling.
+ /// Whether to compress and expand the image color-space to gamma correct the image during processing.
/// A delegate which is called as progress is made processing the image.
/// The
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
- public static Image Resize(this Image source, int width, int height, IResampler sampler, ProgressEventHandler progressHandler = null)
+ public static Image Resize(this Image source, int width, int height, IResampler sampler, bool compand, ProgressEventHandler progressHandler = null)
{
- return Resize(source, width, height, sampler, source.Bounds, progressHandler);
+ return Resize(source, width, height, sampler, source.Bounds, compand, progressHandler);
}
///
@@ -122,10 +138,11 @@ namespace ImageProcessorCore.Samplers
///
/// The structure that specifies the portion of the image object to draw.
///
+ /// Whether to compress and expand the image color-space to gamma correct the image during processing.
/// A delegate which is called as progress is made processing the image.
/// The
/// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image
- public static Image Resize(this Image source, int width, int height, IResampler sampler, Rectangle sourceRectangle, ProgressEventHandler progressHandler = null)
+ public static Image Resize(this Image source, int width, int height, IResampler sampler, Rectangle sourceRectangle, bool compand = false, ProgressEventHandler progressHandler = null)
{
if (width == 0 && height > 0)
{
@@ -137,7 +154,7 @@ namespace ImageProcessorCore.Samplers
height = source.Height * width / source.Width;
}
- Resize processor = new Resize(sampler);
+ Resize processor = new Resize(sampler) { Compand = compand };
processor.OnProgress += progressHandler;
try
@@ -159,7 +176,20 @@ namespace ImageProcessorCore.Samplers
/// The
public static Image Rotate(this Image source, float degrees, ProgressEventHandler progressHandler = null)
{
- return Rotate(source, degrees, new BicubicResampler(), progressHandler);
+ return Rotate(source, degrees, new BicubicResampler(), false, progressHandler);
+ }
+
+ ///
+ /// Rotates an image by the given angle in degrees.
+ ///
+ /// The image to resize.
+ /// The angle in degrees to perform the rotation.
+ /// Whether to compress and expand the image color-space to gamma correct the image during processing.
+ /// A delegate which is called as progress is made processing the image.
+ /// The
+ public static Image Rotate(this Image source, float degrees, bool compand, ProgressEventHandler progressHandler = null)
+ {
+ return Rotate(source, degrees, new BicubicResampler(), compand, progressHandler);
}
///
@@ -168,11 +198,12 @@ namespace ImageProcessorCore.Samplers
/// The image to resize.
/// The angle in degrees to perform the rotation.
/// The to perform the resampling.
+ /// Whether to compress and expand the image color-space to gamma correct the image during processing.
/// A delegate which is called as progress is made processing the image.
/// The
- public static Image Rotate(this Image source, float degrees, IResampler sampler, ProgressEventHandler progressHandler = null)
+ public static Image Rotate(this Image source, float degrees, IResampler sampler, bool compand, ProgressEventHandler progressHandler = null)
{
- Rotate processor = new Rotate(sampler) { Angle = degrees };
+ Rotate processor = new Rotate(sampler) { Angle = degrees, Compand = compand };
processor.OnProgress += progressHandler;
try
diff --git a/src/ImageProcessorCore/Samplers/Resize.cs b/src/ImageProcessorCore/Samplers/Resize.cs
index fa04a3394..ce4d513ac 100644
--- a/src/ImageProcessorCore/Samplers/Resize.cs
+++ b/src/ImageProcessorCore/Samplers/Resize.cs
@@ -57,6 +57,7 @@ namespace ImageProcessorCore.Samplers
int targetBottom = targetRectangle.Bottom;
int startX = targetRectangle.X;
int endX = targetRectangle.Right;
+ bool compand = this.Compand;
if (this.Sampler is NearestNeighborResampler)
{
@@ -107,11 +108,15 @@ namespace ImageProcessorCore.Samplers
foreach (Weight xw in horizontalValues)
{
int originX = xw.Index;
- Color sourceColor = Color.Expand(source[originX, y]);
+ Color sourceColor = compand ? Color.Expand(source[originX, y]) : source[originX, y];
destination += sourceColor * xw.Value;
}
- destination = Color.Compress(destination);
+ if (compand)
+ {
+ destination = Color.Compress(destination);
+ }
+
this.firstPass[x, y] = destination;
}
});
@@ -135,11 +140,15 @@ namespace ImageProcessorCore.Samplers
{
int originY = yw.Index;
int originX = x;
- Color sourceColor = Color.Expand(this.firstPass[originX, originY]);
+ Color sourceColor = compand ? Color.Expand(this.firstPass[originX, originY]) : this.firstPass[originX, originY];
destination += sourceColor * yw.Value;
}
- destination = Color.Compress(destination);
+ if (compand)
+ {
+ destination = Color.Compress(destination);
+ }
+
target[x, y] = destination;
}
this.OnRowProcessed();
diff --git a/src/ImageProcessorCore/Samplers/Rotate.cs b/src/ImageProcessorCore/Samplers/Rotate.cs
index 627f78c63..77cc8e7e7 100644
--- a/src/ImageProcessorCore/Samplers/Rotate.cs
+++ b/src/ImageProcessorCore/Samplers/Rotate.cs
@@ -73,6 +73,7 @@ namespace ImageProcessorCore.Samplers
int endX = targetRectangle.Right;
float negativeAngle = -this.angle;
Point centre = Rectangle.Center(sourceRectangle);
+ bool compand = this.Compand;
if (this.Sampler is NearestNeighborResampler)
{
@@ -144,15 +145,20 @@ namespace ImageProcessorCore.Samplers
if (sourceRectangle.Contains(rotated.X, rotated.Y))
{
- Color sourceColor = Color.Expand(source[rotated.X, rotated.Y]);
+ Color sourceColor = compand ? Color.Expand(source[rotated.X, rotated.Y]) : source[rotated.X, rotated.Y];
destination += sourceColor * yw.Value * xw.Value;
}
}
}
- destination = Color.Compress(destination);
+ if (compand)
+ {
+ destination = Color.Compress(destination);
+ }
+
target[x, y] = destination;
}
+
this.OnRowProcessed();
}
});
diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
index 93f6a36a6..678e9fd07 100644
--- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
+++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs
@@ -92,7 +92,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}"))
{
- image.Resize(image.Width / 2, image.Height / 2, sampler, this.ProgressUpdate)
+ image.Resize(image.Width / 2, image.Height / 2, sampler, false, this.ProgressUpdate)
.Save(output);
}
@@ -120,7 +120,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}"))
{
- image.Resize(image.Width / 3, 0, new TriangleResampler(), this.ProgressUpdate)
+ image.Resize(image.Width / 3, 0, new TriangleResampler(), false, this.ProgressUpdate)
.Save(output);
}
@@ -148,7 +148,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}"))
{
- image.Resize(0, image.Height / 3, new TriangleResampler(), this.ProgressUpdate)
+ image.Resize(0, image.Height / 3, new TriangleResampler(), false, this.ProgressUpdate)
.Save(output);
}
@@ -202,7 +202,7 @@
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"TestOutput/Rotate/{filename}"))
{
- image.Rotate(45, sampler, this.ProgressUpdate)
+ image.Rotate(45, sampler, false, this.ProgressUpdate)
//.BackgroundColor(Color.Aqua)
.Save(output);
}