1 ///////////////////////////////////////////////////////////////////////////////// 2 // Paint.NET // 3 // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. // 4 // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. // 5 // See license-pdn.txt for full licensing and attribution details. // 6 // // 7 // Ported to Pinta by: Marco Rolappe <m_rolappe@gmx.net> // 8 ///////////////////////////////////////////////////////////////////////////////// 9 10 using System; 11 using Cairo; 12 using Pinta.Gui.Widgets; 13 using Pinta.Core; 14 using Mono.Unix; 15 16 namespace Pinta.Effects 17 { 18 public class FrostedGlassEffect : BaseEffect 19 { 20 public override string Icon { 21 get { return "Menu.Effects.Distort.FrostedGlass.png"; } 22 } 23 24 public override string Name { 25 get { return Catalog.GetString ("Frosted Glass"); } 26 } 27 28 public override bool IsConfigurable { 29 get { return true; } 30 } 31 32 public override string EffectMenuCategory { 33 get { return Catalog.GetString ("Distort"); } 34 } 35 36 public FrostedGlassData Data { 37 get { return EffectData as FrostedGlassData; } 38 } 39 40 private Random random = new Random (); 41 FrostedGlassEffect()42 public FrostedGlassEffect () { 43 EffectData = new FrostedGlassData (); 44 } 45 LaunchConfiguration()46 public override bool LaunchConfiguration () { 47 return EffectHelper.LaunchSimpleEffectDialog (this); 48 } 49 50 #region Algorithm Code Ported From PDN Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)51 unsafe public override void Render (ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois) { 52 int width = src.Width; 53 int height = src.Height; 54 int r = Data.Amount; 55 Random localRandom = this.random; 56 57 int* intensityCount = stackalloc int[256]; 58 uint* avgRed = stackalloc uint[256]; 59 uint* avgGreen = stackalloc uint[256]; 60 uint* avgBlue = stackalloc uint[256]; 61 uint* avgAlpha = stackalloc uint[256]; 62 byte* intensityChoices = stackalloc byte[(1 + (r * 2)) * (1 + (r * 2))]; 63 64 int src_width = src.Width; 65 ColorBgra* src_data_ptr = (ColorBgra*)src.DataPtr; 66 67 foreach (var rect in rois) { 68 int rectTop = rect.Top; 69 int rectBottom = rect.GetBottom (); 70 int rectLeft = rect.Left; 71 int rectRight = rect.GetRight (); 72 73 for (int y = rectTop; y <= rectBottom; ++y) { 74 ColorBgra* dstPtr = dst.GetPointAddress (rect.Left, y); 75 76 int top = y - r; 77 int bottom = y + r + 1; 78 79 if (top < 0) { 80 top = 0; 81 } 82 83 if (bottom > height) { 84 bottom = height; 85 } 86 87 for (int x = rectLeft; x <= rectRight; ++x) { 88 int intensityChoicesIndex = 0; 89 90 for (int i = 0; i < 256; ++i) { 91 intensityCount[i] = 0; 92 avgRed[i] = 0; 93 avgGreen[i] = 0; 94 avgBlue[i] = 0; 95 avgAlpha[i] = 0; 96 } 97 98 int left = x - r; 99 int right = x + r + 1; 100 101 if (left < 0) { 102 left = 0; 103 } 104 105 if (right > width) { 106 right = width; 107 } 108 109 for (int j = top; j < bottom; ++j) { 110 if (j < 0 || j >= height) { 111 continue; 112 } 113 114 ColorBgra* srcPtr = src.GetPointAddressUnchecked (src_data_ptr, src_width, left, j); 115 116 for (int i = left; i < right; ++i) { 117 byte intensity = srcPtr->GetIntensityByte (); 118 119 intensityChoices[intensityChoicesIndex] = intensity; 120 ++intensityChoicesIndex; 121 122 ++intensityCount[intensity]; 123 124 avgRed[intensity] += srcPtr->R; 125 avgGreen[intensity] += srcPtr->G; 126 avgBlue[intensity] += srcPtr->B; 127 avgAlpha[intensity] += srcPtr->A; 128 129 ++srcPtr; 130 } 131 } 132 133 int randNum; 134 135 lock (localRandom) { 136 randNum = localRandom.Next (intensityChoicesIndex); 137 } 138 139 byte chosenIntensity = intensityChoices[randNum]; 140 141 byte R = (byte)(avgRed[chosenIntensity] / intensityCount[chosenIntensity]); 142 byte G = (byte)(avgGreen[chosenIntensity] / intensityCount[chosenIntensity]); 143 byte B = (byte)(avgBlue[chosenIntensity] / intensityCount[chosenIntensity]); 144 byte A = (byte)(avgAlpha[chosenIntensity] / intensityCount[chosenIntensity]); 145 146 *dstPtr = ColorBgra.FromBgra (B, G, R, A); 147 ++dstPtr; 148 149 // prepare the array for the next loop iteration 150 for (int i = 0; i < intensityChoicesIndex; ++i) { 151 intensityChoices[i] = 0; 152 } 153 } 154 } 155 } 156 } 157 #endregion 158 159 public class FrostedGlassData : EffectData 160 { 161 [Caption ("Amount"), MinimumValue(1), MaximumValue(10)] 162 public int Amount = 1; 163 } 164 } 165 } 166