mirror of https://github.com/SixLabors/ImageSharp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
126 lines
4.8 KiB
126 lines
4.8 KiB
// <copyright file="ParallelImageProcessor.cs" company="James South">
|
|
// Copyright © James South and contributors.
|
|
// Licensed under the Apache License, Version 2.0.
|
|
// </copyright>
|
|
|
|
namespace ImageProcessor
|
|
{
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
|
|
/// <summary>
|
|
/// Allows the application of processors using parallel processing.
|
|
/// </summary>
|
|
public abstract class ParallelImageProcessor : IImageProcessor
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the count of workers to run the process in parallel.
|
|
/// </summary>
|
|
public int Parallelism { get; set; } = Environment.ProcessorCount;
|
|
|
|
/// <inheritdoc/>
|
|
public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle)
|
|
{
|
|
this.OnApply();
|
|
|
|
if (this.Parallelism > 1)
|
|
{
|
|
int partitionCount = this.Parallelism;
|
|
|
|
Task[] tasks = new Task[partitionCount];
|
|
|
|
for (int p = 0; p < partitionCount; p++)
|
|
{
|
|
int current = p;
|
|
tasks[p] = Task.Run(() =>
|
|
{
|
|
int batchSize = sourceRectangle.Height / partitionCount;
|
|
int yStart = sourceRectangle.Y + (current * batchSize);
|
|
int yEnd = current == partitionCount - 1 ? sourceRectangle.Bottom : yStart + batchSize;
|
|
|
|
this.Apply(target, source, target.Bounds, sourceRectangle, yStart, yEnd);
|
|
});
|
|
}
|
|
|
|
Task.WaitAll(tasks);
|
|
}
|
|
else
|
|
{
|
|
this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle))
|
|
{
|
|
this.OnApply();
|
|
|
|
byte[] pixels = new byte[width * height * 4];
|
|
target.SetPixels(width, height, pixels);
|
|
|
|
if (targetRectangle == Rectangle.Empty)
|
|
{
|
|
targetRectangle = target.Bounds;
|
|
}
|
|
|
|
if (sourceRectangle == Rectangle.Empty)
|
|
{
|
|
sourceRectangle = source.Bounds;
|
|
}
|
|
|
|
if (this.Parallelism > 1)
|
|
{
|
|
int partitionCount = this.Parallelism;
|
|
|
|
Task[] tasks = new Task[partitionCount];
|
|
|
|
for (int p = 0; p < partitionCount; p++)
|
|
{
|
|
int current = p;
|
|
tasks[p] = Task.Run(() =>
|
|
{
|
|
int batchSize = targetRectangle.Bottom / partitionCount;
|
|
int yStart = current * batchSize;
|
|
int yEnd = current == partitionCount - 1 ? targetRectangle.Bottom : yStart + batchSize;
|
|
|
|
this.Apply(target, source, targetRectangle, sourceRectangle, yStart, yEnd);
|
|
});
|
|
}
|
|
|
|
Task.WaitAll(tasks);
|
|
}
|
|
else
|
|
{
|
|
this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This method is called before the process is applied to prepare the processor.
|
|
/// </summary>
|
|
protected virtual void OnApply()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Applies the process to the specified portion of the specified <see cref="ImageBase"/> at the specified location
|
|
/// and with the specified size.
|
|
/// </summary>
|
|
/// <param name="target">Target image to apply the process to.</param>
|
|
/// <param name="source">The source image. Cannot be null.</param>
|
|
/// <param name="targetRectangle">
|
|
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
|
|
/// The image is scaled to fit the rectangle.
|
|
/// </param>
|
|
/// <param name="sourceRectangle">
|
|
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|
/// </param>
|
|
/// <param name="startY">The index of the row within the source image to start processing.</param>
|
|
/// <param name="endY">The index of the row within the source image to end processing.</param>
|
|
/// <remarks>
|
|
/// The method keeps the source image unchanged and returns the
|
|
/// the result of image process as new image.
|
|
/// </remarks>
|
|
protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY);
|
|
}
|
|
}
|
|
|