diff --git a/src/ImageProcessor/Common/Helpers/PixelOperations.cs b/src/ImageProcessor/Common/Helpers/PixelOperations.cs index 0c4197de96..6352025d52 100644 --- a/src/ImageProcessor/Common/Helpers/PixelOperations.cs +++ b/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); } /// @@ -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); } /// diff --git a/src/ImageProcessor/ParallelImageProcessor.cs b/src/ImageProcessor/ParallelImageProcessor.cs index fa224b44ae..72722dd916 100644 --- a/src/ImageProcessor/ParallelImageProcessor.cs +++ b/src/ImageProcessor/ParallelImageProcessor.cs @@ -67,7 +67,7 @@ namespace ImageProcessor { sourceRectangle = source.Bounds; } - this.Parallelism = 1; + if (this.Parallelism > 1) { int partitionCount = this.Parallelism; diff --git a/src/ImageProcessor/Samplers/Resize.cs b/src/ImageProcessor/Samplers/Resize.cs index cdcdd4f46e..da62075666 100644 --- a/src/ImageProcessor/Samplers/Resize.cs +++ b/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 /// /// Computes the weights to apply at each pixel when resizing. /// - /// - /// The destination section size. - /// - /// - /// The source section size. - /// - /// - /// The containing the resampling algorithm. - /// + /// The destination section size. + /// The source section size. /// /// The . /// - 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 + /// + /// Calculates the scaled offset caused by parallelism. + /// + /// The offset position. + /// The destination size. + /// The source size. + /// + /// The . + /// + 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; + } + + /// + /// Represents the weight to be added to a scaled pixel. + /// + protected struct Weight + { + /// + /// The pixel index. + /// public readonly int Index; + /// + /// The result of the interpolation algorithm. + /// public readonly double Value; + + /// + /// Initializes a new instance of the struct. + /// + /// The index. + /// The value. + public Weight(int index, double value) + { + this.Index = index; + this.Value = value; + } } + /// + /// Represents a collection of weights and their sum. + /// protected class Weights { + /// + /// Initializes a new instance of the class. + /// public Weights() { this.Values = new List(); } + /// + /// Gets or sets the values. + /// public List Values { get; set; } + /// + /// Gets or sets the sum. + /// public double Sum { get; set; } } } diff --git a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs index da88b7c94f..01c38bd436 100644 --- a/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs +++ b/tests/ImageProcessor.Tests/Processors/ProcessorTestBase.cs @@ -19,11 +19,13 @@ namespace ImageProcessor.Tests /// public static readonly List Files = new List { - //"../../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" }, diff --git a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs index 881e45bdb3..0ce2733468 100644 --- a/tests/ImageProcessor.Tests/Processors/Samplers/SamplerTests.cs +++ b/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"); diff --git a/tests/ImageProcessor.Tests/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg.REMOVED.git-id b/tests/ImageProcessor.Tests/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg.REMOVED.git-id new file mode 100644 index 0000000000..c6c87c96c7 --- /dev/null +++ b/tests/ImageProcessor.Tests/TestImages/Formats/Jpg/gamma_dalai_lama_gray.jpg.REMOVED.git-id @@ -0,0 +1 @@ +56cbc3371def2882d1ead5d4d2456550f2b8d72c \ No newline at end of file diff --git a/tests/ImageProcessor.Tests/TestImages/Formats/Png/gamma-1.0-or-2.2.png b/tests/ImageProcessor.Tests/TestImages/Formats/Png/gamma-1.0-or-2.2.png new file mode 100644 index 0000000000..6d2ba91fb1 Binary files /dev/null and b/tests/ImageProcessor.Tests/TestImages/Formats/Png/gamma-1.0-or-2.2.png differ