Browse Source

Resizer updates

Getting closer but still not quite right.


Former-commit-id: 7df2d4c45591ba8e71e073c29d61b73e25c38cf0
Former-commit-id: cb63ea1d1341f15a3b6d82fb6b0a6c842107bcf9
Former-commit-id: e3a69acf2949c0081381ca71214c673581712e93
pull/17/head
James Jackson-South 11 years ago
parent
commit
e3a2334ede
  1. 4
      src/ImageProcessor/Common/Helpers/PixelOperations.cs
  2. 2
      src/ImageProcessor/ParallelImageProcessor.cs
  3. 107
      src/ImageProcessor/Samplers/Resize.cs
  4. 12
      tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs
  5. 2
      tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs
  6. 1
      tests/ImageProcessor.Tests/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg.REMOVED.git-id
  7. BIN
      tests/ImageProcessor.Tests/TestImages/Formats/Png/gamma-1.0-or-2.2.png

4
src/ImageProcessor/Common/Helpers/PixelOperations.cs

@ -38,7 +38,7 @@ namespace ImageProcessor
// Create only once and lazily.
byte[] ramp = LinearBytes.Value;
return new Bgra(composite.B, ramp[composite.G], ramp[composite.R], ramp[composite.A]);
return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A);
}
/// <summary>
@ -55,7 +55,7 @@ namespace ImageProcessor
// Create only once and lazily.
byte[] ramp = SrgbBytes.Value;
return new Bgra(linear.B, ramp[linear.G], ramp[linear.R], ramp[linear.A]);
return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A);
}
/// <summary>

2
src/ImageProcessor/ParallelImageProcessor.cs

@ -67,7 +67,7 @@ namespace ImageProcessor
{
sourceRectangle = source.Bounds;
}
this.Parallelism = 1;
if (this.Parallelism > 1)
{
int partitionCount = this.Parallelism;

107
src/ImageProcessor/Samplers/Resize.cs

@ -63,8 +63,10 @@ namespace ImageProcessor.Samplers
int targetSectionHeight = endY - startY;
int sourceSectionHeight = (int)((targetSectionHeight * heightFactor) + .5);
Weights[] horizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width, this.Sampler);
Weights[] verticalWeights = this.PrecomputeWeights(targetSectionHeight, sourceSectionHeight, this.Sampler);
int offsetY = this.CalculateOffset(startY, targetSectionHeight, sourceSectionHeight);
int offsetX = this.CalculateOffset(startX, targetRectangle.Width, sourceRectangle.Width);
Weights[] horizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width);
Weights[] verticalWeights = this.PrecomputeWeights(targetSectionHeight, sourceSectionHeight);
// Width and height decreased by 1
int maxHeight = sourceHeight - 1;
@ -97,8 +99,8 @@ namespace ImageProcessor.Samplers
continue;
}
// TODO: This is wrong. Adding (int)((startY * heightFactor) - .5) gets close but no cigar.
int originY = yw.Index + (int)((startY * heightFactor) - .5);
// TODO: This offset is wrong.
int originY = offsetY == 0 ? yw.Index : yw.Index + offsetY;
originY = originY.Clamp(0, maxHeight);
foreach (Weight xw in horizontalValues)
@ -108,11 +110,13 @@ namespace ImageProcessor.Samplers
continue;
}
// TODO: This need updating to take into account the target rectangle.
int originX = xw.Index;
// TODO: This offset is wrong.
int originX = xw.Index + offsetX;
originX = originX.Clamp(0, maxWidth);
Bgra sourceColor = source[originX, originY];
sourceColor = PixelOperations.ToLinear(sourceColor);
r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum);
g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum);
b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum);
@ -121,6 +125,7 @@ namespace ImageProcessor.Samplers
}
Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte());
destinationColor = PixelOperations.ToSrgb(destinationColor);
target[x, y] = destinationColor;
}
}
@ -131,22 +136,16 @@ namespace ImageProcessor.Samplers
/// <summary>
/// Computes the weights to apply at each pixel when resizing.
/// </summary>
/// <param name="destinationSize">
/// The destination section size.
/// </param>
/// <param name="sourceSize">
/// The source section size.
/// </param>
/// <param name="sampler">
/// The <see cref="IResampler"/> containing the resampling algorithm.
/// </param>
/// <param name="destinationSize">The destination section size.</param>
/// <param name="sourceSize">The source section size.</param>
/// <returns>
/// The <see cref="T:Weights[]"/>.
/// </returns>
private Weights[] PrecomputeWeights(int destinationSize, int sourceSize, IResampler sampler)
private Weights[] PrecomputeWeights(int destinationSize, int sourceSize)
{
float du = sourceSize / (float)destinationSize;
float scale = du;
IResampler sampler = this.Sampler;
double du = sourceSize / (double)destinationSize;
double scale = du;
if (scale < 1)
{
@ -193,28 +192,92 @@ namespace ImageProcessor.Samplers
return result;
}
protected struct Weight
/// <summary>
/// Calculates the scaled offset caused by parallelism.
/// </summary>
/// <param name="offset">The offset position.</param>
/// <param name="destinationSize">The destination size.</param>
/// <param name="sourceSize">The source size.</param>
/// <returns>
/// The <see cref="int"/>.
/// </returns>
private int CalculateOffset(int offset, int destinationSize, int sourceSize)
{
public Weight(int index, double value)
if (offset == 0)
{
this.Index = index;
this.Value = value;
return 0;
}
IResampler sampler = this.Sampler;
double du = sourceSize / (double)destinationSize;
double scale = du;
if (scale < 1)
{
scale = 1;
}
double ru = Math.Ceiling(scale * sampler.Radius);
double fu = ((offset + .5) * du) - 0.5;
int result = (int)Math.Ceiling(fu - ru);
if (result < 0)
{
return 0;
}
return result;
}
/// <summary>
/// Represents the weight to be added to a scaled pixel.
/// </summary>
protected struct Weight
{
/// <summary>
/// The pixel index.
/// </summary>
public readonly int Index;
/// <summary>
/// The result of the interpolation algorithm.
/// </summary>
public readonly double Value;
/// <summary>
/// Initializes a new instance of the <see cref="Weight"/> struct.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="value">The value.</param>
public Weight(int index, double value)
{
this.Index = index;
this.Value = value;
}
}
/// <summary>
/// Represents a collection of weights and their sum.
/// </summary>
protected class Weights
{
/// <summary>
/// Initializes a new instance of the <see cref="Weights"/> class.
/// </summary>
public Weights()
{
this.Values = new List<Weight>();
}
/// <summary>
/// Gets or sets the values.
/// </summary>
public List<Weight> Values { get; set; }
/// <summary>
/// Gets or sets the sum.
/// </summary>
public double Sum { get; set; }
}
}

12
tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs

@ -19,11 +19,13 @@ namespace ImageProcessor.Tests
/// </summary>
public static readonly List<string> Files = new List<string>
{
//"../../TestImages/Formats/Jpg/Backdrop.jpg",
//"../../TestImages/Formats/Jpg/Calliphora.jpg",
//"../../TestImages/Formats/Bmp/Car.bmp",
//"../../TestImages/Formats/Png/cmyk.png",
//"../../TestImages/Formats/Gif/leaf.gif"
"../../TestImages/Formats/Jpg/Backdrop.jpg",
"../../TestImages/Formats/Jpg/Calliphora.jpg",
"../../TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg",
"../../TestImages/Formats/Bmp/Car.bmp",
"../../TestImages/Formats/Png/cmyk.png",
"../../TestImages/Formats/Png/gamma-1.0-or-2.2.png",
"../../TestImages/Formats/Gif/leaf.gif",
"../../TestImages/Formats/Gif/rings.gif"
// { "../../TestImages/Formats/Gif/ani.gif" },

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

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

1
tests/ImageProcessor.Tests/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg.REMOVED.git-id

@ -0,0 +1 @@
56cbc3371def2882d1ead5d4d2456550f2b8d72c

BIN
tests/ImageProcessor.Tests/TestImages/Formats/Png/gamma-1.0-or-2.2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Loading…
Cancel
Save