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