Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ protected override void OnFrameApply(ImageFrame<TPixel> source)
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha);
ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration,
interest,
in operation);
this.Configuration,
interest,
in operation);

Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ internal EdgeDetector2DProcessor(
/// <inheritdoc/>
protected override void BeforeImageApply()
{
using (IImageProcessor<TPixel> opaque = new OpaqueProcessor<TPixel>(this.Configuration, this.Source, this.SourceRectangle))
{
opaque.Execute();
}

if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ internal EdgeDetectorCompassProcessor(Configuration configuration, CompassKernel
/// <inheritdoc/>
protected override void BeforeImageApply()
{
using (IImageProcessor<TPixel> opaque = new OpaqueProcessor<TPixel>(this.Configuration, this.Source, this.SourceRectangle))
{
opaque.Execute();
}

if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public EdgeDetectorProcessor(
/// <inheritdoc/>
protected override void BeforeImageApply()
{
using (IImageProcessor<TPixel> opaque = new OpaqueProcessor<TPixel>(this.Configuration, this.Source, this.SourceRectangle))
{
opaque.Execute();
}

if (this.Grayscale)
{
new GrayscaleBt709Processor(1F).Execute(this.Configuration, this.Source, this.SourceRectangle);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.

using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;

namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
internal sealed class OpaqueProcessor<TPixel> : ImageProcessor<TPixel>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't be MakeOpaqueProcessor better? (Related extension to be added later: image.MakeOpaque().)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can do that if/when we choose to expose such an extension.

where TPixel : unmanaged, IPixel<TPixel>
{
public OpaqueProcessor(
Configuration configuration,
Image<TPixel> source,
Rectangle sourceRectangle)
: base(configuration, source, sourceRectangle)
{
}

protected override void OnFrameApply(ImageFrame<TPixel> source)
{
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());

var operation = new OpaqueRowOperation(this.Configuration, source, interest);
ParallelRowIterator.IterateRows<OpaqueRowOperation, Vector4>(this.Configuration, interest, in operation);
}

private readonly struct OpaqueRowOperation : IRowOperation<Vector4>
{
private readonly Configuration configuration;
private readonly ImageFrame<TPixel> target;
private readonly Rectangle bounds;

[MethodImpl(InliningOptions.ShortMethod)]
public OpaqueRowOperation(
Configuration configuration,
ImageFrame<TPixel> target,
Rectangle bounds)
{
this.configuration = configuration;
this.target = target;
this.bounds = bounds;
}

/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int y, Span<Vector4> span)
{
Span<TPixel> targetRowSpan = this.target.GetPixelRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Scale);
ref Vector4 baseRef = ref MemoryMarshal.GetReference(span);

for (int x = 0; x < this.bounds.Width; x++)
{
ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
v.W = 1F;
}

PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan, PixelConversionModifiers.Scale);
Comment on lines +54 to +63
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet another place where an extended PixelTypeInfo would be super useful to eliminate unnecessary scanning. Related discussion.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup.

}
}
}
}
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 All @@ -25,15 +25,6 @@ public class EntropyCropTest
public void EntropyCrop<TPixel>(TestImageProvider<TPixel> provider, float value)
where TPixel : unmanaged, IPixel<TPixel>
{
// The result dimensions of EntropyCrop may differ on .NET Core 3.1 because of unstable edge detection results.
// TODO: Re-enable this test case if we manage to improve stability.
#if SUPPORTS_RUNTIME_INTRINSICS
if (provider.SourceFileOrDescription.Contains(TestImages.Png.Ducky))
{
return;
}
#endif

provider.RunValidatingProcessorTest(x => x.EntropyCrop(value), value, appendPixelTypeToFileName: false);
}
}
Expand Down