ReMake Posted November 11, 2015 Share Posted November 11, 2015 (edited) How to create a plugin of the Sponge effect in CodeLab I wrote in tutorial CodeLab - First Steps (Sponge). In the end of this tutorial I recommended to apply the Oil Painting effect before you call the Sponge effect. When I read BoltBait's topic How to Write an Effect Plugin (Part 7 - Extra Surface), I understood how to create a plugin which combines two effects - Clouds and Oil Painting. EDIT: The first variant of this tutorial was based on BoltBait's How to Write an Effect Plugin (Part 7 - Extra Surface) tutorial. In this variant the Clouds effect was processed in OnSetRenderInfo function. toe_head2001 suggested to combine both effects in the Render loop. It has allowed to increase speed of effect. I have updated this tutorial. Start CodeLab (Effects-> Advanced-> CodeLab). Choose New in the menu File. In a dialogue box Script Editor click a No button. The dialogue box New Source (Template) will be presented to you. In the drop-down list choose Clouds and in the drop-down list Blend choose Multiply. Click the Generate Code button. We will get the following script of effect: // Name: // Submenu: // Author: // Title: // Desc: // Keywords: // URL: // Help: #region UICode IntSliderControl Amount1 = 250; // [2,1000] Scale DoubleSliderControl Amount2 = 0.5; // [0,1] Roughness BinaryPixelOp Amount3 = LayerBlendModeUtil.CreateCompositionOp(LayerBlendMode.Normal); // Blend Mode ReseedButtonControl Amount4 = 0; // [255] Reseed #endregion // Setup for calling the Render Clouds effect private CloudsEffect cloudsEffect = new CloudsEffect(); private PropertyCollection cloudsProps; // Setup for using Multiply blend op private BinaryPixelOp multiplyOp = LayerBlendModeUtil.CreateCompositionOp(LayerBlendMode.Multiply); // Here is the main render loop function void Render(Surface dst, Surface src, Rectangle rect) { // Call the Render Clouds function cloudsProps = cloudsEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken CloudsParameters = new PropertyBasedEffectConfigToken(cloudsProps); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Scale, Amount1); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Power, Amount2); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.BlendMode, Amount3); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Seed, (int)Amount4); cloudsEffect.SetRenderInfo(CloudsParameters, new RenderArgs(dst), new RenderArgs(src)); // Call the Clouds function using Black and White cloudsEffect.Render(new Rectangle[1] {rect},0,1); // Now in the main render loop, the dst canvas has a render of clouds for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra CurrentPixel = dst[x,y]; // TODO: Add additional pixel processing code here CurrentPixel = multiplyOp.Apply(src[x,y], CurrentPixel); dst[x,y] = CurrentPixel; } } } Open the designer interface (File -> User Interface Designer), select in it the Scale control and rename it to Brush Size. Set the maximum value to 100, set the default value to 25. Click the Update button. Select the second control. Select Integer Slider in the Control type box. Set the minimum value to 0, the maximum value to 10 and the default value to 0. Click the Update button. Remove the third and fourth controls - we don't need them. Select Integer Slider in the Control type box. Type Intensity in the Control name box. Set the maximum value to 255 and click the Add button. Select Integer Slider in the Control type box. Type Smoothness in the Control name box. Set the minimum value to 1, set the default value to 2 and the maximum value to 8. Click the Add button. Last two controls will be necessary for us later. Click button OK. Comment out or delete the following line: CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.BlendOp, Amount3); it isn't need to us any more. In the line CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Seed, (int)Amount4); write 255 instead of (int) Amount4. Since we changed the type of the variable Amount2, we will have to make a change in the next line: CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Power, Amount2); replacing Amount2 to (10 - Amount2) / 10.0 Let's convert our clouds to the black-and-white contrast image. For this purpose color components of pixel (R, G, В) will be necessary for us. If the components value is less than 128, we will set it to 0, otherwise - 255. Insert into the script the following block of codes instead of the comment //TODO: int A = CurrentPixel.A; // Convert to black-and-white contrast image int R = CurrentPixel.R < 128 ? 0 : 255; int G = CurrentPixel.G < 128 ? 0 : 255; int B = CurrentPixel.B < 128 ? 0 : 255; Now let's eliminate light areas in this image and restore our pixel from the updated values of the color components. Insert into the script the following block of codes before blend operation: // Eliminate light areas A = 255 - Math.Min(Math.Min(R, G), В); // Restore pixel CurrentPixel.R = Int32Util.ClampToByte(R); CurrentPixel.G = Int32Util.ClampToByte(G); CurrentPixel.B = Int32Util.ClampToByte(В); CurrentPixel.A = Int32Util.ClampToByte(A + Amount3 - 255); Fill the commented lines at the top of the script, for example, like these: // Name: Sponge // Submenu: Artistic // Author: ReMake // Title: Sponge v1.2 ReMake 2015 // Desc: The Paint.NET effect which simulates Sponge painting // Keywords: paint.net|effect|sponge // URL: http://www.getpaint.net/redirect/plugins.html If your effect has to have the help, add one more comment: // Help: The Paint.NET effect which simulates Sponge painting. Save this script with the Sponge_1 name and create a DLL file with the same name. Try how your effect works. Try to apply different settings for controls. Notice, visually appreciable change of intensity comes through each three-four units of variable Amount3. Let's remember it. Below are the most effective parameters ranges of our effect: - Brush Size - 20...32 - Intensity - 200...240 Let's modify our script with the received results. The code block of the user interface will look like this: #region UICode IntSliderControl Amount1 = 3; // [1,10] Brush Size IntSliderControl Amount2 = 7; // [0,10] Roughness IntSliderControl Amount3 = 5; // [0,15] Intensity IntSliderControl Amount4 = 2; // [1,8] Smoothness #endregion Change the following line in the script: CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Scale, Amount1 + 20); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Power, (10 - Amount2) / 10.0); CurrentPixel.A = Int32Util.ClampToByte(A + Amount3*3 - 240); For the further work we will need an auxiliary surface for our effect. Add in the script the next lines after UI code block: // Declare auxiliary surface private Surface aux; Our final script should look like this: // Name: Sponge // Submenu: Artistic // Author: ReMake // Title: Sponge v1.2 ReMake 2015 // Desc: The Paint.NET effect which simulates Sponge painting // Keywords: paint.net|effect|sponge // URL: http://www.getpaint.net/redirect/plugins.html // Help: The Paint.NET effect which simulates Sponge painting. #region UICode IntSliderControl Amount1 = 3; // [1,10] Brush Size IntSliderControl Amount2 = 7; // [0,10] Roughness IntSliderControl Amount3 = 5; // [0,15] Intensity IntSliderControl Amount4 = 3; // [1,8] Smoothness #endregion // Declare auxiliary surface private Surface aux; // Setup for calling the Render Clouds effect private CloudsEffect cloudsEffect = new CloudsEffect(); private PropertyCollection cloudsProps; // Setup for using Multiply blend op private BinaryPixelOp multiplyOp = LayerBlendModeUtil.CreateCompositionOp(LayerBlendMode.Multiply); // Here is the main render loop function void Render(Surface dst, Surface src, Rectangle rect) { // Call the Render Clouds function cloudsProps = cloudsEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken CloudsParameters = new PropertyBasedEffectConfigToken(cloudsProps); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Scale, Amount1 + 20); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Power, (10 - Amount2) / 10.0); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Seed, 255); cloudsEffect.SetRenderInfo(CloudsParameters, new RenderArgs(dst), new RenderArgs(src)); // Call the Clouds function using Black and White cloudsEffect.Render(new Rectangle[1] {rect},0,1); // Now in the main render loop, the dst canvas has a render of clouds for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra CurrentPixel = dst[x,y]; int A = CurrentPixel.A; // Convert to black-and-white contrast image int R = CurrentPixel.R < 128 ? 0 : 255; int G = CurrentPixel.G < 128 ? 0 : 255; int B = CurrentPixel.B < 128 ? 0 : 255; // Eliminate light areas A = 255 - Math.Min(Math.Min(R, G), В); // Restore pixel CurrentPixel.R = Int32Util.ClampToByte(R); CurrentPixel.G = Int32Util.ClampToByte(G); CurrentPixel.B = Int32Util.ClampToByte(В); CurrentPixel.A = Int32Util.ClampToByte(A + Amount3 * 3 - 240); CurrentPixel = multiplyOp.Apply(src[x,y], CurrentPixel); dst[x,y] = CurrentPixel; } } } Save this script with the Sponge name - maybe it will be necessary to you in the future. Now let's prepare our script to moving into Visual Studio. Open the dialogue box Building (File -> Save As DLL...). Click the Select icon link and select the icon (for example, like this: ). Click the View source check box and click the Build button. You will see a dialogue box containing all the source code that CodeLab prepared for you. Our script is ready to moving into Visual Studio. Copy this code (click on button ) and move it to a Visual Studio project how it's written in BoltBait's tutorial: CodeLab Tutorial Part 5 - Beyond CodeLab. Let's continue. Find the function named OnSetRenderInfo. Currently it looks like this: protected override void OnSetRenderInfo(PropertyBasedEffectConfigToken newToken, RenderArgs dstArgs, RenderArgs srcArgs) { Amount1 = newToken.GetProperty<Int32Property>(PropertyNames.Amount1).Value; Amount2 = newToken.GetProperty<Int32Property>(PropertyNames.Amount2).Value; Amount3 = newToken.GetProperty<Int32Property>(PropertyNames.Amount3).Value; Amount4 = newToken.GetProperty<Int32Property>(PropertyNames.Amount4).Value; base.OnSetRenderInfo(newToken, dstArgs, srcArgs); } We will use the following line to create the auxiliary surface: aux = new Surface(srcArgs.Size); Place this line before the base.OnSetRenderInfo call. Return to CodeLab and open in it the dialogue box New Source (Template). In the drop-down list choose Oil Painting and click the Generate Code button. Copy from the script this code block: // Setup for calling the Oil Painting effect OilPaintingEffect oilpaintEffect = new OilPaintingEffect(); PropertyCollection oilpaintProps = oilpaintEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken oilpaintParameters = new PropertyBasedEffectConfigToken(oilpaintProps); oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.BrushSize, Amount1); oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.Coarseness, Amount2); oilpaintEffect.SetRenderInfo(oilpaintParameters, new RenderArgs(dst), new RenderArgs(src)); // Call the Oil Painting function oilpaintEffect.Render(new Rectangle[1] {rect},0,1); // Now in the main render loop, the dst canvas has an oil painted version of the src canvas and paste it into Visual Studio before the comment // Call the Render Clouds function In the line oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.BrushSize, Amount1); change Amount1 to Amount4 and in the line oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.Coarseness, Amount2); change Amount2 to 3: oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.BrushSize, Amount4); oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.Coarseness, 3); In the line cloudsEffect.SetRenderInfo(CloudsParameters, new RenderArgs(dst), new RenderArgs(src)); change dst to aux, and src to dst. cloudsEffect.SetRenderInfo(CloudsParameters, new RenderArgs(aux), new RenderArgs(dst)); Now we should move Clouds from an auxiliary surface to the destination canvas. For this in the line ColorBgra CurrentPixel = dst[x, y]; change dst to aux: ColorBgra CurrentPixel = aux[x, y]; It's necessary to mix current pixel with appropriate pixel on the destination canvas. For this purpose replace a line CurrentPixel = multiplyOp.Apply(src[x,y], CurrentPixel); with the line CurrentPixel = multiplyOp.Apply(CurrentPixel, dst[x, y]); Our final render function should look like this: void Render(Surface dst, Surface src, Rectangle rect) { // Setup for calling the Oil Painting effect OilPaintingEffect oilpaintEffect = new OilPaintingEffect(); PropertyCollection oilpaintProps = oilpaintEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken oilpaintParameters = new PropertyBasedEffectConfigToken(oilpaintProps); oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.BrushSize, Amount4); oilpaintParameters.SetPropertyValue(OilPaintingEffect.PropertyNames.Coarseness, 3); oilpaintEffect.SetRenderInfo(oilpaintParameters, new RenderArgs(dst), new RenderArgs(src)); // Call the Oil Painting function oilpaintEffect.Render(new Rectangle[1] { rect }, 0, 1); // Now in the main render loop, the dst canvas has an oil painted version of the src canvas // Call the Render Clouds function cloudsProps = cloudsEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken CloudsParameters = new PropertyBasedEffectConfigToken(cloudsProps); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Scale, Amount1 + 20); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Power, (10 - Amount2) / 10.0); CloudsParameters.SetPropertyValue(CloudsEffect.PropertyNames.Seed, 255); cloudsEffect.SetRenderInfo(CloudsParameters, new RenderArgs(aux), new RenderArgs(dst)); // Call the Clouds function using Black and White cloudsEffect.Render(new Rectangle[1] {rect},0,1); // Now in the main render loop, the dst canvas has a render of clouds for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra CurrentPixel = aux[x, y]; int A = CurrentPixel.A; // Convert to black-and-white contrast image int R = CurrentPixel.R < 128 ? 0 : 255; int G = CurrentPixel.G < 128 ? 0 : 255; int B = CurrentPixel.B < 128 ? 0 : 255; // Eliminate light areas A = 255 - Math.Min(Math.Min(R, G), В); // Restore pixel CurrentPixel.R = Int32Util.ClampToByte(R); CurrentPixel.G = Int32Util.ClampToByte(G); CurrentPixel.B = Int32Util.ClampToByte(В); CurrentPixel.A = Int32Util.ClampToByte(A + Amount3 * 3 - 240); CurrentPixel = multiplyOp.Apply(CurrentPixel, dst[x, y]); dst[x, y] = CurrentPixel; } } } Save this solution and build your DLL from within Visual Studio. Try this effect in Paint.NET. The user interface of our new effect looks like this. The source image And this is result of effect's work. Thanks BoltBait for his excellent tutorials. Edited July 8, 2020 by toe_head2001 Formatting 1 1 Quote Link to comment Share on other sites More sharing options...
Ego Eram Reputo Posted November 11, 2015 Share Posted November 11, 2015 Brilliant tutorial ReMake! Thank you so much for writing it. It will be a fabulous resource for plugin authors wishing to migrate from CodeLab to Visual Studio. Bravo! 1 Quote ebook: Mastering Paint.NET | resources: Plugin Index | Stereogram Tut | proud supporter of Codelab plugins: EER's Plugin Pack | Planetoid | StickMan | WhichSymbol+ | Dr Scott's Markup Renderer | CSV Filetype | dwarf horde plugins: Plugin Browser | ShapeMaker Link to comment Share on other sites More sharing options...
ReMake Posted November 11, 2015 Author Share Posted November 11, 2015 Thank You, EER. In this case much more thanks deserves BoltBait for his How to Write an Effect Plugin (Part 7 - Extra Surface) tutorial. I'm only repeated it. 1 Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted November 15, 2015 Share Posted November 15, 2015 These three lines: int R = (int)(double)((CurrentPixel.R < 128) ? 0 : 255); int G = (int)(double)((CurrentPixel.G < 128) ? 0 : 255); int B = (int)(double)((CurrentPixel.B < 128) ? 0 : 255); Why do you have these casts here? You only have two possible values: 0 or 255. They are already compatible int values, so no need for '(int)'. And I have no idea why you have the '(double)'. Much cleaner code without the useless casts. If you wanted to, you can also remove the () around the inline If statements. int R = CurrentPixel.R < 128 ? 0 : 255; int G = CurrentPixel.G < 128 ? 0 : 255; int B = CurrentPixel.B < 128 ? 0 : 255; Why put the Clouds effect code in OnSetRenderInfo? You lose the advantage of using ROIS. Both can work perfectly fine in Render. Please tell me the rationale for this decision. 1 Quote (June 9th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
ReMake Posted November 15, 2015 Author Share Posted November 15, 2015 ...Much cleaner code without the useless casts. If you wanted to, you can also remove the () around the inline If statements... I agree, fixed. It's more elegant code. I was not very attentive. Why put the Clouds effect code in OnSetRenderInfo? You lose the advantage of using ROIS. Both can work perfectly fine in Render. Please tell me the rationale for this decision. From CodeLab Tutorial Part 3 - Complex by BoltBait: ...When designing a complex effect, you need to keep in mind the limitations of CodeLab and the Paint.NET effect system: Complex effects can call one built-in effect,... I don't know how to combine both effects in Render loop. Give me an example, please. I will be very thankful to you. 1 Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted November 15, 2015 Share Posted November 15, 2015 (edited) BoltBait's been smoking something. I have two in my Blur Fill effect. In this case they are daisy-chained, but they don't have to be. I take the 'enlargedSurface' which was prepared in OnSetRenderInfo, and input it into Gaussian Blur. It outputs to 'bluredSurface'. Then I take 'bluredSurface', and input it into Brightness and Contrast. It outputs to 'lightSurface'. 'lightSurface' is what I use in my x,y Loop. Here's the reduced example: void Render(Surface dst, Surface src, Rectangle rect) { // Setup for calling the Gaussian Blur effect GaussianBlurEffect blurEffect = new GaussianBlurEffect(); PropertyCollection blurProps = blurEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken BlurParameters = new PropertyBasedEffectConfigToken(blurProps); BlurParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount1); blurEffect.SetRenderInfo(BlurParameters, new RenderArgs(bluredSurface), new RenderArgs(enlargedSurface)); // Call the Gaussian Blur function blurEffect.Render(new Rectangle[1] { rect }, 0, 1); // Setup for calling the Brightness and Contrast Adjustment function BrightnessAndContrastAdjustment bacAdjustment = new BrightnessAndContrastAdjustment(); PropertyCollection bacProps = bacAdjustment.CreatePropertyCollection(); PropertyBasedEffectConfigToken bacParameters = new PropertyBasedEffectConfigToken(bacProps); bacParameters.SetPropertyValue(BrightnessAndContrastAdjustment.PropertyNames.Brightness, Amount2); bacParameters.SetPropertyValue(BrightnessAndContrastAdjustment.PropertyNames.Contrast, 0); bacAdjustment.SetRenderInfo(bacParameters, new RenderArgs(lightSurface), new RenderArgs(bluredSurface)); // Call the Brightness and Contrast Adjustment function bacAdjustment.Render(new Rectangle[1] { rect }, 0, 1); for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { dst[x, y] = normalOp.Apply(lightSurface[x, y], src[x, y]); } } } You can see the full file here:https://github.com/toehead2001/pdn-blur-fill/blob/master/BlurFill/BlurFill.cs Edited November 16, 2015 by toe_head2001 1 Quote (June 9th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
ReMake Posted November 15, 2015 Author Share Posted November 15, 2015 Thanks for the info, Kalama. I'll see it tomorrow. We now have a deep night. 1 Quote Link to comment Share on other sites More sharing options...
MJW Posted November 15, 2015 Share Posted November 15, 2015 (edited) BoltBait's been smoking something. I have two in my Blur Fill effect. In this case they are daisy-chained, but they don't have to be. I think BoltBait was talking about a limitation in CodeLab, where you can't create your own surfaces. EDIT: I took this out, because I thought maybe I was wrong, but I think it's correct, so I put it back in: I think, though, that even in CodeLab you could call multiple effects, provided that all but the first were adjustment-type effects (not necessarily in the Adjustment menu), which only use a single pixel as input to modify the same pixel. You could, I believe, call the effect with the dst surface as input and output. Perhaps I'm mistaken, but offhand I don't see why that wouldn't work. Edited November 16, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted November 16, 2015 Share Posted November 16, 2015 I think BoltBait was talking about a limitation in CodeLab, where you can't create your own surfaces. You can create your own surfaces in CodeLab, it's just that anything you do with them will have poor performance. I did this with my first release of Text Window, and then wised-up and started using OnSetRenderInfo for that sort of thing. You could, I believe, call the effect with the dst surface as input and output. Perhaps I'm mistaken, but offhand I don't see why that wouldn't work. I tried this a few months ago, and it didn't work... at least for what I was doing. I don't remember the details though. Quote (June 9th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
MJW Posted November 16, 2015 Share Posted November 16, 2015 It seems to work for the case I tried. The following plugin has an initial blur, followed by a brightness and contrast adjustment, and finally, an optional color inversion which is done in the render loop. The loop is only executed if the invert is done, since otherwise dst already contains the final image. There's a bit a flicker when the controls are moved, but the result is correct. Here is the code: Hidden Content: // Name: Gaussian Blur with Brightness and Contrast // Submenu: Blurs // Author: MJW // Title: Gaussian Blur with Brighness and Contrast // Desc: Gaussian Blur with Brightness and Contrast (test multiple built-in effects) // Keywords: Gaussian blur contrast brightness test multiple built-in effects // URL: // Help: #region UICode IntSliderControl Amount1 = 1; // [0,100] Blur Radius IntSliderControl Amount2 = 0; // [-100,100] Brightness IntSliderControl Amount3 = 0; // [-100,100] Contrast CheckboxControl Amount4 = false; // [0,1] Invert Colors #endregion // Here is the main render loop function void Render(Surface dst, Surface src, Rectangle rect) { // Setup for calling the Gaussian Blur effect GaussianBlurEffect blurEffect = new GaussianBlurEffect(); PropertyCollection blurProps = blurEffect.CreatePropertyCollection(); PropertyBasedEffectConfigToken BlurParameters = new PropertyBasedEffectConfigToken(blurProps); BlurParameters.SetPropertyValue(GaussianBlurEffect.PropertyNames.Radius, Amount1); blurEffect.SetRenderInfo(BlurParameters, new RenderArgs(dst), new RenderArgs(src)); // Call the Gaussian Blur function blurEffect.Render(new Rectangle[1] {rect}, 0, 1); // Adjust brightness and contrast. BrightnessAndContrastAdjustment bacAdjustment = new BrightnessAndContrastAdjustment(); PropertyCollection bacProps = bacAdjustment.CreatePropertyCollection(); PropertyBasedEffectConfigToken bacParameters = new PropertyBasedEffectConfigToken(bacProps); bacParameters.SetPropertyValue(BrightnessAndContrastAdjustment.PropertyNames.Brightness, Amount2); bacParameters.SetPropertyValue(BrightnessAndContrastAdjustment.PropertyNames.Contrast, Amount3); bacAdjustment.SetRenderInfo(bacParameters, new RenderArgs(dst), new RenderArgs(dst)); // Call the Brightness and Contrast Adjustment function bacAdjustment.Render(new Rectangle[1] {rect}, 0, 1); // Now in the main render loop, the dst canvas has a blurred version of the src canvas // The dst canvas has the contrast adjusted. // No need to do any more unless Invert is selected. if (Amount4) { for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra CurrentPixel = dst[x, y]; CurrentPixel = ColorBgra.FromUInt32(0x00ffffff ^ CurrentPixel.Bgra); dst[x, y] = CurrentPixel; } } } } Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted November 16, 2015 Share Posted November 16, 2015 Hmm, I tried using the same surface on my Blur Fill plugin, and I get a nasty banding effect. This is the same problem I was having a few months ago, as I recall now. Quote (June 9th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
MJW Posted November 16, 2015 Share Posted November 16, 2015 (edited) For which effect are you trying to reuse the same surface as both the source and the destination? You should be able to do so with the brightness adjustment, but not with the enlargement or blur. The only way I know of for a CodeLab plugin to do the Blur Fill (at least without additional surfaces) is if the blur and enlargement could somehow be done in a single step, because in both operations a pixel's value depends on other pixels, which may or may not have already been modified. (I can't immediately see how it could be done in CodeLab even with additional surfaces, but I'd need to think about it more carefully before saying it couldn't.) Edited November 16, 2015 by MJW Quote Link to comment Share on other sites More sharing options...
toe_head2001 Posted November 16, 2015 Share Posted November 16, 2015 ...because in both operations a pixel's valued depends on other pixels, and those pixels may or may not have already been modified Yeah, I knew the pre-enlarged surface and the enlarged surface needed to be different, so I left those as is. The issue was caused by using the same surface in the Blur effect. Thanks for that explanation, I didn't realize that about Gaussian Blur. Quote (June 9th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
ReMake Posted November 16, 2015 Author Share Posted November 16, 2015 Hello, Kalama. I tried to use both effects in the Render loop - it really work. Thanks for your hint. I will modify tutorial later. Maybe tomorrow. For this I will need some time. Quote Link to comment Share on other sites More sharing options...
ReMake Posted November 17, 2015 Author Share Posted November 17, 2015 The tutorial is updated after discussion (see first post). 1 Quote Link to comment Share on other sites More sharing options...
lynxster4 Posted September 3, 2018 Share Posted September 3, 2018 Hi @ReMake I've been doing your tutorials to familiarize myself with CodeLab and Visual Studio. I've already done @BoltBait's tutorials, and up to this point, everything has come out perfect. After following @BoltBait instructions here, I am unable to build the DLL because I still have (2) error messages concerning the 'MultiplyBlendOp' lines. Here is a screenshot: I have looked at 'suggested fixes' and nothing works to get rid of the red squiggly lines. I also have a small grey line in code above the red ones. When I did BoltBait's ColorBalance example, it worked fine and I was able to build the DLL. Please keep in mind that I do not know C# at this time. I was simply trying to to get more familiar using these. Any help would be appreciated. Thanks! Here's a dropbox link to my VS folder if you need it. https://www.dropbox.com/sh/7j3skswsqscr9b3/AADmTb4MxKw1GnKSBFDhUrTla?dl=0 Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to comment Share on other sites More sharing options...
BoltBait Posted September 3, 2018 Share Posted September 3, 2018 I think you're missing a reference. Add another reference to your project, click the "Browse" tab. Browse over to the "C:\Program Files\Paint.NET\" folder. Select the file "PaintDotNet.Data.DLL". Click OK. You added references for Base, Core, and Effects. You just forgot Data. 1 1 Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
toe_head2001 Posted September 3, 2018 Share Posted September 3, 2018 You can also use the CodeLab v4 beta; it can automatically create the Visual Studio solution for you. But maybe you want to learn the "nuts and bolts" of things, and therefore want to do it manually. 1 Quote (June 9th, 2023) Sorry about any broken images in my posts. I am aware of the issue. My Gallery | My Plugin Pack Layman's Guide to CodeLab Link to comment Share on other sites More sharing options...
BoltBait Posted September 3, 2018 Share Posted September 3, 2018 2 minutes ago, toe_head2001 said: You can also use the CodeLab v4 beta; it can automatically create the Visual Studio solution for you. This will GREATLY simplify Tutorial 5 once CodeLab 4.0 ships. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
lynxster4 Posted September 3, 2018 Share Posted September 3, 2018 Thank you @BoltBait and @toe_head2001 Yes, I'm taking the 'long route' on purpose. I've learned quite a few things already. I will try your solution BB, and post whether it worked. Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to comment Share on other sites More sharing options...
lynxster4 Posted September 3, 2018 Share Posted September 3, 2018 (edited) YEAH! It worked! @BoltBait ? I had a sneaky suspicion that I needed to add a file under 'References'. But I did not need that file for your ColorBalance lesson. How would I have known to add that particular file for Sponge effect? Or do I need the 'Data" file all the time now? And it did not give me the icon I embedded. I got the icon when I did ColorBalance lesson. Edited September 3, 2018 by lynxster4 added extra info Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" Link to comment Share on other sites More sharing options...
ReMake Posted September 3, 2018 Author Share Posted September 3, 2018 Yes, BoltBait is right, you did not have enough references. The idea proposed toe_head2001 I really like - is a lot easier. Here is a list of necessary and sufficient references for this effect: PaintDotNet.Base PaintDotNet.Core PaintDotNet.Data PaintDotNet.Effects System System.Drawing System.Windows.Forms Good luck. 1 Quote Link to comment Share on other sites More sharing options...
BoltBait Posted September 3, 2018 Share Posted September 3, 2018 16 minutes ago, lynxster4 said: YEAH! It worked! @BoltBait ? I had a sneaky suspicion that I needed to add a file under 'References'. But I did not need that file for your ColorBalance lesson. How would I have known to add that particular file for Sponge effect? Or do I need the 'Data" file all the time now? And it did not give me the icon I embedded. I got the icon when I did ColorBalance lesson. It depends. Here's the thing... different parts of Paint.NET are defined in different DLL's. The ColorBalance lesson didn't need a blending operation, so it didn't need PaintDotNet.Data (which is where Paint.NET has implemented all of the blending operations). It doesn't hurt to have it added to the references. In fact, the new Create VS Project function of CodeLab 4.0 always adds ALL of the DLL's, just in case you need them later. Quote Download: BoltBait's Plugin Pack | CodeLab | and a Computer Dominos Game Link to comment Share on other sites More sharing options...
lynxster4 Posted September 3, 2018 Share Posted September 3, 2018 1 hour ago, BoltBait said: Here's the thing... different parts of Paint.NET are defined in different DLL's. The ColorBalance lesson didn't need a blending operation, so it didn't need PaintDotNet.Data (which is where Paint.NET has implemented all of the blending operations). It doesn't hurt to have it added to the references. In fact, the new Create VS Project function of CodeLab 4.0 always adds ALL of the DLL's, just in case you need them later. I appreciate the explanation. I still have a couple more CodeLab tuts to do, then who knows? But as @toe_head2001 said, I'm doing it this way to learn the 'nuts and bolts'. I know so much more than I did two weeks ago. And thanks @ReMake. The VS Solution button will surely come in handy when I'm ready to dabble on my own. 1 Quote My Art Gallery | My Shape Packs | ShapeMaker Mini Tut | Air Bubble Stained Glass Chrome Text with Reflections | Porcelain Text w/ Variegated Coloring | Realistic Knit PatternOpalescent Stained Glass | Frosted Snowman Cookie | Leather Texture | Plastic Text | Silk Embroidery Visit my Personal Website "Never, ever lose your sense of humor - you'll live longer" 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.