Search the Community

Showing results for tags 'stylize'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Information
    • Forum Rules
    • Paint.NET Search
    • Official Paint.NET website
    • Help Files (the official paint.net documentation)
  • Paint.NET
    • Paint.NET Discussion and Questions
    • The Pictorium
    • Tutorials - Publishing ONLY!
    • Competitions
    • Plugins - Publishing ONLY!
    • Troubleshooting & Bug Reports
  • Off-Topic
    • Grand Theory of Everything
  • Paint.NET Programming / Development
    • Plugin Developer's Central
    • Preview Center
    • Translation and Localization

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Website URL


AIM


MSN


ICQ


Yahoo


Jabber


Skype


Location


Interests

Found 9 results

  1. ArgusMagnus

    Edge Detection

    Effect->Stylize->Edge Detection (Argus) Download: https://onedrive.live.com/redir?resid=429F16CCEF18E484!339757&authkey=!AJ0aYSIXTh_4Jhs&ithint=folder%2ctxt (Copy the files ArgusPaintNet.EdgeDetection.dll and ArgusPaintNet.Shared.dll to the paint.net/Effects folder) This effect uses an edge detection algorithm. It draws edges with given colors and sets the other pixels to transparent. I haven't had any good idea for the name, so I called it Edge Detection for now, the (Argus) is simply to make it better distinguishable from the built in Edge Detect effect. If anyone has an idea for a better name, feel free to share it :-) UI Explanation (See example below): Lower Threshold: All pixels with values (Structur Tensor Eigenvalues) below this threshold are fully transparent: Higher Threshold --> Less Edges detected Upper Threshold: All pixels with values above this threshold are fully opaque. The range of "good" values really depends on the image. For hard edges (extreme case: black line on white), "good" values may go up to 1, for softer edges (as typically found in photographes), "good" values will usually be below 0.2 Color/Color2/Angle/Hue Direction: ​Edges with a normal angle the same as the chosen Angle are drawn in the color set in Color, edges with a normal angle perpendicular to Angle are drawn in the color set in Color2, ​in between the color is interpolated between Color and Color2. Hue Direction determines how the Hue value is interpolated. Difference Filter: The Kernel used to get the image derivates in x and y direction. I have yet to encounter a situation where I needed to change this value. If you change this value, a lot of calculations have to be redone. Some time may pass before you see something happening. Smoothing Radius: As expected, smoothes the output. Performance: Calculating initial values (Structur Tensors) may take some time, therefore, depending on the selection size, it may take some time after the effect dialog pops up before you can see something happening. If you change the value "Difference Filter" these calculations have to be redone. Smoothing is also somewhat expensive, which you can see if you change the smoothing radius. Intermediate values (Structur Tensors, eigenvalues of smoothed Tensors) are held in memory so re-rendering the output for different Threshold/Color/Angle values is fast. The cost for that is memory usage: Roughly 24 bytes per Pixel are used (excluding the memory used for the source and destination surface). ​ ​
  2. Radius Corners This is an continuation of @dan9298's abandoned 'Radius Fill Corners' plugin. Effects -> Stylize -> Radius Corners Features Creates rounded corners on your image at an adjustable radius. Automatically sets the maximum radius size allowed (based on half the size of the shortest side of the canvas); defaults to a quarter size Fill the background with transparency or a custom color Changelog v1.6 (July 8, 2018) Improved: Better performance when increasing the Margin value Changed: Moved the Anti-aliasing button directly under the Radius slider v1.5 (Sept 10, 2016) Added: There is now an option for a margin. v1.4 (Dec 1, 2015) Fixed: The dynamic values on the Radius slider (Max & Default) now recognize selections v1.3 (Feb 28, 2015) Added: Anti-aliasing! Changed: Plugin is now called Radius Corners (the Fill function is not important enough to be in the name ) Changed: Moved to the Stylize Submenu (same reason as above) Fixed: Right and bottom edges were off by 1px v1.2 (Feb 26, 2015) Changed: Replaced the old WinForms UI with a fancy IndirectUI one Changed: Replaced the Primary Color & Secondary Color options with a Color Wheel (which defaults to the primary color) Changed: Instead of having the default Radius Size at 50, it is now set to a quarter of the size of the shortest side of the canvas New: Metadata was added for the 'Plugin Browser' v1.1 by dan9298 (Nov 21, 2008) Prevent the radius from exceeding half the size of the shortest side of the canvas v1.0 by dan9298 (Nov 9, 2008) Initial release Download RadiusFillCorners.zip Source Code Source files and Git history
  3. Radobot

    Heightmap v1.3

    I made my version of 3D Heightmap plugin. New version 1.3 has now light angle option and updated names of settings. How plugin works: Imagine that you are looking at uneven surface - heightmap (image in PDN). Lightness of each pixel represents it's height. You can choose from where is light coming and you can adjust the angle of light. Plugin generates how will heightmap look with your settings. It generates lightness of each pixel by calculating at which angle it is from next pixel and generating lightness of pixel form angle. How to use it: Light direction - Direction from which is light coming. Brightness - Angle from which is light coming. Contrast - Strength of light. Shadows - Turns on/off shadows. Replace Alpha - If you have image with transparent parts, this changes them all to one value. Replace Alpha with - Value, to which change all Alpha in image. Plugin is in Stylize submenu. Images before: Images after: Just ask if you want something (previous versions, code, ...) . Heightmap v1.3.zip
  4. This plugin allows you to reduce number of colors in an image with the help of eleven error diffusion dithering algorithms. You are able to choose one of the four software palettes. You can also enable "Serpentine scanning" to alternate scanning direction between lines. Unfortunately, these algorithms do not work quickly due to single-threadedness. The advantage of this plugin is correct work with any selection. Plugin: Effects > Stylize > Error diffusion dithering Examples: Download: ErrorDiffusionDithering.dll
  5. Star Glow Plugin What's this? This is a plugin under Effect/Stylize menu. You should use it to add some shiny glow to your image. Faster than the sparkles effect, it changes the value of the pixels instead of drawing lines or circles. It just offers the possilibity to select the 8 radius to be on/off... Download the DLL Plugin StarGlow.dll Here is the DLL The MadJik's All plugins package is available ! http://forums.getpaint.net/index.php?showtopic=7186 How to install Close Paint.net Classic version of Paint.net Unzip and (re)place the DLL in your Effect folder usually: C:/Program Files/Paint.NET/Effects Microsoft Store version of Paint.net Unzip and (re)place the DLL in your Effect folder usually: /My Documents/paint.net App Files/Effects/ You have to adapt for your language My Documents The User interface This plugin is added to the menu Effects, submenu Stylize. Mini / Maxi : set the range of values for the luminosity to test. Each color found on the image between mini and maxi will be a source of a glow. Red / Green / Blue : set the color chanel to test or not. Ray/Diag Up/Down/Left/Right: check the box to draw the described ray. Black: check the box to draw the ray in black, instead white. Examples: Model / Result : Model / Result :
  6. This is a CodeLab port of @harold's NormalMapPlus plugin. It's functionally identical, except for some fixes, the slider controls having an extra decimal place (due to the way CodeLab works), and the addition of a brief Help menu. Though the code is functionally the same, it was somewhat rewritten. It's in the Stylize submenu. The fixes are: 1) The ROI boundary pixels are handled correctly. 2) The normals are computed at the correct positions, rather than being shifted one pixel left. 3) The JIT compiler optimization crash doesn't occur. (The crash is almost certainly not due to a bug in the original plugin code, and will probably be fixed in the JIT compiler soon.) Here is the DLL (Version 1.4): NormalMapPlus.zip Here is the code: EDIT 01 AUG 1017: Moved to Stylize window. Changed version to 1.4.
  7. NomBot

    DotMatrix

    This is similar to other plugins out there (since there are about 8 million of them on this site) Curtis' Dots, for one... but that one doesn't use path gradients. Anyway it's my first plugin using GDI+ (thanks to Red ochre for pointing me in that direction) and done entirely in CodeLab, my favorite 'plugin'. ...and not much to do with dot-matrix printers, if anyone remembers them... DotMatrix.zip (Found under Stylize) User Interface: Dot Diameter: size of the dots (very low diameters can produce tapestry-like effects) Background Color: fills the background, default black. Grad Percent: gradation amount Light Direction: drag the cross to direction light will come from. Use Path Gradient: use a path brush rather than a linear brush. The following controls apply only to the path brush: Highlight Width: width of the highlight area Highlight Height: height of the highlight area Point: Sharpness of the highlight Spread: this affects the blend curve Light Distance: how far the light is from the canvas (no effect if light direction is in center)
  8. This is a rather silly little plugin, but it might be fun to play with. I call it the HSV Scrambler. It treats the Hue, Saturation, and Value of each pixel as a value from 0 to 1, then allows any of the components to be derived from a scaled and offset version of any of the other components. It's under Effects>Stylize>HSV Scrambler. Here is the interface: Each component has a Source, which can be Hue, Saturation, Value, or One. The Source component is Offset then scaled by the Scale factor. Each component also has a choice of Bounds Handling, which can be Wrap, Reflected Wrap, or Clamp. Wrap wraps all values to 0 to 1, Clamp clamps out-of-range values to 0 or 1, and Reflected Wrap maps values up to 1 then backwards down to 0. Reflected Wrap prevents the discontinuities at boundaries for Saturation and Value. It isn't necessary in order to make the Hue continuous. The Hue has a Secondary Color Expansion control. I thought the secondary color (yellow, cyan, and magenta) bands were sometimes too thin relative to the primary (red, green, and blue) color bands, so I added a control to optionally widen the bands. It can also be used to narrow the secondary bands, if desired. I think 0.5 often works quite well. Probably the most common choice will be Value for the Hue source, and One for the Saturation and Value sources. This pseudo colors a black and white image. Here is a quick example: After HSV Scrambler: Here is the CodeLab code: Hidden Content: // Author: MJW // Name: HSV Scrambler // Title: HSV Scrambler // Submenu: Stylize // Desc: Scramble the HSV components // Keywords: scramble HSV color #region UICode byte Amount1 = 0; // Hue Source|Hue|Saturation|Value|One byte Amount2 = 0; // Hue Bounds Handling|Wrap|Reflected Wrap|Clamp double Amount3 = 0; // [-1,1] Hue Offset double Amount4 = 1; // [-8,8] Hue Scale double Amount5 = 0; // [-1,1] Secondary Color Expansion byte Amount6 = 0; // Saturation Source|Saturation|Value|Hue|One byte Amount7 = 0; // Saturation Bounds Handling|Reflected Wrap|Clamp|Wrap double Amount8 = 0; // [-1,1] Saturation Offset double Amount9 = 1; // [-8,8] Saturation Scale byte Amount10 = 0; // Value Source|Value|Hue|Saturation|One byte Amount11 = 0; // Value Bounds Handling|Reflected Wrap|Clamp|Wrap double Amount12 = 0; // [-1,1] Value Offset double Amount13 = 1; // [-8,8] Value Scale #endregion delegate double getDouble(); delegate double transformDouble(double d); private transformDouble [] selectBoundsH, selectBoundsSV; // Here is the main render loop function void Render(Surface dst, Surface src, Rectangle rect) { double offsetH, offsetS, offsetV; double scaleH, scaleS, scaleV; double secondaryExpansion; getDouble getH, getS, getV; transformDouble boundH, boundS, boundV; double srcH = 0.0, srcS = 0.0, srcV = 0.0; // Bounds handling routines. if (selectBoundsH == null) { selectBoundsH = new transformDouble [] {Wrap, ReflectedWrap, Clamp}; selectBoundsSV = new transformDouble [] {ReflectedWrap, Clamp, Wrap}; } boundH = selectBoundsH[Amount2]; boundS = selectBoundsSV[Amount7]; boundV = selectBoundsSV[Amount11]; // Offsets and scaling factors. offsetH = Amount3; scaleH = Amount4; offsetS = Amount8; scaleS = Amount9; offsetV = Amount12; scaleV = Amount13; // Amount to expand the secondary colors (yellow, cyan, and magenta). secondaryExpansion = (Amount5 < 0) ? 0.5 * Amount5 : Amount5; unsafe { // Source of the component. double one = 1.0; double *pH = (Amount1 < 2) ? ((Amount1 == 0) ? &srcH : &srcS) : ((Amount1 == 2) ? &srcV : &one); double *pS = (Amount6 < 2) ? ((Amount6 == 0) ? &srcS : &srcV) : ((Amount6 == 2) ? &srcH : &one); double *pV = (Amount10 < 2) ? ((Amount10 == 0) ? &srcV : &srcH) : ((Amount10 == 2) ? &srcS : &one); // Rendering loop. for (int y = rect.Top; y < rect.Bottom; y++) { if (IsCancelRequested) return; for (int x = rect.Left; x < rect.Right; x++) { ColorBgra CurrentPixel = src[x, y]; byte a = CurrentPixel.A; RGBtoHSV(CurrentPixel, out srcH, out srcS, out srcV); double h = boundH(offsetH + scaleH * *pH); if (secondaryExpansion != 0.0) h = AdjustHue(h, secondaryExpansion); double s = boundS(offsetS + scaleS * *pS); double v = boundV(offsetV + scaleV * *pV); dst[x, y] = HSVtoRGBA(h, s, v, a); } } } } double Clamp(double d) { return (d < 0.0) ? 0.0 : ((d > 1.0) ? 1.0 : d); } double Wrap(double d) { return d - Math.Floor(d); } double ReflectedWrap(double d) { d = Math.Abs(d) % 2.0; return (d > 1.0) ? 2.0 - d : d; } const double oneThird = 1.0 / 3.0; double AdjustHue(double h, double secondaryExpansion) { double tripledH = 3.0 * HueConstrain(h); double frac = tripledH - Math.Floor(tripledH); double twiceFrac = 2.0 * frac; tripledH += secondaryExpansion * twiceFrac * (frac - 1.0) * (twiceFrac - 1.0); return oneThird * tripledH; } public ColorBgra HSVtoRGBA(double H, double S, double V, double A) { return HSVtoRGBA(H, S, V, (byte)(255 * A + 0.5)); } public ColorBgra HSVtoRGBA(double H, double S, double V, byte A) { byte r, g, b; HSVtoRGB(H, S, V, out r, out g, out ; return ColorBgra.FromBgra(b, g, r, (byte)A); } public void HSVtoRGB(double H, double S, double V, out byte bR, out byte bG, out byte bB) { // Parameters must satisfy the following ranges: // 0.0 <= H < 1.0 // 0.0 <= S <= 1.0 // 0.0 <= V <= 1.0 // Handle special case of gray (so no Hue) first if ((S == 0.0) || (V == 0.0)) { byte x = (byte)(int)(V * 255.0); bR = x; bG = x; bB = x; return; } H = HueConstrain(H); double R = V, G = V, B = V; double Hi = Math.Floor(6.0 * H); double f = 6.0 * H - Hi; double p = V * (1.0 - S); double q = V * (1.0 - f * S); double t = V * (1.0 - (1.0 - f) * S); if (Hi == 0.0) { R = V; G = t; B = p; } else if (Hi == 1.0) { R = q; G = V; B = p; } else if (Hi == 2.0) { R = p; G = V; B = t; } else if (Hi == 3.0) { R = p; G = q; B = V; } else if (Hi == 4.0) { R = t; G = p; B = V; } else // if (Hi == 5.0) { R = V; G = p; B = q; } int iR = (int)(R * 255.0 + 0.5); int iG = (int)(G * 255.0 + 0.5); int iB = (int)(B * 255.0 + 0.5); bR = (byte)iR; bG = (byte)iG; bB = (byte)iB; } public void RGBtoHSV(ColorBgra color, out double H, out double S, out double V) { RGBtoHSV(color.R, color.G, color.B, out H, out S, out V); } public void RGBtoHSV(int R, int G, int B, out double outH, out double outS, out double outV) { const double H_UNDEFINED = 0.0; // Arbitrarily set undefined hue to 0 const double recip6 = 1.0 / 6.0; // R, G, and B must range from 0 to 255 // Ouput value ranges: // outH - 0.0 to 1.0 // outS - 0.0 to 1.0 // outV - 0.0 to 1.0 double dR = (double)R / 255.0; double dG = (double)G / 255.0; double dB = (double)B / 255.0; double dmaxRGB = Max3(dR, dG, dB); double dminRGB = Min3(dR, dG, dB); double delta = dmaxRGB - dminRGB; // Set value outV = dmaxRGB; // Handle special case of V = 0 (black) if (dmaxRGB == 0) { outH = H_UNDEFINED; outS = 0.0; return; } // Handle specai case of S = 0 (gray) outS = delta / dmaxRGB; if (dmaxRGB == dminRGB) { outH = H_UNDEFINED; return; } // Finally, compute hue if (dR == dmaxRGB) { outH = (dG - dB) / delta; } else if (dG == dmaxRGB) { outH = 2.0 + (dB - dR) / delta; } else //if (dB == dmaxRGB) { outH = 4.0 + (dR - dG) / delta; } outH *= recip6; outH = HueConstrain(outH); } public double Max3(double x, double y, double z) { return (x > y) ? ((x > z) ? x : z) : ((y > z) ? y : z); } public double Min3(double x, double y, double z) { return (x < y) ? ((x < z) ? x : z) : ((y < z) ? y : z); } public double HueConstrain(double MyHue) { // Makes sure that 0.0 <= MyAngle < 1.0 // Wraps around the value if its outside this range while (MyHue >= 1.0) { MyHue -= 1.0; } while (MyHue < 0.0) { MyHue += 1.0; } return MyHue; } Here is the icon: Here is the plugin: HsvScrambler.zip EDIT: Version 1.1. Add control to optionally widen the secondary Hue color bands. Change scale ranges from 10 to 8. Modify method of fetching source components (using "unsafe" pointers suggested by midora). Use different selection method for sources, and slightly revise method for selecting bounding delegates. Move bounding selection control next to component selection. It makes less sense logically, but I believe it makes the interface clearer.
  9. This is a plugin I wrote to test a method for computing the color gradient, but which might be useful for non-testing reasons. I call it (the rather unwieldy) "Display Color Change Direction" because "color gradient" has another common meaning for plugins, and I didn't want to be confusing. The maximum direction of the color change is shown by the hue. It's in the Effects>Stylize menu. The interface is: The Color Scale controls control the color brightness. To allow for a wide range, I have coarse and fine controls. Color Range expands or compresses the range of colors. Because the colors no longer form a continuous circle, some anomalies may a occur when adjacent colors with almost the same color-change direction are colored with colors at the opposite ends of the color range. This problem can be reduced by using Reflected Color Range. Color Shift shifts the hue around the color circle. Color Phase changes which color is associated with which color-change direction. When the full range of colors is used, it duplicates the function of the Color Shift control. When used with a restricted range, the Color Shift selects which colors are used, and the Color Phase selects how the current range of colors are associated with the color change directions. Reverse Color Order reverses the order around the color circle. Full Circle assigns a direction to the color change. Normally, since the color changes as rapidly in the opposite direction, the direction of maximum color change is between 0° and 180°. When this option is set, a direction is assigned to the color, based on the change in intensity of the back-and-white image. I made True the default, both because I think the images generally look better, and because it makes the encoded color change direction correspond to the PDN color wheel. Reflected Color Range reflects the current color range so instead of the going from the beginning color to the ending color, it goes from the beginning color to the ending color at mid-range, then in the opposite order, back to the beginning color. (E.g., Red->Yellow->Green->Yellow->Red.) This makes the color range continuous around the circle of color-directions, avoiding color anomalies when using restricted color ranges. Transparent Background colors makes the background transparent instead of black. As I've mentioned, the purpose was to test the algorithm, but it can be used to produce some interesting effects. For example, the background for this sig was produced using only Clouds and this plugin: The plugin can also be used for edge detection. For example, by running the plugin, then converting to black-and-white and inverting the colors. Here is the CodeLab code: Hidden Content: // Author: MJW // Name: Display Color Change Direction // Title: Display Color Change Direction // Submenu: Stylize // Desc: Show the direction of the maximum color change as a color. // Keywords: color change direction #region UICode double Amount1 = 10; //[0, 25]Color Scale (Coarse) double Amount2 = 0; //[-1, 1]Color Scale (Fine) double Amount3 = 1.0; //[0, 2]Color Range double Amount4 = 0.0; //[0, 1]Color Shift double Amount5 = 0.0; //[0, 1]Color Phase bool Amount6 = false; //Reverse Color Order bool Amount7 = true; //Full Circle bool Amount8 = false; //Reflected Color Range bool Amount9 = false; //Transparent Background #endregion Surface Src, Dst; int maxX, maxY; double colorScale; bool maxScale; double colorShift; double colorPhase; double colorRange; double colorOrder, colorOrderAdj; bool fullCircle; bool reflectColors; bool transparentBackground; const int middleWeight = 2; const double angleScale = 1.0 / Math.PI; void Render(Surface dst, Surface src, Rectangle rect) { colorScale = 0.002 * (Amount1 + Amount2); if (colorScale < 0) colorScale = 0; maxScale = (colorScale >= 25.0); // If scale is max., display all colors at full range. colorScale *= 4.0 / (2.0 + (double)middleWeight); colorShift = Amount4; colorPhase = Amount5; colorRange = Amount3; if (Amount6) // Sign of scaling chosen to match color menu wheel. { colorOrder = -angleScale; colorOrderAdj = 1.0; } else { colorOrder = angleScale; colorOrderAdj = 0.0; } fullCircle = Amount7; reflectColors = Amount8; transparentBackground = Amount9; Src = src; Dst = dst; Rectangle selection = this.EnvironmentParameters.GetSelection(src.Bounds).GetBoundsInt(); int left = rect.Left; int right = rect.Right; int top = rect.Top; int bottom = rect.Bottom; maxX = src.Width - 1; maxY = src.Height - 1; for (int y = top; y < bottom; y++) for (int x = left; x < right; x++) dst[x, y] = FindGradientColor(x, y); } protected ColorBgra FindGradientColor(int x, int y) { ColorBgra MM, UM, UR, MR, LR, LM, LL, ML, UL; ColorBgra gradColor = ColorBgra.Black; int lX, rX, uY, lY; lX = (x == 0) ? x : x - 1; rX = (x == maxX) ? x : x + 1; uY = (y == 0) ? y : y - 1; lY = (y == maxY) ? y : y + 1; MM = Src.GetPointUnchecked(x, y); UM = Src.GetPointUnchecked(x, uY); UR = Src.GetPointUnchecked(rX, uY); MR = Src.GetPointUnchecked(rX, y); LR = Src.GetPointUnchecked(rX, lY); LM = Src.GetPointUnchecked(x, lY); LL = Src.GetPointUnchecked(lX, lY); ML = Src.GetPointUnchecked(lX, y); UL = Src.GetPointUnchecked(lX, uY); int xR = (UL.R - UR.R) + middleWeight * (ML.R - MR.R) + (LL.R - LR.R); int xG = (UL.G - UR.G) + middleWeight * (ML.G - MR.G) + (LL.G - LR.G); int xB = (UL.B - UR. + middleWeight * (ML.B - MR. + (LL.B - LR.; int yR = (UL.R - LL.R) + middleWeight * (UM.R - LM.R) + (UR.R - LR.R); int yG = (UL.G - LL.G) + middleWeight * (UM.G - LM.G) + (UR.G - LR.G); int yB = (UL.B - LL. + middleWeight * (UM.B - LM. + (UR.B - LR.; int xDelta, yDelta, mag2; // The straight-forward implementation. // The change in each color component can either be consdered positive or negative. // Since changing all the signs won't change the magnitude of the change, red is // fixed and blue and green can have either sign. // Compute all four versions and choose the on that gives the largest magnitude. int xDeltaA, yDeltaA, xDeltaB, yDeltaB, xDeltaC, yDeltaC; int mag2A, mag2B, mag2C; xDelta = xR + xG + xB; yDelta = yR + yG + yB; xDeltaA = xR + xG - xB; yDeltaA = yR + yG - yB; xDeltaB = xR - xG + xB; yDeltaB = yR - yG + yB; xDeltaC = xR - xG - xB; yDeltaC = yR - yG - yB; mag2 = xDelta * xDelta + yDelta * yDelta; mag2A = xDeltaA * xDeltaA + yDeltaA * yDeltaA; mag2B = xDeltaB * xDeltaB + yDeltaB * yDeltaB; mag2C = xDeltaC * xDeltaC + yDeltaC * yDeltaC; // Use the one with the largest magnitude. if (mag2A > mag2) { xDelta = xDeltaA; yDelta = yDeltaA; mag2 = mag2A; } if (mag2C > mag2B) { xDeltaB = xDeltaC; yDeltaB = yDeltaC; mag2B = mag2C; } if (mag2B > mag2) { xDelta = xDeltaB; yDelta = yDeltaB; mag2 = mag2B; } if (mag2 == 0) { return transparentBackground ? ColorBgra.Transparent : ColorBgra.Black; } else { // Adjust sign of deltas so yDelta >= 0. This will produce an ATan between 0 and PI. if (yDelta < 0) { xDelta = -xDelta; yDelta = -yDelta; } double magnitude = Math.Sqrt((double)mag2); double xComponent = xDelta / magnitude; double yComponent = yDelta / magnitude; double value = maxScale ? 1.0 : Math.Min(1.0, colorScale * magnitude); // 0 <= hue <= 1.0 double hue = colorOrder * Math.Atan2(yComponent, xComponent) + colorOrderAdj; // If full circle, use the intensity to determine the direction. if (fullCircle) { hue *= 0.5; double intensity = xComponent * (xR + xG + xB) + yComponent * (yR + yG + yB); if (intensity > 0.0) hue += 0.5; } // Adjust the phase before restricting the range. hue += colorPhase; if (hue >= 1.0) hue -= 1.0; // Reflected colors match at the endpoints for better restricted range colors. if (reflectColors) { hue *= 2.0; if (hue > 1.0) hue = 2.0 - hue; } hue = colorRange * hue + colorShift; gradColor = transparentBackground ? HSVtoRGBA(hue, 1.0, 1.0, value) : HSVtoRGB(hue, 1.0, value); return gradColor; } } public ColorBgra HSVtoRGBA(double H, double S, double V, double A) { byte r, g, b; HSVtoRGB(H, S, V, out r, out g, out ; return ColorBgra.FromBgra(b, g, r, (byte)(255 * A + 0.5)); } public ColorBgra HSVtoRGB(double H, double S, double V) { byte r, g, b; HSVtoRGB(H, S, V, out r, out g, out ; return ColorBgra.FromBgr(b, g, r); } public void HSVtoRGB(double H, double S, double V, out byte bR, out byte bG, out byte bB) { // Parameters must satisfy the following ranges: // 0.0 <= H < 1.0 // 0.0 <= S <= 1.0 // 0.0 <= V <= 1.0 // Handle special case of gray (so no Hue) first if ((S == 0.0) || (V == 0.0)) { byte x = (byte)(int)(V * 255.0); bR = x; bG = x; bB = x; return; } H = HueConstrain(H); double R = V, G = V, B = V; double Hi = Math.Floor(6.0 * H); double f = 6.0 * H - Hi; double p = V * (1.0 - S); double q = V * (1.0 - f * S); double t = V * (1.0 - (1.0 - f) * S); if (Hi == 0.0) { R = V; G = t; B = p; } else if (Hi == 1.0) { R = q; G = V; B = p; } else if (Hi == 2.0) { R = p; G = V; B = t; } else if (Hi == 3.0) { R = p; G = q; B = V; } else if (Hi == 4.0) { R = t; G = p; B = V; } else // if (Hi == 5.0) { R = V; G = p; B = q; } int iR = (int)(R * 255.0 + 0.5); int iG = (int)(G * 255.0 + 0.5); int iB = (int)(B * 255.0 + 0.5); bR = (byte)iR; bG = (byte)iG; bB = (byte)iB; } public double HueConstrain(double MyHue) { // Makes sure that 0.0 <= MyAngle < 1.0 // Wraps around the value if its outside this range while (MyHue >= 1.0) { MyHue -= 1.0; } while (MyHue < 0.0) { MyHue += 1.0; } return MyHue; } Here's the (not especially attractive!) icon: Here is the plugin: DisplayColorChangeDirection.zip EDIT: Fixed spelling of "Coarse" (H/T, Djisves). Changed version to 1.1. EDIT: Restored icon, which I forgot in the previous version (sorry about that). Changed version to 1.2. EDIT: Added Color Range control. Changed version to 1.3. EDIT: Added Color Phase control. Changed version to 1.4. EDIT: Removed mostly unnecessary Middle Weight and Original Image controls. Replaced (at Eli's suggestion) White Background with Transparent Background. Added Reflected Color Range for improved colors when using restricted ranges. Changed version to 2.0.