Browse Source

Add Alpha, enhance Contrast

Former-commit-id: a06e8058488c43fa8048b4ffd480d8424d88cc27
Former-commit-id: f0edb842766e8c2d2276625aa23b79ca1739918e
Former-commit-id: c55ff7a504d21ce4941fe51596c1beb621ef2082
af/merge-core
James Jackson-South 10 years ago
parent
commit
f1d485d39b
  1. 56
      src/ImageProcessor/Filters/Alpha.cs
  2. 54
      src/ImageProcessor/Filters/Contrast.cs
  3. 46
      src/ImageProcessor/Filters/ImageFilterExtensions.cs
  4. 2
      src/ImageProcessor/ImageProcessor.csproj
  5. 28
      tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs
  6. 3
      tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs

56
src/ImageProcessor/Filters/Alpha.cs

@ -0,0 +1,56 @@
// <copyright file="Alpha.cs" company="James South">
// Copyright © James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Filters
{
using System;
/// <summary>
/// An <see cref="IImageProcessor"/> to change the Alpha of an <see cref="Image"/>.
/// </summary>
public class Alpha : ParallelImageProcessor
{
/// <summary>
/// Initializes a new instance of the <see cref="Alpha"/> class.
/// </summary>
/// <param name="percent">The percentage to adjust the opacity of the image. Must be between 0 and 100.</param>
/// <exception cref="ArgumentException">
/// <paramref name="percent"/> is less than 0 or is greater than 100.
/// </exception>
public Alpha(int percent)
{
Guard.MustBeBetweenOrEqualTo(percent, 0, 100, nameof(percent));
this.Value = percent;
}
/// <summary>
/// Gets the alpha value.
/// </summary>
public int Value { get; }
/// <inheritdoc/>
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
double alpha = this.Value / 100.0;
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
for (int y = startY; y < endY; y++)
{
if (y >= sourceY && y < sourceBottom)
{
for (int x = startX; x < endX; x++)
{
Bgra color = source[x, y];
double a = color.A * alpha;
target[x, y] = new Bgra(color.B, color.G, color.R, a.ToByte());
}
}
}
}
}
}

54
src/ImageProcessor/Filters/Contrast.cs

@ -17,7 +17,7 @@ namespace ImageProcessor.Filters
/// </summary>
/// <param name="contrast">The new contrast of the image. Must be between -100 and 100.</param>
/// <exception cref="ArgumentException">
/// <paramref name="contrast"/> is less than -100 is greater than 100.
/// <paramref name="contrast"/> is less than -100 or is greater than 100.
/// </exception>
public Contrast(int contrast)
{
@ -34,35 +34,45 @@ namespace ImageProcessor.Filters
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
{
double contrast = (100.0 + this.Value) / 100.0;
int sourceY = sourceRectangle.Y;
int sourceBottom = sourceRectangle.Bottom;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
for (int y = startY; y < endY; y++)
{
for (int x = sourceRectangle.X; x < sourceRectangle.Right; x++)
if (y >= sourceY && y < sourceBottom)
{
Bgra color = source[x, y];
for (int x = startX; x < endX; x++)
{
Bgra sourceColor = source[x, y];
sourceColor = PixelOperations.ToLinear(sourceColor);
double r = color.R / 255.0;
r -= 0.5;
r *= contrast;
r += 0.5;
r *= 255;
r = r.ToByte();
double r = sourceColor.R / 255.0;
r -= 0.5;
r *= contrast;
r += 0.5;
r *= 255;
r = r.ToByte();
double g = color.G / 255.0;
g -= 0.5;
g *= contrast;
g += 0.5;
g *= 255;
g = g.ToByte();
double g = sourceColor.G / 255.0;
g -= 0.5;
g *= contrast;
g += 0.5;
g *= 255;
g = g.ToByte();
double b = color.B / 255.0;
b -= 0.5;
b *= contrast;
b += 0.5;
b *= 255;
b = b.ToByte();
double b = sourceColor.B / 255.0;
b -= 0.5;
b *= contrast;
b += 0.5;
b *= 255;
b = b.ToByte();
target[x, y] = new Bgra((byte)b, (byte)g, (byte)r, color.A);
Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), sourceColor.A);
destinationColor = PixelOperations.ToSrgb(destinationColor);
target[x, y] = destinationColor;
}
}
}
}

46
src/ImageProcessor/Filters/ImageFilterExtensions.cs

@ -6,7 +6,7 @@
namespace ImageProcessor.Filters
{
/// <summary>
/// Exstensions methods for <see cref="Image"/> to apply filters to the image.
/// Extensions methods for <see cref="Image"/> to apply filters to the image.
/// </summary>
public static class ImageFilterExtensions
{
@ -16,6 +16,48 @@ namespace ImageProcessor.Filters
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Contrast(this Image source, int amount) => source.Process(new Contrast(amount));
public static Image Contrast(this Image source, int amount)
{
return Contrast(source, amount, source.Bounds);
}
/// <summary>
/// Alters the contrast component of the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="amount">The new contrast of the image. Must be between -100 and 100.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Contrast(this Image source, int amount, Rectangle sourceRectangle)
{
return source.Process(sourceRectangle, new Contrast(amount));
}
/// <summary>
/// Alters the alpha component of the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Alpha(this Image source, int percent)
{
return Alpha(source, percent, source.Bounds);
}
/// <summary>
/// Alters the alpha component of the image.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="percent">The new opacity of the image. Must be between 0 and 100.</param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image Alpha(this Image source, int percent, Rectangle sourceRectangle)
{
return source.Process(sourceRectangle, new Alpha(percent));
}
}
}

2
src/ImageProcessor/ImageProcessor.csproj

@ -43,6 +43,7 @@
<Compile Include="Colors\Cmyk.cs" />
<Compile Include="Common\Helpers\ImageMaths.cs" />
<Compile Include="Common\Helpers\PixelOperations.cs" />
<Compile Include="Filters\Alpha.cs" />
<Compile Include="Filters\Contrast.cs" />
<Compile Include="Filters\ImageFilterExtensions.cs" />
<Compile Include="ImageExtensions.cs" />
@ -181,6 +182,7 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Numerics\Rectangle.cs" />
<Compile Include="Numerics\Size.cs" />
<Compile Include="Samplers\Resamplers\Lanczos5Resampler.cs" />
<Compile Include="Samplers\Resamplers\Lanczos8Resampler.cs" />
<Compile Include="Samplers\Resamplers\WelchResampler.cs" />
<Compile Include="Samplers\Resamplers\CatmullRomResampler.cs" />

28
tests/ImageProcessor.Tests/Processors/Filters/FilterTests.cs

@ -1,12 +1,10 @@

namespace ImageProcessor.Tests
{
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using ImageProcessor.Filters;
using ImageProcessor.Samplers;
using Xunit;
@ -16,6 +14,7 @@ namespace ImageProcessor.Tests
{
{ "Contrast-50", new Contrast(50) },
{ "Contrast--50", new Contrast(-50) },
{ "Alpha--50", new Alpha(50) },
};
[Theory]
@ -43,30 +42,5 @@ namespace ImageProcessor.Tests
}
}
}
[Fact]
public void ResizeImage()
{
if (!Directory.Exists("Resized"))
{
Directory.CreateDirectory("Resized");
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
Stopwatch watch = Stopwatch.StartNew();
Image image = new Image(stream);
string filename = Path.GetFileName(file);
using (FileStream output = File.OpenWrite($"Resized/{ Path.GetFileName(filename) }"))
{
image.Resize(400, 400).Save(output);
}
Trace.WriteLine($"{ filename }: { watch.ElapsedMilliseconds}ms");
}
}
}
}
}

3
tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs

@ -46,7 +46,8 @@ namespace ImageProcessor.Tests
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
using (FileStream output = File.OpenWrite($"Resized/{filename}"))
{
image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output);
//image.Resize(image.Width / 2, image.Height / 2, sampler).Save(output);
image.Resize(500, 500, sampler, new Rectangle(0, 0, 100, 100), new Rectangle(0, 0, 500, 500)).Save(output);
}
Trace.WriteLine($"{name}: {watch.ElapsedMilliseconds}ms");

Loading…
Cancel
Save