Jump to content
How to Install Plugins ×

Kaleidoscope Effect Plugin


Recommended Posts

From a newbie, this is a port of some HLSL FX code that I wrote for a Kaleidoscope Effect for Windows Movie Maker 6.0; I just wanted to see how the Paint.Net coding tool Code Lab works and to get some experience with Paint.net and the C# language.

It is a similar, but a bit different than the Kaleidoscope Effect that Madjik submitted around 2008. This one adds a center point selector and a source angle rotater. The pie shaped selection is just the image swept out by rotating clockwise 360/n degrees. It is missing Madjik's copy all over all option, show single piece etc.

Also the edge of the image can be clamped or repeated.

Anyway, just for fun. Here is the DLL DPL KAL.zip (Edit: Upload by EER 16 April 2017)

Unzip and place the DLL in the .../Paint.Net/Effects folder.

Then DPL Kaleidoscope will show up in the Effect->Distort menu

Here is a sample with a elliptical selection followed by a rectangular selection.



Also of course the whole canvas can be selected (by selecting nothing).




The UI is:


The controls are:

  • The Selection Rectangle = Drawing Destination
    (Lasso, Ellipse and Inverted Selections gives some interesting results)
  • (Source Center) Selector - x y position of the center to be processed
  • (Source Angle) Chooser - Rotate the start of the pie to be copied
  • (Destination Angle) Chooser - Rotate the resulting kaleidoscope image
  • (Zoom) Slider - Zoom in/out on the kaleidoscope image
  • (Repetitions) Slider - Number of copies
  • (Imaging Type) Radio Buttons
    Reflect, Left, Right
  • (Clamp Edge / Repeat) At Edge Check Box -
  • (Ellipse / Rectangle) Check Box - clip at a rectangle or ellipse representing the selection area
  • (Border Width) Slider (0 for none) -
  • (Colored Background) Checkbox - Surround the selection with a single color
  • (Background Color) Color Wheel - Choose border color and surrounding color when colored background is on.
  • (Distort) CheckBox - Gives a bit of a spherical look. Originally a bug, now featured boltbait.roll.png.

Edit: Per Rick suggestion, changed the Image Type radio buttons to a dropdown list. UI is now 780 pixels tall.

Also, a later post has a 750 pixel version with the Distort checkbox removed.

Comments welcome, pleabo

  • Upvote 1

Link to comment
Share on other sites

CSM725 and Goonfella. Till I figure out how to rearrange the UI, here is one with the Color Chooser removed.

It has a UI about 700 pixels tall. The background/border color is hard coded to dark blue. DPLKALsmall.zip

Following is one 690 pixel candidate for what I would like to do: (Click for full size)


But so far I don't know how to arrange radio buttons or check boxes horizontally.??

Edited by pleabo

Link to comment
Share on other sites

You can't stack controls horizontally like that in CodeLab. CodeLab uses a UI system called IndirectUI that Rick wrote to simplify UI design. Although IndirectUI makes UI design easier, it also imposes some limits on control placement. If you want to move the controls around at will, you would have to switch over to an IDE, such as Visual Studio or SharpDevelop, and learn to use WinForms.

Link to comment
Share on other sites

You can, however, tell the StaticListChoiceProperty to use a dropdown list (combobox) instead of a vertical list of radio buttons. That will save some space.

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

  • 2 weeks later...
  • 1 month later...

This plugin is done. If a moderator chooses, this thread can be moved to Plugins - Publishing Only.

Done. Feel free to rename the thread, perhaps to remove "Newbie". It's up to you though.

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

  • 2 weeks later...

This gives some interesting results, but it is difficult to predict how it will look like. The repeted piece isn't clearly identified.

Anyhow I would be interested to have a look at the source...

Thanks for your interest. OK, here's the code:

#region UICode
Pair<double, double> Amount1 = Pair.Create( 0.0 , 0.0 ); // Source Center
double Amount2 = 0; // [-180,180] Source Angle
double Amount3 = 0; // [-180,180] Destination Angle
double Amount4 = 1; // [0.1,10] Zoom
int Amount5 = 4; // [1,50] Repetitions
byte Amount6 = 0; // Imaging Type|Reflect| Left| Right
bool Amount7 = false; // [0,1] Clamp Edge
bool Amount8 = true; // [0,1] Ellipse
int Amount9 = 0; // [0,512] Border Width (0 for none)
bool Amount10 = false; // [0,1] Colored Ellipse Background
ColorBgra Amount11 = ColorBgra.FromBgr(0,0,0); // Border/BackGround Color
bool Amount12 = false; // [0,1] Distort

// Submenu: Distort
// Name: DPL Kaleidoscope
// Title: DPL Kaleidoscope
// Author: pleabo

void Render(Surface dst, Surface src, Rectangle rect) {
 Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt();
 int xx, yy;
 double PI = Math.PI;
 ColorBgra CurrentPixel;
 double ctrX    = Amount1.First;  // Source Center x
 double ctrY    = Amount1.Second; // Source Center y
 double angleS   = Amount2/180*PI; // [-180,180] Source Angle
 double angleD   = Amount3/180*PI; // [-180,180] Destination Angle
 double zoom 	= Amount4;  // [1,10] Zoom X
 int    nn   	= Amount5;  // [1,50] Number of Reflections
 byte   itype    = Amount6;  // Reflect| Left| Right
 bool   clmp 	= Amount7;  // [0,1] Clamp Edge
 bool   iselip   = Amount8;  // Do Elipse
 int    bdr      = Amount9;  // Border Thickness
 bool   bgclr    = Amount10; // [0,1] Do Background Color
 ColorBgra clrbg = Amount11; // The Background Color
 bool   distort  = Amount12; // Distort the Destination  

 int    width  = src.Width; 	// Source - Whole Image
 int    height = src.Height;

 int right  = rect.Right;   	// Selection (Partial Destination)
 int left   = rect.Left;
 int top    = rect.Top;
 int bottom = rect.Bottom;

 int dright  = selection.Right; // Selection (Whole Destination)
 int dleft   = selection.Left;
 int dtop    = selection.Top;  
 int dbottom = selection.Bottom;
 int dwidth  = dright - dleft;
 int dheight = dbottom - dtop;  

 double magx   = (double)width /dwidth;
 double magy   = (double)height/dheight;
 double magxy  = Math.Min(magx, magy);  // Pick smallest side

 int    scx    = (int)(ctrX*width /2+ width/2 ); // Source Center XY
 int    scy    = (int)(ctrY*height/2+ height/2); 
 int    dcx    = (int)((dwidth)/2+dleft);  // Destination Center XY
 int    dcy    = (int)((dheight)/2+dtop);

 if (itype==0) nn *= 2;   // Make visual number of nodes match nn in reflect mode
 if (distort)  nn *= 2;   // Keep number of nodes when distorting  
 if (bgclr) bdr=0;        // No border if colored background
 for (int y = top; y < bottom; y++) {
   for (int x = left; x < right; x++) {
     CurrentPixel = src[x,y];        
     if (IsIn(x,y,dleft, dtop, dright-dleft, dbottom-dtop, iselip)) {
       CurrentPixel = clrbg;        // Border color
       int rmin = Math.Min(dright-dleft, dbottom-dtop)/2;        
       if (bdr<rmin) {   // Keep center at clrbg for big border 
         if (IsIn(x,y,dleft+bdr, dtop+bdr, dright-dleft-2*bdr, dbottom-dtop-2*bdr, iselip)) {
           int dx = x-dcx;
           int dy = y-dcy;
           double dist = distort ? 0.5 : 1.0;      
           double angle = dist*nn*(Math.Atan2(dy,-dx)+PI-angleD);
           int n = (int)(((angle+(2*nn-1)*PI)/(PI/nn*2)+nn/2)/(nn))%(nn); // Section number - 0->(2*Reflections-1)

           double angleL = (angle-n*2*PI)/(1*nn); 			// As Is
           double angleR = 2*PI/(1*nn)-(angle-n*2*PI)/(1*nn); // Mirror

           switch (itype) {
             case 0: angle = ((n%2)>0)?angleL:angleR;break; // Alternate        
             case 1: angle = angleL; break; 				// Left
             case 2: angle = angleR; break; 				// Right

           double sinxy = Math.Sin(angle-angleS);
           double cosxy = Math.Cos(angle-angleS);

           int sx = (int)(dx*magxy); 
           int sy = (int)(dy*magxy);      

           double sxy2 = sx*sx + sy*sy;  // Sum of squares
           double rS = Math.Sqrt(sxy2)/zoom*magxy; // Radius (distance to center)*Konstant

           xx = (int)(scx + rS*cosxy);  
           yy = (int)(scy + rS*sinxy);  
           if (clmp) {
             xx = Clamp(xx,width -1);                    
             yy = Clamp(yy,height-1);  
             xx = Repeat(xx,width );                    
             yy = Repeat(yy,height);  
           CurrentPixel = src[Math.Abs(xx), Math.Abs(yy)];
     } else CurrentPixel = bgclr ? clrbg : src[x,y]; // BackGround/Original Pixel 		
     dst[x,y] = CurrentPixel;

// ----------------  Checking for x,y in rectangle or ellipse ------- x2/a2 + y2/b2 = 1 --
public bool IsIn(int x,int y,int rx, int ry, int rl, int rh, bool elips) {
bool rc = false;    
 if (elips) {
   int cx = rx+rl/2,   	cy = ry+rh/2;
   int dx = (x-cx)*(x-cx), dy = (y-cy)*(y-cy);
   float z2 = rl*rl,   	w2 = rh*rh;
   rc = (4*(dx/z2+dy/w2)<1);
 } else 
   rc = (x<rx)?false:(x>(rx+rl))?false:(y<ry)?false:(y>(ry+rh))?false:true;
 return rc;

// -------------- Clamp iValue to zero and upper ---------------
public int  Clamp(int iValue, int upper) {
return (int)Math.Max(Math.Min(iValue, upper), 0);

// --------------- Repeat iValue below zero and above upper (modulo upper)
public int Repeat(int iValue, int upper) {
 return iValue%upper;  



Link to comment
Share on other sites

Thanks !

You're code is clean and readable.

You could optimize it a bit if you move some unique calculation out of the loops (ex: int rmin=... doesn't depend on x nor y).

Your zoom out (ex: zoom = 0.4) is great and gives amazing results with repeat the effect (ctrl+F)

Link to comment
Share on other sites

  • 1 year later...
  • 4 years later...

Now that was a nice learning experience. So easy when you have the source code. Now if I could just understand what all the code meant - I might become a publisher. Thanks Boltbait for suggesting I try it. My first plug- in written by me (well sort of).

Edited by AndrewDavid
removed image - too large signature


Link to comment
Share on other sites

^ Glad you pulled it off AndrewDavid ;)


For anyone not interested in compiling the source, I've added a zipped DLL to the first post and also added an image of the UI.

  • Upvote 1
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.

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...