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 PixelateEffect : BaseEffect
19 	{
20 		public override string Icon {
21 			get { return "Menu.Effects.Distort.Pixelate.png"; }
22 		}
23 
24 		public override string Name {
25 			get { return Catalog.GetString ("Pixelate"); }
26 		}
27 
28 		public override bool IsConfigurable {
29 			get { return true; }
30 		}
31 
32 		public PixelateData Data {
33 			get { return EffectData as PixelateData; }
34 		}
35 
36 		public override string EffectMenuCategory {
37 			get { return Catalog.GetString ("Distort"); }
38 		}
39 
PixelateEffect()40 		public PixelateEffect () {
41 			EffectData = new PixelateData ();
42 		}
43 
LaunchConfiguration()44 		public override bool LaunchConfiguration () {
45 			return EffectHelper.LaunchSimpleEffectDialog (this);
46 		}
47 
48 		#region Algorithm Code Ported From PDN
ComputeCellColor(int x, int y, ImageSurface src, int cellSize, Gdk.Rectangle srcBounds)49 		private ColorBgra ComputeCellColor (int x, int y, ImageSurface src, int cellSize, Gdk.Rectangle srcBounds) {
50 			Gdk.Rectangle cell = GetCellBox (x, y, cellSize);
51 			cell.Intersect (srcBounds);
52 
53 			int left = cell.Left;
54 			int right = cell.GetRight ();
55 			int bottom = cell.GetBottom ();
56 			int top = cell.Top;
57 
58 			ColorBgra colorTopLeft = src.GetColorBgraUnchecked (left, top).ToStraightAlpha();
59 			ColorBgra colorTopRight = src.GetColorBgraUnchecked (right, top).ToStraightAlpha();
60 			ColorBgra colorBottomLeft = src.GetColorBgraUnchecked (left, bottom).ToStraightAlpha();
61 			ColorBgra colorBottomRight = src.GetColorBgraUnchecked (right, bottom).ToStraightAlpha();
62 
63 			ColorBgra c = ColorBgra.BlendColors4W16IP (colorTopLeft, 16384, colorTopRight, 16384, colorBottomLeft, 16384, colorBottomRight, 16384);
64 
65 			return c.ToPremultipliedAlpha();
66 		}
67 
GetCellBox(int x, int y, int cellSize)68 		private Gdk.Rectangle GetCellBox (int x, int y, int cellSize) {
69 			int widthBoxNum = x % cellSize;
70 			int heightBoxNum = y % cellSize;
71 			var leftUpper = new Gdk.Point (x - widthBoxNum, y - heightBoxNum);
72 
73 			var returnMe = new Gdk.Rectangle (leftUpper, new Gdk.Size (cellSize, cellSize));
74 
75 			return returnMe;
76 		}
77 
78 
Render(ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois)79 		unsafe public override void Render (ImageSurface src, ImageSurface dest, Gdk.Rectangle[] rois) {
80 			var cellSize = Data.CellSize;
81 
82 			Gdk.Rectangle src_bounds = src.GetBounds ();
83 			Gdk.Rectangle dest_bounds = dest.GetBounds ();
84 
85 			foreach (var rect in rois) {
86 				for (int y = rect.Top; y <= rect.GetBottom (); ++y) {
87 					int yEnd = y + 1;
88 
89 					for (int x = rect.Left; x <= rect.GetRight (); ++x) {
90 						var cellRect = GetCellBox (x, y, cellSize);
91 						cellRect.Intersect (dest_bounds);
92 						var color = ComputeCellColor (x, y, src, cellSize, src_bounds);
93 
94 						int xEnd = Math.Min (rect.GetRight (), cellRect.GetRight ());
95 						yEnd = Math.Min (rect.GetBottom (), cellRect.GetBottom ());
96 
97 						for (int y2 = y; y2 <= yEnd; ++y2) {
98 							ColorBgra* ptr = dest.GetPointAddressUnchecked (x, y2);
99 
100 							for (int x2 = x; x2 <= xEnd; ++x2) {
101 								ptr->Bgra = color.Bgra;
102 								++ptr;
103 							}
104 						}
105 
106 						x = xEnd;
107 					}
108 
109 					y = yEnd;
110 				}
111 			}
112 		}
113 		#endregion
114 	}
115 
116 
117 	public class PixelateData : EffectData
118 	{
119 		[Caption ("Cell Size"), MinimumValue(1), MaximumValue(100)]
120 		public int CellSize = 2;
121 	}
122 }
123