Skip to content

Commit ccda98f

Browse files
committed
Add background mode (Blur)
1 parent 1091747 commit ccda98f

File tree

5 files changed

+194
-55
lines changed

5 files changed

+194
-55
lines changed

AwesomeWallpaper/AwesomeWallpaper.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
<Generator>MSBuild:Compile</Generator>
129129
<SubType>Designer</SubType>
130130
</ApplicationDefinition>
131+
<Compile Include="Drawing\GaussianBlur.cs" />
131132
<Compile Include="Extensions\BitmapExtensions.cs" />
132133
<Compile Include="Extensions\EnumExtensions.cs" />
133134
<Compile Include="Native\NativeConstants.cs" />
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Drawing;
4+
using System.Drawing.Imaging;
5+
using System.Runtime.InteropServices;
6+
using System.Threading.Tasks;
7+
8+
namespace AwesomeWallpaper.Drawing
9+
{
10+
public class GaussianBlur
11+
{
12+
private readonly int[] _alpha;
13+
private readonly int[] _red;
14+
private readonly int[] _green;
15+
private readonly int[] _blue;
16+
17+
private readonly int _width;
18+
private readonly int _height;
19+
20+
private readonly ParallelOptions _pOptions = new ParallelOptions { MaxDegreeOfParallelism = 16 };
21+
22+
public GaussianBlur(Bitmap image)
23+
{
24+
var rct = new Rectangle(0, 0, image.Width, image.Height);
25+
var source = new int[rct.Width * rct.Height];
26+
var bits = image.LockBits(rct, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
27+
Marshal.Copy(bits.Scan0, source, 0, source.Length);
28+
image.UnlockBits(bits);
29+
30+
_width = image.Width;
31+
_height = image.Height;
32+
33+
_alpha = new int[_width * _height];
34+
_red = new int[_width * _height];
35+
_green = new int[_width * _height];
36+
_blue = new int[_width * _height];
37+
38+
Parallel.For(0, source.Length, _pOptions, i =>
39+
{
40+
_alpha[i] = (int)((source[i] & 0xff000000) >> 24);
41+
_red[i] = (source[i] & 0xff0000) >> 16;
42+
_green[i] = (source[i] & 0x00ff00) >> 8;
43+
_blue[i] = (source[i] & 0x0000ff);
44+
});
45+
}
46+
47+
public Bitmap Process(int radial)
48+
{
49+
var newAlpha = new int[_width * _height];
50+
var newRed = new int[_width * _height];
51+
var newGreen = new int[_width * _height];
52+
var newBlue = new int[_width * _height];
53+
var dest = new int[_width * _height];
54+
55+
Parallel.Invoke(
56+
() => gaussBlur_4(_alpha, newAlpha, radial),
57+
() => gaussBlur_4(_red, newRed, radial),
58+
() => gaussBlur_4(_green, newGreen, radial),
59+
() => gaussBlur_4(_blue, newBlue, radial));
60+
61+
Parallel.For(0, dest.Length, _pOptions, i =>
62+
{
63+
if (newAlpha[i] > 255) newAlpha[i] = 255;
64+
if (newRed[i] > 255) newRed[i] = 255;
65+
if (newGreen[i] > 255) newGreen[i] = 255;
66+
if (newBlue[i] > 255) newBlue[i] = 255;
67+
68+
if (newAlpha[i] < 0) newAlpha[i] = 0;
69+
if (newRed[i] < 0) newRed[i] = 0;
70+
if (newGreen[i] < 0) newGreen[i] = 0;
71+
if (newBlue[i] < 0) newBlue[i] = 0;
72+
73+
dest[i] = (int)((uint)(newAlpha[i] << 24) | (uint)(newRed[i] << 16) | (uint)(newGreen[i] << 8) | (uint)newBlue[i]);
74+
});
75+
76+
var image = new Bitmap(_width, _height);
77+
var rct = new Rectangle(0, 0, image.Width, image.Height);
78+
var bits2 = image.LockBits(rct, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
79+
Marshal.Copy(dest, 0, bits2.Scan0, dest.Length);
80+
image.UnlockBits(bits2);
81+
return image;
82+
}
83+
84+
private void gaussBlur_4(int[] source, int[] dest, int r)
85+
{
86+
var bxs = boxesForGauss(r, 3);
87+
boxBlur_4(source, dest, _width, _height, (bxs[0] - 1) / 2);
88+
boxBlur_4(dest, source, _width, _height, (bxs[1] - 1) / 2);
89+
boxBlur_4(source, dest, _width, _height, (bxs[2] - 1) / 2);
90+
}
91+
92+
private int[] boxesForGauss(int sigma, int n)
93+
{
94+
var wIdeal = Math.Sqrt((12 * sigma * sigma / n) + 1);
95+
var wl = (int)Math.Floor(wIdeal);
96+
if (wl % 2 == 0) wl--;
97+
var wu = wl + 2;
98+
99+
var mIdeal = (double)(12 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (-4 * wl - 4);
100+
var m = Math.Round(mIdeal);
101+
102+
var sizes = new List<int>();
103+
for (var i = 0; i < n; i++) sizes.Add(i < m ? wl : wu);
104+
return sizes.ToArray();
105+
}
106+
107+
private void boxBlur_4(int[] source, int[] dest, int w, int h, int r)
108+
{
109+
for (var i = 0; i < source.Length; i++) dest[i] = source[i];
110+
boxBlurH_4(dest, source, w, h, r);
111+
boxBlurT_4(source, dest, w, h, r);
112+
}
113+
114+
private void boxBlurH_4(int[] source, int[] dest, int w, int h, int r)
115+
{
116+
var iar = (double)1 / (r + r + 1);
117+
Parallel.For(0, h, _pOptions, i =>
118+
{
119+
var ti = i * w;
120+
var li = ti;
121+
var ri = ti + r;
122+
var fv = source[ti];
123+
var lv = source[ti + w - 1];
124+
var val = (r + 1) * fv;
125+
for (var j = 0; j < r; j++) val += source[ti + j];
126+
for (var j = 0; j <= r; j++)
127+
{
128+
val += source[ri++] - fv;
129+
dest[ti++] = (int)Math.Round(val * iar);
130+
}
131+
for (var j = r + 1; j < w - r; j++)
132+
{
133+
val += source[ri++] - dest[li++];
134+
dest[ti++] = (int)Math.Round(val * iar);
135+
}
136+
for (var j = w - r; j < w; j++)
137+
{
138+
val += lv - source[li++];
139+
dest[ti++] = (int)Math.Round(val * iar);
140+
}
141+
});
142+
}
143+
144+
private void boxBlurT_4(int[] source, int[] dest, int w, int h, int r)
145+
{
146+
var iar = (double)1 / (r + r + 1);
147+
Parallel.For(0, w, _pOptions, i =>
148+
{
149+
var ti = i;
150+
var li = ti;
151+
var ri = ti + r * w;
152+
var fv = source[ti];
153+
var lv = source[ti + w * (h - 1)];
154+
var val = (r + 1) * fv;
155+
for (var j = 0; j < r; j++) val += source[ti + j * w];
156+
for (var j = 0; j <= r; j++)
157+
{
158+
val += source[ri] - fv;
159+
dest[ti] = (int)Math.Round(val * iar);
160+
ri += w;
161+
ti += w;
162+
}
163+
for (var j = r + 1; j < h - r; j++)
164+
{
165+
val += source[ri] - source[li];
166+
dest[ti] = (int)Math.Round(val * iar);
167+
li += w;
168+
ri += w;
169+
ti += w;
170+
}
171+
for (var j = h - r; j < h; j++)
172+
{
173+
val += lv - source[li];
174+
dest[ti] = (int)Math.Round(val * iar);
175+
li += w;
176+
ti += w;
177+
}
178+
});
179+
}
180+
}
181+
}

AwesomeWallpaper/Extensions/BitmapExtensions.cs

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Drawing;
55
using System.Drawing.Imaging;
66
using System.Windows.Media.Imaging;
7+
using AwesomeWallpaper.Drawing;
78
using static AwesomeWallpaper.Native.NativeMethods;
89

910
namespace AwesomeWallpaper.Extensions
@@ -118,58 +119,10 @@ public static Bitmap Pixelate(this Bitmap bitmap, int pixelateSize)
118119
return newBitmap;
119120
}
120121

121-
public static Bitmap Blur(this Bitmap bitmap, int blurSize)
122+
public static Bitmap Blur(this Bitmap bitmap, int radial)
122123
{
123-
var newBitmap = new Bitmap(bitmap.Width, bitmap.Height);
124-
125-
// make an exact copy of the bitmap provided
126-
using (var graphics = Graphics.FromImage(newBitmap))
127-
{
128-
graphics.DrawImage(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height), new Rectangle(0, 0, bitmap.Width, bitmap.Height), GraphicsUnit.Pixel);
129-
}
130-
131-
// look at every pixel in the blur rectangle
132-
for (var xx = 0; xx < newBitmap.Width; xx++)
133-
{
134-
for (var yy = 0; yy < newBitmap.Height; yy++)
135-
{
136-
var avgR = 0;
137-
var avgG = 0;
138-
var avgB = 0;
139-
var blurPixelCount = 0;
140-
141-
// average the color of the red, green and blue for each pixel in the
142-
// blur size while making sure you don't go outside the bitmap bounds
143-
for (var x = xx; (x < xx + blurSize && x < newBitmap.Width); x++)
144-
{
145-
for (var y = yy; (y < yy + blurSize && y < newBitmap.Height); y++)
146-
{
147-
var pixel = newBitmap.GetPixel(x, y);
148-
149-
avgR += pixel.R;
150-
avgG += pixel.G;
151-
avgB += pixel.B;
152-
153-
blurPixelCount++;
154-
}
155-
}
156-
157-
avgR = avgR / blurPixelCount;
158-
avgG = avgG / blurPixelCount;
159-
avgB = avgB / blurPixelCount;
160-
161-
// now that we know the average for the blur size, set each pixel to that color
162-
for (var x = xx; x < xx + blurSize && x < newBitmap.Width && x < newBitmap.Width; x++)
163-
{
164-
for (var y = yy; y < yy + blurSize && y < newBitmap.Height && y < newBitmap.Height; y++)
165-
{
166-
newBitmap.SetPixel(x, y, Color.FromArgb(avgR, avgG, avgB));
167-
}
168-
}
169-
}
170-
}
171-
172-
return newBitmap;
124+
var blur = new GaussianBlur(bitmap);
125+
return blur.Process(radial);
173126
}
174127

175128
public static Bitmap Copy(this Bitmap bitmap)

AwesomeWallpaper/MainWindow.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ private Bitmap ConvertBitmap(Bitmap original, BackgroundMode mode)
235235
switch (mode)
236236
{
237237
case BackgroundMode.None: return original.Copy();
238+
case BackgroundMode.Blur: return original.Blur(3);
238239
case BackgroundMode.Pixelate: return original.Pixelate(3);
239240
case BackgroundMode.Dark: return original.Dark();
240241
case BackgroundMode.BlackAndWhite: return original.BlackAndWhite();

AwesomeWallpaper/Settings/BackgroundMode.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ public enum BackgroundMode
77
[Display(Name = "None")]
88
None = 0,
99

10+
[Display(Name = "Blur")]
11+
Blur = 1,
12+
1013
[Display(Name = "Pixelate")]
11-
Pixelate = 1,
14+
Pixelate = 2,
1215

1316
[Display(Name = "Dark")]
14-
Dark = 2,
17+
Dark = 3,
1518

1619
[Display(Name = "Black And White")]
17-
BlackAndWhite = 3,
20+
BlackAndWhite = 4,
1821

1922
[Display(Name = "Grayscale")]
20-
Grayscale = 4
23+
Grayscale = 5
2124
}
2225
}

0 commit comments

Comments
 (0)