1 module ithox.qrcode.renderer.image.decorator.finderpattern;
2 
3 import ithox.qrcode.renderer.image.decorator.decoratorinterface;
4 import ithox.qrcode.renderer.color.colorinterface;
5 import ithox.qrcode.renderer.color.gray;
6 import ithox.qrcode.encoder.qrcode;
7 import ithox.qrcode.renderer.rendererinterface;
8 
9 import std.conv;
10 
11 /**
12 * Finder pattern decorator.
13 */
14 class FinderPattern : DecoratorInterface
15 {
16 
17     /**
18 	* @var Color\ColorInterface
19 	*/
20     protected ColorInterface innerColor;
21     /**
22 	* @varColor\ColorInterface
23 	*/
24     protected ColorInterface outerColor;
25     /**
26 	* Outer position detection pattern.
27 	*
28 	* @var array
29 	*/
30     protected static int[][] outerPositionDetectionPattern = [
31 		[1, 1, 1, 1, 1, 1, 1],
32 		[1, 0, 0, 0, 0, 0, 1],
33 		[1, 0, 0, 0, 0, 0, 1],
34 		[1, 0, 0, 0, 0, 0, 1],
35 		[1, 0, 0, 0, 0, 0, 1],
36 		[1, 0, 0, 0, 0, 0, 1],
37 		[1, 1, 1, 1, 1, 1, 1],
38 	];
39 	/**
40 	* Inner position detection pattern.
41 	*
42 	* @var array
43 	*/
44     protected static int[][] innerPositionDetectionPattern = [
45 		[0, 0, 0, 0, 0, 0, 0],
46 		[0, 0, 0, 0, 0, 0, 0],
47 		[0, 0, 1, 1, 1, 0, 0],
48 		[0, 0, 1, 1, 1, 0, 0],
49 		[0, 0, 1, 1, 1, 0, 0],
50 		[0, 0, 0, 0, 0, 0, 0],
51 		[0, 0, 0, 0, 0, 0, 0],
52 	];
53     /**
54 	* Sets outer color.
55 	*
56 	* @param  Color\ColorInterface color
57 	* @return FinderPattern
58 	*/
59     public FinderPattern setOuterColor(ColorInterface color)
60     {
61         this.outerColor = color;
62         return this;
63     }
64     /**
65 	* Gets outer color.
66 	*
67 	* @return Color\ColorInterface
68 	*/
69     public ColorInterface getOuterColor()
70     {
71         if (this.outerColor is null) {
72             this.outerColor = new Gray(100);
73         }
74         return this.outerColor;
75     }
76     /**
77 	* Sets inner color.
78 	*
79 	* @param  Color\ColorInterface color
80 	* @return FinderPattern
81 	*/
82     public FinderPattern setInnerColor(ColorInterface color)
83     {
84         this.innerColor = color;
85         return this;
86     }
87     /**
88 	* Gets inner color.
89 	*
90 	* @return Color\ColorInterface
91 	*/
92     public ColorInterface getInnerColor()
93     {
94         if (this.innerColor is null) {
95             this.innerColor = new Gray(0);
96         }
97         return this.innerColor;
98     }
99     /**
100 	* preProcess(): defined by DecoratorInterface.
101 	*
102 	* @see    DecoratorInterface::preProcess()
103 	* @param  QrCode            qrCode
104 	* @param  RendererInterface renderer
105 	* @param  integer           outputWidth
106 	* @param  integer           outputHeight
107 	* @param  integer           leftPadding
108 	* @param  integer           topPadding
109 	* @param  integer           multiple
110 	* @return void
111 	*/
112     public void preProcess(  QrCode qrCode,  RendererInterface renderer, int outputWidth, int outputHeight, int leftPadding, int topPadding,  int multiple ) 
113 	{
114 		auto  matrix    = qrCode.matrix();
115 		auto positions = [
116 							[0, 0],
117 							[matrix.width() - 7, 0],
118 							[0, matrix.height() - 7],
119 						];
120 		foreach ( int y,  row;outerPositionDetectionPattern) {
121 			foreach ( int x, isSet;row) {
122 				foreach ( position; positions) {
123 					matrix.set(x + position[0], y + position[1], 0);
124 				}
125 			}
126 		}
127 	}
128     /**
129 	* postProcess(): defined by DecoratorInterface.
130 	*
131 	* @see    DecoratorInterface::postProcess()
132 	*
133 	* @param  QrCode            qrCode
134 	* @param  RendererInterface renderer
135 	* @param  integer           outputWidth
136 	* @param  integer           outputHeight
137 	* @param  integer           leftPadding
138 	* @param  integer           topPadding
139 	* @param  integer           multiple
140 	* @return void
141 	*/
142     public void postProcess(  QrCode qrCode,  RendererInterface renderer, int outputWidth, int outputHeight, int leftPadding, int topPadding,  int multiple ) 
143 	{
144 		auto matrix    = qrCode.matrix();
145 		auto positions = [
146 							[0, 0],
147 							[matrix.width() - 7, 0],
148 							[0, matrix.height() - 7],
149 		];
150 		renderer.addColor("finder-outer", this.getOuterColor());
151 		renderer.addColor("finder-inner", this.getInnerColor());
152 		foreach ( y, row;outerPositionDetectionPattern) {
153 			foreach ( x,isOuterSet;row) {
154 				auto isInnerSet = innerPositionDetectionPattern[y][x];
155 				if (isOuterSet) {
156 					foreach ( position;positions) {
157 						renderer.drawBlock(
158 										   to!int(leftPadding + x * multiple + position[0] * multiple),
159 											to!int(topPadding + y * multiple + position[1] * multiple),
160 											"finder-outer"
161 											);
162 					}
163 				}
164 				if (isInnerSet) {
165 					foreach ( position;positions) {
166 						renderer.drawBlock(
167 											to!int(leftPadding + x * multiple + position[0] * multiple),
168 											to!int(topPadding + y * multiple + position[1] * multiple),
169 											"finder-inner"
170 											);
171 					}
172 				}
173 			}
174 		}
175 	}
176 }