Mercurial > hg > isophonics-drupal-site
comparison core/lib/Drupal/Component/Utility/Rectangle.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\Component\Utility; | |
4 | |
5 /** | |
6 * Rectangle rotation algebra class. | |
7 * | |
8 * This class is used by the image system to abstract, from toolkit | |
9 * implementations, the calculation of the expected dimensions resulting from | |
10 * an image rotate operation. | |
11 * | |
12 * Different versions of PHP for the GD toolkit, and alternative toolkits, use | |
13 * different algorithms to perform the rotation of an image and result in | |
14 * different dimensions of the output image. This prevents predictability of | |
15 * the final image size for instance by the image rotate effect, or by image | |
16 * toolkit rotate operations. | |
17 * | |
18 * This class implements a calculation algorithm that returns, given input | |
19 * width, height and rotation angle, dimensions of the expected image after | |
20 * rotation that are consistent with those produced by the GD rotate image | |
21 * toolkit operation using PHP 5.5 and above. | |
22 * | |
23 * @see \Drupal\system\Plugin\ImageToolkit\Operation\gd\Rotate | |
24 */ | |
25 class Rectangle { | |
26 | |
27 /** | |
28 * The width of the rectangle. | |
29 * | |
30 * @var int | |
31 */ | |
32 protected $width; | |
33 | |
34 /** | |
35 * The height of the rectangle. | |
36 * | |
37 * @var int | |
38 */ | |
39 protected $height; | |
40 | |
41 /** | |
42 * The width of the rotated rectangle. | |
43 * | |
44 * @var int | |
45 */ | |
46 protected $boundingWidth; | |
47 | |
48 /** | |
49 * The height of the rotated rectangle. | |
50 * | |
51 * @var int | |
52 */ | |
53 protected $boundingHeight; | |
54 | |
55 /** | |
56 * Constructs a new Rectangle object. | |
57 * | |
58 * @param int $width | |
59 * The width of the rectangle. | |
60 * @param int $height | |
61 * The height of the rectangle. | |
62 */ | |
63 public function __construct($width, $height) { | |
64 if ($width > 0 && $height > 0) { | |
65 $this->width = $width; | |
66 $this->height = $height; | |
67 $this->boundingWidth = $width; | |
68 $this->boundingHeight = $height; | |
69 } | |
70 else { | |
71 throw new \InvalidArgumentException("Invalid dimensions ({$width}x{$height}) specified for a Rectangle object"); | |
72 } | |
73 } | |
74 | |
75 /** | |
76 * Rotates the rectangle. | |
77 * | |
78 * @param float $angle | |
79 * Rotation angle. | |
80 * | |
81 * @return $this | |
82 */ | |
83 public function rotate($angle) { | |
84 // PHP 5.5 GD bug: https://bugs.php.net/bug.php?id=65148: To prevent buggy | |
85 // behavior on negative multiples of 30 degrees we convert any negative | |
86 // angle to a positive one between 0 and 360 degrees. | |
87 $angle -= floor($angle / 360) * 360; | |
88 | |
89 // For some rotations that are multiple of 30 degrees, we need to correct | |
90 // an imprecision between GD that uses C floats internally, and PHP that | |
91 // uses C doubles. Also, for rotations that are not multiple of 90 degrees, | |
92 // we need to introduce a correction factor of 0.5 to match the GD | |
93 // algorithm used in PHP 5.5 (and above) to calculate the width and height | |
94 // of the rotated image. | |
95 if ((int) $angle == $angle && $angle % 90 == 0) { | |
96 $imprecision = 0; | |
97 $correction = 0; | |
98 } | |
99 else { | |
100 $imprecision = -0.00001; | |
101 $correction = 0.5; | |
102 } | |
103 | |
104 // Do the trigonometry, applying imprecision fixes where needed. | |
105 $rad = deg2rad($angle); | |
106 $cos = cos($rad); | |
107 $sin = sin($rad); | |
108 $a = $this->width * $cos; | |
109 $b = $this->height * $sin + $correction; | |
110 $c = $this->width * $sin; | |
111 $d = $this->height * $cos + $correction; | |
112 if ((int) $angle == $angle && in_array($angle, [60, 150, 300])) { | |
113 $a = $this->fixImprecision($a, $imprecision); | |
114 $b = $this->fixImprecision($b, $imprecision); | |
115 $c = $this->fixImprecision($c, $imprecision); | |
116 $d = $this->fixImprecision($d, $imprecision); | |
117 } | |
118 | |
119 // This is how GD on PHP5.5 calculates the new dimensions. | |
120 $this->boundingWidth = abs((int) $a) + abs((int) $b); | |
121 $this->boundingHeight = abs((int) $c) + abs((int) $d); | |
122 | |
123 return $this; | |
124 } | |
125 | |
126 /** | |
127 * Performs an imprecision check on the input value and fixes it if needed. | |
128 * | |
129 * GD that uses C floats internally, whereas we at PHP level use C doubles. | |
130 * In some cases, we need to compensate imprecision. | |
131 * | |
132 * @param float $input | |
133 * The input value. | |
134 * @param float $imprecision | |
135 * The imprecision factor. | |
136 * | |
137 * @return float | |
138 * A value, where imprecision is added to input if the delta part of the | |
139 * input is lower than the absolute imprecision. | |
140 */ | |
141 protected function fixImprecision($input, $imprecision) { | |
142 if ($this->delta($input) < abs($imprecision)) { | |
143 return $input + $imprecision; | |
144 } | |
145 return $input; | |
146 } | |
147 | |
148 /** | |
149 * Returns the fractional part of a float number, unsigned. | |
150 * | |
151 * @param float $input | |
152 * The input value. | |
153 * | |
154 * @return float | |
155 * The fractional part of the input number, unsigned. | |
156 */ | |
157 protected function fraction($input) { | |
158 return abs((int) $input - $input); | |
159 } | |
160 | |
161 /** | |
162 * Returns the difference of a fraction from the closest between 0 and 1. | |
163 * | |
164 * @param float $input | |
165 * The input value. | |
166 * | |
167 * @return float | |
168 * the difference of a fraction from the closest between 0 and 1. | |
169 */ | |
170 protected function delta($input) { | |
171 $fraction = $this->fraction($input); | |
172 return $fraction > 0.5 ? (1 - $fraction) : $fraction; | |
173 } | |
174 | |
175 /** | |
176 * Gets the bounding width of the rectangle. | |
177 * | |
178 * @return int | |
179 * The bounding width of the rotated rectangle. | |
180 */ | |
181 public function getBoundingWidth() { | |
182 return $this->boundingWidth; | |
183 } | |
184 | |
185 /** | |
186 * Gets the bounding height of the rectangle. | |
187 * | |
188 * @return int | |
189 * The bounding height of the rotated rectangle. | |
190 */ | |
191 public function getBoundingHeight() { | |
192 return $this->boundingHeight; | |
193 } | |
194 | |
195 } |