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: Olivier Dufour <olivier.duff@gmail.com>                 //
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 ZoomBlurEffect : BaseEffect
19 	{
20 		public override string Icon {
21 			get { return "Menu.Effects.Blurs.ZoomBlur.png"; }
22 		}
23 
24 		public override string Name {
25 			get { return Catalog.GetString ("Zoom Blur"); }
26 		}
27 
28 		public override bool IsConfigurable {
29 			get { return true; }
30 		}
31 
32 		public override string EffectMenuCategory {
33 			get { return Catalog.GetString ("Blurs"); }
34 		}
35 
36 		public ZoomBlurData Data { get { return EffectData as ZoomBlurData; } }
37 
ZoomBlurEffect()38 		public ZoomBlurEffect ()
39 		{
40 			EffectData = new ZoomBlurData ();
41 		}
42 
LaunchConfiguration()43 		public override bool LaunchConfiguration ()
44 		{
45 			return EffectHelper.LaunchSimpleEffectDialog (this);
46 		}
47 
48 		#region Algorithm Code Ported From PDN
Render(ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)49 		public unsafe override void Render (ImageSurface src, ImageSurface dst, Gdk.Rectangle[] rois)
50 		{
51 			if (Data.Amount == 0) {
52 				// Copy src to dest
53 				return;
54 			}
55 
56 			int src_width = src.Width;
57 			ColorBgra* src_data_ptr = (ColorBgra*)src.DataPtr;
58 			int dst_width = dst.Width;
59 			ColorBgra* dst_data_ptr = (ColorBgra*)dst.DataPtr;
60 			Gdk.Rectangle src_bounds = src.GetBounds ();
61 
62 			long w = dst.Width;
63 			long h = dst.Height;
64 			long fox = (long)(dst.Width * Data.Offset.X * 32768.0);
65 			long foy = (long)(dst.Height * Data.Offset.Y * 32768.0);
66 			long fcx = fox + (w << 15);
67 			long fcy = foy + (h << 15);
68 			long fz = Data.Amount;
69 
70 			const int n = 64;
71 
72 			foreach (Gdk.Rectangle rect in rois) {
73 				for (int y = rect.Top; y <= rect.GetBottom (); ++y) {
74 					ColorBgra* dstPtr = dst.GetPointAddressUnchecked (dst_data_ptr, dst_width, rect.Left, y);
75 					ColorBgra* srcPtr = src.GetPointAddressUnchecked (src_data_ptr, src_width, rect.Left, y);
76 
77 					for (int x = rect.Left; x <= rect.GetRight (); ++x) {
78 						long fx = (x << 16) - fcx;
79 						long fy = (y << 16) - fcy;
80 
81 						int sr = 0;
82 						int sg = 0;
83 						int sb = 0;
84 						int sa = 0;
85 						int sc = 0;
86 
87 						sr += srcPtr->R * srcPtr->A;
88 						sg += srcPtr->G * srcPtr->A;
89 						sb += srcPtr->B * srcPtr->A;
90 						sa += srcPtr->A;
91 						++sc;
92 
93 						for (int i = 0; i < n; ++i) {
94 							fx -= ((fx >> 4) * fz) >> 10;
95 							fy -= ((fy >> 4) * fz) >> 10;
96 
97 							int u = (int)(fx + fcx + 32768 >> 16);
98 							int v = (int)(fy + fcy + 32768 >> 16);
99 
100 							if (src_bounds.Contains (u, v)) {
101 								ColorBgra* srcPtr2 = src.GetPointAddressUnchecked (src_data_ptr, src_width, u, v);
102 
103 								sr += srcPtr2->R * srcPtr2->A;
104 								sg += srcPtr2->G * srcPtr2->A;
105 								sb += srcPtr2->B * srcPtr2->A;
106 								sa += srcPtr2->A;
107 								++sc;
108 							}
109 						}
110 
111 						if (sa != 0) {
112 							*dstPtr = ColorBgra.FromBgra (
113 							    Utility.ClampToByte (sb / sa),
114 							    Utility.ClampToByte (sg / sa),
115 							    Utility.ClampToByte (sr / sa),
116 							    Utility.ClampToByte (sa / sc));
117 						} else {
118 							dstPtr->Bgra = 0;
119 						}
120 
121 						++srcPtr;
122 						++dstPtr;
123 					}
124 				}
125 			}
126 		}
127 		#endregion
128 
129 		public class ZoomBlurData : EffectData
130 		{
131 			[Caption ("Amount"), MinimumValue (0), MaximumValue (100)]
132 			public int Amount = 10;
133 
134 			[Caption ("Offset")]
135 			public Gdk.Point Offset = new Gdk.Point (0, 0);
136 
137 			[Skip]
138 			public override bool IsDefault { get { return Amount == 0; } }
139 		}
140 	}
141 }
142