Skip to content

Commit

Permalink
Processors refactoring (#983)
Browse files Browse the repository at this point in the history
* Added new properties to ImageProcessor<TPixel>

* Fixed constructors for convolution processors

* Fixed constructors for binarization processors

* Fixed constructor for dithering processor

* Fixed constructors for effects processors

* Fixed constructor for filter processor

* Fixed constructor for normalization processor

* Fixed constructors for overlay processors

* Fixed constructor for quantization processor

* Fixed constructors for transforms processors

* Updated CreatePixelSpecificProcessor<TPixel> definition

* Fixed convolution processors creation

* Fixed leftover dithering processor constructor

* Fixed another leftover dithering processor constructor

* Fixed dithering processors creation

* Fixed effects processors creation

* Fixed filters processor

* Fixed normalization processors creation

* Fixed overlays processors creation

* Fixed quantizer processor creation

* Fixed constructors for some remaining processors

* Fixed transform processors creation

* ImageProcessor class refactored

* Renamed some parameters

* Convolution processors refactored

* Refactored filters and dithering processors

* Refactored normalization processors

* Overlays processors refactored

* Renamed some parameters

* CloningImageProcessor class refactored

* Transforms processors refactored

* Updated DefaultImageProcessingContext class

* Src builds, tests still require updating.

* Fix tests

* Removed unnecessary local variable
  • Loading branch information
Sergio0694 authored and JimBobSquarePants committed Aug 25, 2019
1 parent 79f5ff5 commit 13989ac
Show file tree
Hide file tree
Showing 101 changed files with 961 additions and 891 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using SixLabors.ImageSharp.PixelFormats;
Expand Down Expand Up @@ -59,10 +59,10 @@ public DrawImageProcessor(
public float Opacity { get; }

/// <inheritdoc />
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>()
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Image<TPixelBg> source, Rectangle sourceRectangle)
where TPixelBg : struct, IPixel<TPixelBg>
{
var visitor = new ProcessorFactoryVisitor<TPixelBg>(this);
var visitor = new ProcessorFactoryVisitor<TPixelBg>(this, source, sourceRectangle);
this.Image.AcceptVisitor(visitor);
return visitor.Result;
}
Expand All @@ -71,10 +71,14 @@ private class ProcessorFactoryVisitor<TPixelBg> : IImageVisitor
where TPixelBg : struct, IPixel<TPixelBg>
{
private readonly DrawImageProcessor definition;
private readonly Image<TPixelBg> source;
private readonly Rectangle sourceRectangle;

public ProcessorFactoryVisitor(DrawImageProcessor definition)
public ProcessorFactoryVisitor(DrawImageProcessor definition, Image<TPixelBg> source, Rectangle sourceRectangle)
{
this.definition = definition;
this.source = source;
this.sourceRectangle = sourceRectangle;
}

public IImageProcessor<TPixelBg> Result { get; private set; }
Expand All @@ -84,11 +88,13 @@ public void Visit<TPixelFg>(Image<TPixelFg> image)
{
this.Result = new DrawImageProcessor<TPixelBg, TPixelFg>(
image,
this.source,
this.sourceRectangle,
this.definition.Location,
this.definition.ColorBlendingMode,
this.definition.AlphaCompositionMode,
this.definition.Opacity);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,24 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
where TPixelFg : struct, IPixel<TPixelFg>
{
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelDst, TPixelSrc}"/> class.
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelBg, TPixelFg}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="image">The foreground <see cref="Image{TPixelFg}"/> to blend with the currently processing image.</param>
/// <param name="source">The source <see cref="Image{TPixelBg}"/> for the current processor instance.</param>
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(
Image<TPixelFg> image,
Image<TPixelBg> source,
Rectangle sourceRectangle,
Point location,
PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode,
float opacity)
: base(source, sourceRectangle)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));

Expand Down Expand Up @@ -63,11 +68,11 @@ public DrawImageProcessor(
public Point Location { get; }

/// <inheritdoc/>
protected override void OnFrameApply(
ImageFrame<TPixelBg> source,
Rectangle sourceRectangle,
Configuration configuration)
protected override void OnFrameApply(ImageFrame<TPixelBg> source)
{
Rectangle sourceRectangle = this.SourceRectangle;
Configuration configuration = this.Configuration;

Image<TPixelFg> targetImage = this.Image;
PixelBlender<TPixelBg> blender = this.Blender;
int locationY = this.Location.Y;
Expand Down Expand Up @@ -101,11 +106,10 @@ protected override void OnFrameApply(
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixelBg> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixelFg> foreground =
targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
Span<TPixelFg> foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend<TPixelFg>(configuration, background, background, foreground, this.Opacity);
}
});
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;

namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
Expand Down Expand Up @@ -33,10 +34,10 @@ public FillProcessor(IBrush brush, GraphicsOptions options)
public GraphicsOptions Options { get; }

/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new FillProcessor<TPixel>(this);
return new FillProcessor<TPixel>(this, source, sourceRectangle);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ internal class FillProcessor<TPixel> : ImageProcessor<TPixel>
{
private readonly FillProcessor definition;

public FillProcessor(FillProcessor definition)
public FillProcessor(FillProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(source, sourceRectangle)
{
this.definition = definition;
}

/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
Rectangle sourceRectangle = this.SourceRectangle;
Configuration configuration = this.Configuration;
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
int startY = sourceRectangle.Y;
Expand Down Expand Up @@ -115,4 +118,4 @@ private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush)
return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;

namespace SixLabors.ImageSharp.Processing.Processors.Drawing
{
Expand Down Expand Up @@ -41,10 +42,10 @@ public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options)
public GraphicsOptions Options { get; }

/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new FillRegionProcessor<TPixel>(this);
return new FillRegionProcessor<TPixel>(this, source, sourceRectangle);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,16 @@ internal class FillRegionProcessor<TPixel> : ImageProcessor<TPixel>
{
private readonly FillRegionProcessor definition;

public FillRegionProcessor(FillRegionProcessor definition)
public FillRegionProcessor(FillRegionProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(source, sourceRectangle)
{
this.definition = definition;
}

/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
Configuration configuration = this.Configuration;
GraphicsOptions options = this.definition.Options;
IBrush brush = this.definition.Brush;
Region region = this.definition.Region;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors.
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
Expand Down Expand Up @@ -72,10 +72,10 @@ public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IB
public PointF Location { get; }

/// <inheritdoc />
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>()
public IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>(Image<TPixel> source, Rectangle sourceRectangle)
where TPixel : struct, IPixel<TPixel>
{
return new DrawTextProcessor<TPixel>(this);
return new DrawTextProcessor<TPixel>(this, source, sourceRectangle);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ internal class DrawTextProcessor<TPixel> : ImageProcessor<TPixel>

private readonly DrawTextProcessor definition;

public DrawTextProcessor(DrawTextProcessor definition)
public DrawTextProcessor(DrawTextProcessor definition, Image<TPixel> source, Rectangle sourceRectangle)
: base(source, sourceRectangle)
{
this.definition = definition;
}
Expand All @@ -44,35 +45,35 @@ public DrawTextProcessor(DrawTextProcessor definition)

private IBrush Brush => this.definition.Brush;

protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
protected override void BeforeImageApply()
{
base.BeforeImageApply(source, sourceRectangle);
base.BeforeImageApply();

// do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
{
ApplyKerning = this.Options.ApplyKerning,
TabWidth = this.Options.TabWidth,
WrappingWidth = this.Options.WrapTextWidth,
HorizontalAlignment = this.Options.HorizontalAlignment,
VerticalAlignment = this.Options.VerticalAlignment
};

this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null);
{
ApplyKerning = this.Options.ApplyKerning,
TabWidth = this.Options.TabWidth,
WrappingWidth = this.Options.WrapTextWidth,
HorizontalAlignment = this.Options.HorizontalAlignment,
VerticalAlignment = this.Options.VerticalAlignment
};

this.textRenderer = new CachingGlyphRenderer(this.Source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null);
this.textRenderer.Options = (GraphicsOptions)this.Options;
var renderer = new TextRenderer(this.textRenderer);
renderer.RenderText(this.Text, style);
}

protected override void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
protected override void AfterImageApply()
{
base.AfterImageApply(source, sourceRectangle);
base.AfterImageApply();
this.textRenderer?.Dispose();
this.textRenderer = null;
}

/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
protected override void OnFrameApply(ImageFrame<TPixel> source)
{
// this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome
Draw(this.textRenderer.FillOperations, this.Brush);
Expand All @@ -82,7 +83,7 @@ void Draw(List<DrawingOperation> operations, IBrush brush)
{
if (operations?.Count > 0)
{
using (BrushApplicator<TPixel> app = brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options))
using (BrushApplicator<TPixel> app = brush.CreateApplicator(source, this.SourceRectangle, this.textRenderer.Options))
{
foreach (DrawingOperation operation in operations)
{
Expand Down Expand Up @@ -279,19 +280,19 @@ public void EndGlyph()
if (this.renderFill)
{
this.FillOperations.Add(new DrawingOperation
{
Location = this.currentRenderPosition,
Map = renderData.FillMap
});
{
Location = this.currentRenderPosition,
Map = renderData.FillMap
});
}

if (this.renderOutline)
{
this.OutlineOperations.Add(new DrawingOperation
{
Location = this.currentRenderPosition,
Map = renderData.OutlineMap
});
{
Location = this.currentRenderPosition,
Map = renderData.OutlineMap
});
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/ImageSharp/Advanced/AotCompilerTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,8 @@ private static void AotCompilePixelOperations<TPixel>()
private static void AotCompileResizeOperations<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
var resizeProcessor = new ResizeProcessor(new ResizeOptions(), default);
var genericResizeProcessor = new ResizeProcessor<TPixel>((ResizeProcessor)resizeProcessor.CreatePixelSpecificProcessor<TPixel>());
genericResizeProcessor.AotCreateDestination(new Image<TPixel>(0, 0), default);
var genericResizeProcessor = (ResizeProcessor<TPixel>)new ResizeProcessor(new ResizeOptions(), default).CreatePixelSpecificProcessor(new Image<TPixel>(0, 0), default);
genericResizeProcessor.AotCreateDestination();
}
}
}
26 changes: 8 additions & 18 deletions src/ImageSharp/Processing/DefaultImageProcessorContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,43 +53,33 @@ public Image<TPixel> GetResultImage()
/// <inheritdoc/>
public Size GetCurrentSize() => this.GetCurrentBounds().Size;

public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
{
var processorImplementation = processor.CreatePixelSpecificProcessor<TPixel>();
return this.ApplyProcessor(processorImplementation, rectangle);
}

/// <inheritdoc/>
public IImageProcessingContext ApplyProcessor(IImageProcessor processor)
{
var processorImplementation = processor.CreatePixelSpecificProcessor<TPixel>();
return this.ApplyProcessor(processorImplementation);
return this.ApplyProcessor(processor, this.GetCurrentBounds());
}

private IImageProcessingContext ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle)
/// <inheritdoc/>
public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle)
{
if (!this.mutate && this.destination is null)
{
// This will only work if the first processor applied is the cloning one thus
// realistically for this optimization to work the resize must the first processor
// applied any only up processors will take the double data path.
if (processor is ICloningImageProcessor<TPixel> cloningImageProcessor)
if (processor.CreatePixelSpecificProcessor(this.source, rectangle) is ICloningImageProcessor<TPixel> cloningImageProcessor)
{
this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle);
this.destination = cloningImageProcessor.CloneAndApply();
return this;
}

this.destination = this.source.Clone();
}

processor.Apply(this.destination, rectangle);
processor.CreatePixelSpecificProcessor(this.destination, rectangle).Apply();
return this;
}

private IImageProcessingContext ApplyProcessor(IImageProcessor<TPixel> processor)
{
return this.ApplyProcessor(processor, this.GetCurrentBounds());
}

private Rectangle GetCurrentBounds() => this.destination?.Bounds() ?? this.source.Bounds();
}
}
}
Loading

0 comments on commit 13989ac

Please sign in to comment.