Jump to content

What does the "rect" parameter really work?


geist_

Recommended Posts

int num;

void Render(Surface dst, Surface src, Rectangle rect)
{
    for (int y = rect.Top; y < rect.Bottom; y++)
    {
        for (int x = rect.Left; x < rect.Right; x++)
        {
            num++; //for every pixel in your selection, increment this num variable
        }
    }

    #if DEBUG
    Debug.WriteLine(num);
    #endif
}

 

If you take a look at this code, the num variable should return the amount of pixels you have selected.  At first it only worked some of the time, and was confused as to why. But after some messing around I found out rect only contains the selected area visible to the user:

 

For example in a 64x64 image:

 

Running that code with the full image selected and with the full view of it

 

image.thumb.png.283936c828bd330af3108652ec5a8d83.png

 

Will return the correct number of pixels, 64 * 64 = 4096

 

But running the code with only a part of the image visible (while still selecting it whole):

 

image.thumb.png.717b49ad6d794841f74c42a22d89bad3.png

 

Will return the wrong number of pixels, because the effect only works on the currently visible selected area, despite still having the entire image selected.

 

Is there a way to get around this? without using src.Bounds and forcing a single render call (in order to work with none-rectangle selections)

the usual

 

0054-0133.gif

Link to comment
Share on other sites

10 minutes ago, geist_ said:

If you take a look at this code, the num variable should return the amount of pixels you have selected.

 

Nope.  It will return the number of pixels in the current ROI (rectangle of interest).

 

Please review this: https://boltbait.com/pdn/CodeLab/help/overview.php

 

BTW, if only part of an image is visible, the renderer will slice the image up into ROI's differently such that priority is given to the visible section of your image and those ROI's will be finished first.

 

Link to comment
Share on other sites

12 minutes ago, geist_ said:

Is there a way to get around this?

 

Well, there could be any number of "ways around this"... we just need to know what information you want:

 

Are you after the total number of pixels selected?

Does it need to take irregular selections into account, or would an overall rectangle be ok?

What is the purpose of knowing this information--how will it affect your render?

etc.

Link to comment
Share on other sites

 

 

Quote

BTW, if only part of an image is visible, the renderer will slice the image up into ROI's differently such that priority is given to the visible section of your image and those ROI's will be finished first.

 

ROI visible get priority, alright, but the rest of the ROI's never get passed as rect? otherwise how can i get each pixel from the current selection?

the usual

 

0054-0133.gif

Link to comment
Share on other sites

1 minute ago, BoltBait said:

 

Well, there could be any number of "ways around this"... we just need to know what information you want:

 

Are you after the total number of pixels selected?

Does it need to take irregular selections into account, or would an overall rectangle be ok?

What is the purpose of knowing this information--how will it affect your render?

etc.

 

1. No

2. Yes 

Quote

without using src.Bounds and forcing a single render call (in order to work with none-rectangle selections)

3. I want to work on CurrentPixel for every pixel in the entire selection

the usual

 

0054-0133.gif

Link to comment
Share on other sites

1 minute ago, geist_ said:

ROI visible get priority, alright, but the rest of the ROI's never get passed as rect? otherwise how can i get each pixel from the current selection?

 

You really should read all the tutorials I pointed you to above.  In those tutorials, it is explained that:

 

Your effect is run multi-threaded and each thread is given an ROI to work on.

 

 

 

Link to comment
Share on other sites

1 minute ago, geist_ said:

I want to work on CurrentPixel for every pixel in the entire selection

 

In this case, you should run CodeLab like this:

 

image.png

This will force your effect to run as a single thread and process the entire selection as a single ROI.

Link to comment
Share on other sites

Quote

In this case, you should run CodeLab like this:

 

image.png

 

This will force your effect to run as a single thread and process the entire selection as a single ROI.

 

I already tried working with Single Render Call

. It still returns an amount based off my view

Edited by geist_

the usual

 

0054-0133.gif

Link to comment
Share on other sites

Sounds like you need to move your processing into the PreRender().  You can read up on that here:

 

https://boltbait.com/pdn/CodeLab/help/tutorial3.php

 

and

 

https://forums.getpaint.net/topic/32107-how-to-write-an-effect-plugin-part-7-extra-surface/

 

Link to comment
Share on other sites

3 hours ago, geist_ said:

If you take a look at this code, the num variable should return the amount of pixels you have selected. 

 

It'd be simpler to multiply the width of the rectangle times its height instead of using a loop. What I think should work is to clear the count in PreRender, then in each Render call calculate its ROI rectangle size and add it into the count. However, I think you'll need to copy the pixels from src to dst in the Render calls. (I should know for sure if that's necessary, but off hand, I don't.) You can do the whole thing in PreRender, but it's a little more complicated, since you either have to test each pixel to see if it's selected (which is a inefficient test), or process the list of ROI rectangles.

Link to comment
Share on other sites

Quote

It'd be simpler to multiply the width of the rectangle times its height instead of using a loop.

Thank you, but that isn't what i'm trying to achieve. My main question was how the Render() function was called, since every time I ran my script, the result was based off my 

view of the image and not the selected area.

the usual

 

0054-0133.gif

Link to comment
Share on other sites

7 minutes ago, geist_ said:

My main question was how the Render() function was called, since every time I ran my script, the result was based off my 

view of the image and not the selected area.

 

I'm not quite sure what that means (or how the method of computing the rectangle size affects it), but if you read the tutorials, you'll see how Render is called. In summary, the selected region is divided into disjoint rectangles, and Render is called for each of those rectangles.

Link to comment
Share on other sites

4 minutes ago, MJW said:

 

I'm not quite sure what that means (or how the method of computing the rectangle size affects it), but if you read the tutorials, you'll see how Render is called. In summary, the selected region is divided into disjoint rectangles, and Render is called for each of those rectangles.

I have read the tutorials, but you seem to not have read my post?

Quote

the selected region is divided into disjoint rectangles, and Render is called for each of those rectangles.

I am fully aware of that - however - what the tutorial doesn't mention is that, those ROI are only from the "visible" selection from the perspective of the user.

the usual

 

0054-0133.gif

Link to comment
Share on other sites

1 hour ago, geist_ said:

I am fully aware of that - however - what the tutorial doesn't mention is that, those ROI are only from the "visible" selection from the perspective of the user.

 

I'm pretty certain that's wrong. Your attempt at computing the selection size doesn't work with multi-processing, since multiple Render routine calls are writing to the same variable. What you're seeing is, I believe, a result of the selected canvas being processed as a single ROI in the first instance, and two ROIs in the second. If what you say were true, then running a plugin on a partially visible image wouldn't change the pixels in the non-visible region. You can easily confirm that the entire selected region -- visible or not -- is processed.

 

(I hypothesize that when part of the image isn't visible, PDN processes the visible area first to give the user a quicker visible response.)

Link to comment
Share on other sites

Quote

Your attempt at computing the selection size doesn't work with multi-processing, since multiple Render routine calls are writing to the same variable

oh so is that it? multiple threads can't write to the same variable? nvm then lol

 

What bugs me, is that even when I tried running it with Force Single Render Call (or building it in a .dll with single render call enabled) it still called Render multiple times 

the usual

 

0054-0133.gif

Link to comment
Share on other sites

2 hours ago, geist_ said:

oh so is that it? multiple threads can't write to the same variable?

 

They can write to the same variable, but since the variable is shared between them, and not individual to each thread, they'll write on top of each other. The value will be whatever was written last. If it were a local variable, rather than a class-level variable, each thread would have its own copy. But, of course, the variable would be lost as soon as the particular Render call exited.

Link to comment
Share on other sites

2 hours ago, geist_ said:

What bugs me, is that even when I tried running it with Force Single Render Call (or building it in a .dll with single render call enabled) it still called Render multiple times 

 

For reasons which I do not know (though I expect they are good ones), when a plugin is called, a rendering pass is often started, then aborted, and another pass is begun. Perhaps that's what's happening. (By a rendering pass, I mean an attempt to render the full image -- the thing that happens each time a control is changed.)

  • Like 1
Link to comment
Share on other sites

48 minutes ago, MJW said:

 

For reasons which I do not know (though I expect they are good ones), when a plugin is called, a rendering pass is often started, then aborted, and another pass is begun. Perhaps that's what's happening. (By a rendering pass, I mean an attempt to render the full image -- the thing that happens each time a control is changed.)

I'm very glad you pointed this out, my script has a Drop-Down List Box options control, and every time i change that option, it gets called with the previous option again, then with the new one. Do you happen to know a way to prevent this? perhaps @BoltBait you could know? Last question i promise <3

the usual

 

0054-0133.gif

Link to comment
Share on other sites

To count the pixels that are contained in the selection, you don't need to use the rois parameter.

 

For a classic effect (a pre-v5.0 effect), which is what you're using, you can access all of the rectangles of the selection via this.EnvironmentParameters.GetSelectionAsPdnRegion().GetRegionScansInt() and then just do whatever you need with the list of rectangles. So do a foreach over them and add up the Width*Height or whatever (I recommend casting Width and Height to long, and summing into a long, not an int, otherwise your code will fail on larger images).

 

For modern effects (BitmapEffect and GpuEffect in PDNv5), once CodeLab supports these you'll have a slightly different way of retrieving this, but it's fundamentally the same thing.

The Paint.NET Blog: https://blog.getpaint.net/

Donations are always appreciated! https://www.getpaint.net/donate.html

forumSig_bmwE60.jpg

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...