PhilipLB Posted March 5, 2008 Share Posted March 5, 2008 Hi, for my plugin I need the min- and maxvalues of R,G,B, so I need to loop over the whole source. How do I do that? The render-function seems to be called often and srcArgs.Surface seems to contain only the current tile. I tried this, but this is very slow and crashes: for (int y = 0; y < srcArgs.Bitmap.Height; ++y) { for (int x = 0; x < srcArgs.Bitmap.Width; ++x) { r = srcArgs.Bitmap.GetPixel(x, y).R; g = srcArgs.Bitmap.GetPixel(x, y).G; b = srcArgs.Bitmap.GetPixel(x, y).B; if (r < minR) { minR = r; } if (g < minG) { minG = g; } if (b < minB) { minB = b; } if (r > maxR) { maxR = r; } if (g > maxG) { maxG = g; } if (b > maxB) { maxB = b; } } } And if I'm right with my tile-suspicion, it would be kinda unessessary to determine the min- and maxvalues every time render is called. Is there any way to do this only once? //Edit: Ok, found a way to actually debug some values within a dll, sry, C#-beginner. render() is actually called ca a million times. Each time the srcArgs.Surface has the same width and height as the original image. This is weird because it means tiles seems not the reason for the many calls? //Edit2: "Solved" it now with some private class variables and a flag which indicates, whether it is the first call of render. Kinda ugly though. Quote Link to comment Share on other sites More sharing options...
jchunn Posted March 6, 2008 Share Posted March 6, 2008 Sorry for double post... see next post. Quote Total hack. Link to comment Share on other sites More sharing options...
jchunn Posted March 6, 2008 Share Posted March 6, 2008 Put the part of the code that you only want to execute once in the "OnSetRenderInfo" method (instead of the "OnRender" method). OnSetRenderInfo only executes once per render (before OnRender starts getting called), whereas OnRender executes multiple times per render. Save the max values at the module level, and use the values in OnRender. Quote Total hack. Link to comment Share on other sites More sharing options...
pyrochild Posted March 6, 2008 Share Posted March 6, 2008 Instead of looping through the whole image each time Render is called, you should only loop through the pixels passed by the array of Rectangles passed to the method. Otherwise, you're processing the entire image hundreds of times. Put the part of the code that you only want to execute once in the "OnSetRenderInfo" method (instead of the "OnRender" method). OnSetRenderInfo only executes once per render (before OnRender starts getting called), whereas OnRender executes multiple times per render. Save the max values at the module level, and use the values in OnRender. Don't do that unless you absolutely must. It's not multi-threaded. Render is automatically multithreaded, and will give better performance. Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
PhilipLB Posted March 6, 2008 Author Share Posted March 6, 2008 I stayed with my first solution with the flag. A private boolean, which indicates, whether it's the first call of the render-function. If so, I loop over so whole Sourceimage to determine the min- and maxvalues of the pixels. Quote Link to comment Share on other sites More sharing options...
jchunn Posted March 6, 2008 Share Posted March 6, 2008 Instead of looping through the whole image each time Render is called, you should only loop through the pixels passed by the array of Rectangles passed to the method. Otherwise, you're processing the entire image hundreds of times. Yes, that was in my original post, but I deleted it once I understood that what he is trying to do is just get the "min" and "max" rgb values from the entire image (all pixels), and he didn't want to do that for every call to OnRender, since he only needed to do that once. In other words, as you know, you are correct, and I agree. Put the part of the code that you only want to execute once in the "OnSetRenderInfo" method (instead of the "OnRender" method). OnSetRenderInfo only executes once per render (before OnRender starts getting called), whereas OnRender executes multiple times per render. Save the max values at the module level, and use the values in OnRender. Don't do that unless you absolutely must. It's not multi-threaded. Render is automatically multithreaded, and will give better performance. True, but this is a case where it makes much more sense to do it in the OnSetRenderInfo. It is no better or worse, performance-wise, than trying to figure out if this is the first time you are entering the "OnRender" method and just doing it one time in that method. Either way, you are executing the code exactly once, and by doing it in the OnSetRenderInfo, you actually eliminate the need to run logic multiple times to determine whether this is the first pass in OnRender or not, so overall performance would actually be (negligably) better by doing it in OnSetRenderInfo. The problem, however, is that it is possible that the second call to OnRender could complete before the first call has completed, because the first call will be MUCH slower since it has to iterate through the entire image. In that case, the threading model would introduce a bug that would be difficult to debug. Since his "min" and "max" values are not yet set, any "OnRender" calls that completed before the first one would have bad data, and the only fix would be to go back to using OnSetRenderInfo, or create a "hack" to delay all other threads until the first thread completes. OnSetRenderInfo is garaunteed to complete before the first call to OnRender, so that is what I would recommend. Quote Total hack. Link to comment Share on other sites More sharing options...
PhilipLB Posted March 6, 2008 Author Share Posted March 6, 2008 Oh, thanks for that hint. Yeah, sure, of course this can happen. I'll switch to OnSetRenderInfo then. Quote Link to comment Share on other sites More sharing options...
pyrochild Posted March 6, 2008 Share Posted March 6, 2008 ...once I understood that what he is trying to do is just get the "min" and "max" rgb values from the entire image (all pixels), and he didn't want to do that for every call to OnRender, since he only needed to do that once. Oh. I didn't bother reading the code... silly me. @PhilipLB: in that case, do it in OnSetRenderInfo, as jchunn said. hehe Quote ambigram signature by Kemaru [i write plugins and stuff] If you like a post, upvote it! Link to comment Share on other sites More sharing options...
jchunn Posted March 6, 2008 Share Posted March 6, 2008 ...once I understood that what he is trying to do is just get the "min" and "max" rgb values from the entire image (all pixels), and he didn't want to do that for every call to OnRender, since he only needed to do that once. Oh. I didn't bother reading the code... silly me. @PhilipLB: in that case, do it in OnSetRenderInfo, as jchunn said. hehe Don't feel bad... I made the exact same mistake with my first (deleted) response :oops: Quote Total hack. Link to comment Share on other sites More sharing options...
PhilipLB Posted March 6, 2008 Author Share Posted March 6, 2008 Yeah, sorry, wrote a bit confusing, I'm new to the API of Paint.NET and actually new to C#. I wrote only a few plugins for TheGIMP in C so far. Quote Link to comment Share on other sites More sharing options...
Rick Brewster Posted March 7, 2008 Share Posted March 7, 2008 For two pass effects of (1) analysis and (2) rendering, it is most appropriate to do the first pass in OnSetRenderInfo(). Quote The Paint.NET Blog: https://blog.getpaint.net/ Donations are always appreciated! https://www.getpaint.net/donate.html Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.