null54

Content Aware Fill (2017-06-07)

Recommended Posts

A problem that iy have with this plugin is that it immediately starts working when I change the settings, even if I am not done changing them, and then I have to wait a long time for it to finish only to update the settings again.

 

It would be better to have an "apply" button.

 

Share this post


Link to post
Share on other sites

Perhaps the algorithm affords a "draft quality" setting? (I'm not familiar with the algorithm though...)

 

Similar to how some of the other effects have a Quality slider.

Share this post


Link to post
Share on other sites
9 hours ago, alexo said:

A problem that iy have with this plugin is that it immediately starts working when I change the settings, even if I am not done changing them, and then I have to wait a long time for it to finish only to update the settings again.

 

The effect renders automatically because that is the expected behavior for all Paint.NET effects that do not show their own drawing surface.

If I were to add an apply button it would be controlled by a checkbox that disables the automatic rendering.

 

6 hours ago, Rick Brewster said:

Perhaps the algorithm affords a "draft quality" setting?

 

I could try to adjust the number of refinement passes and random points the algorithm will try when searching for matches.

Currently the algorithm uses 6 refinement passes and will try up to 500 random points if it does not find a match in the 16 neighboring points.

 

Unfortunately this algorithm only supports sequential processing of the image data, so it cannot use Paint.NET's multi-threaded rendering.

Share this post


Link to post
Share on other sites
2 hours ago, null54 said:

Unfortunately this algorithm only supports sequential processing of the image data, so it cannot use Paint.NET's multi-threaded rendering.

 

Sprinkle these throughout the algorithm?

 

if (IsCancelRequested) return;

 

Share this post


Link to post
Share on other sites
52 minutes ago, BoltBait said:

Sprinkle these throughout the algorithm?

 

That is what the plugin does when it is run as a repeat effect (in OnSetRenderInfo).

Because Paint.NET does not allow Effect plugins to report their own progress, the effect dialog uses a BackgroundWorker for rendering to allow its progress bar to be updated.

Currently the effect dialog does not tell the BackgroundWorker to abort and restart when the settings change, it only aborts the BackgroundWorker when the user cancels the dialog.

 

 

Share this post


Link to post
Share on other sites
18 hours ago, null54 said:

 

The effect renders automatically because that is the expected behavior for all Paint.NET effects that do not show their own drawing surface.

If I were to add an apply button it would be controlled by a checkbox that disables the automatic rendering.

 

The problem is that if I want to move the slider from the default 50 to say 12, the process starts as soon as I start moving the slider, before it reaches the mark.  Then I have to wait for it to finish (can take 20 second's or so),  then try to trigger it again, which is problem when the slider is already in the correct position, so I end up running it twice more.  It is an unnecessary inconvenience.

 

Share this post


Link to post
Share on other sites
16 hours ago, null54 said:

 

That is what the plugin does when it is run as a repeat effect (in OnSetRenderInfo).

Because Paint.NET does not allow Effect plugins to report their own progress, the effect dialog uses a BackgroundWorker for rendering to allow its progress bar to be updated.

Currently the effect dialog does not tell the BackgroundWorker to abort and restart when the settings change, it only aborts the BackgroundWorker when the user cancels the dialog.

 

 

 

Try this instead...

 

https://forums.getpaint.net/topic/112378-plugin-development-nuggets-of-wisdom-i-learned/?do=findComment&comment=542006

 

Share this post


Link to post
Share on other sites
2 hours ago, BoltBait said:

Try this instead...

 

Rendering in OnSetRenderInfo would break the progress reporting for the plugin.

 

 

Share this post


Link to post
Share on other sites

Well, I'm out of ideas on how to make your UI more responsive. :( 

  • Like 1

Share this post


Link to post
Share on other sites

You should be able to give the BackgroundWorker access to your Effect.IsCancelRequested. And then just stop what you're doing -- either return or `throw OperationCanceledException` (and catch it in an appropriate place).

  • Like 1

Share this post


Link to post
Share on other sites
3 hours ago, Rick Brewster said:

You should be able to give the BackgroundWorker access to your Effect.IsCancelRequested. And then just stop what you're doing -- either return or `throw OperationCanceledException` (and catch it in an appropriate place). 

 

The IsCancelRequested property would not help as I render to a temporary surface, and only call FinishTokenUpdate when the BackgroundWorker completes.

 

 

  • Like 1

Share this post


Link to post
Share on other sites

That sounds like the wrong way to architect this then. Rendering should happen in response to OnRender(). Even rendering in OnSetRenderInfo() isn't the right way to do things anymore now that IsCancelRequested exists.

  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, Rick Brewster said:

Even rendering in OnSetRenderInfo() isn't the right way to do things anymore now that IsCancelRequested exists. 

 

Unfortunately not all algorithms are compatible with the chunked rendering used by OnRender.

The algorithm used by this plugin performs multi-pass rendering on the selected area.

 

After some experimentation I determined that rendering in OnSetRenderInfo and adding an event to the effect class that allows the config dialog to receive the rendering progress appears to be the best approach to fixing the UI responsiveness.

This allows Paint.NET to handle the restarting the effect when the token changes while still allowing the dialog to display the rendering progress.

  • Like 1

Share this post


Link to post
Share on other sites
On 6/6/2018 at 8:26 AM, Rick Brewster said:

That sounds like the wrong way to architect this then. Rendering should happen in response to OnRender(). Even rendering in OnSetRenderInfo() isn't the right way to do things anymore now that IsCancelRequested exists.

 

IsCancelRequested currently works in OnSetRnderInfo, and at least originally was intended to be pollable from within OnSetRenderInfo:

 

On 12/28/2009 at 11:54 PM, Rick Brewster said:

.NET threads will correspond to Win32 threads. The abstraction between "managed thread ID" and "native thread ID" mapping does exist, but it only matters if you are doing custom .NET hosting, e.g. SQL Server. Also, .NET is not a virtual machine or environment, so you are doing yourself a disservice by thinking that way.

As a corollary, in Paint.NET you can be sure that a managed thread will not be "migrated" among native threads, or processes. Fibers are never used anywhere.

And you're right that Paint.NET has a lot of "ambitious ambiguity" in the contract. However, at this point (5 years later) it's safe to say:

1) OnSetRenderInfo() will always be called first, and always by itself.

2) OnRender() will be called next. The first ROI is always executed by itself. After that, parallelism ensues.

Also, the token that is given to the effect is a Clone() of the one from the effect config dialog. From there, each thread used for OnRender() has its own Clone() of the token.

So, there is some "bracketing" that takes place. You can be assured that calls to OnSetRenderInfo() and OnRender() will never overlap when drawn on a timeline.

Also, in v3.5.2 I am adding an IsCancelRequested property that you can poll from within OnSetRenderInfo() or OnRender(). The guarantee at that point is that when IsCancelRequested flips to true that any "in-flight" OnRender() calls will be discarded.

In a future version, I plan to redo the effect system to provide more control over execution and progress reporting type stuff. Basically you'll be given an object to report progress through, and a simple ReadPixels() / WritePixels() interface. From there, additional classes will be provided which will take care of chunking of ROIs, parallelism, etc. But at that point those things will be optional -- great for multipass effects, and also great for effects where a different ROI "chunking" strategy is preferred.

 

I certainly hope it will always work in OnSetRenderInfo.  As null54 points out, there are many very useful algorithms that require the entire canvas be processed at once, not in randomly-ordered pieces.

Share this post


Link to post
Share on other sites

I don't remember if IsCancelRequested works during OnSetRenderInfo. If it does, then everything's fine. Otherwise you won't be able to cancel out of your rendering until the first OnRender() call, which will be too late to maintain a good user experience.

  • Like 1

Share this post


Link to post
Share on other sites

IsCancelRequested works in OnSetRenderInfo. I tested it to make sure processing in OnSetRenderInfo is aborted when a control is changed. Perhaps I should say it worked as of Nov. 2016, since that's when I ran the test.

  • Like 1
  • Upvote 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now