1+ <?php
2+
3+ /*! Marat Tanalin | http://tanalin.com */
4+
5+ namespace MaratTanalin ;
6+
7+ require_once 'IntegerScaling/Ratios.php ' ;
8+
9+ class IntegerScaling
10+ {
11+ /**
12+ * Calculates an integer scaling ratio common for X/Y axes (square pixels).
13+ *
14+ * @param int $areaWidth
15+ * @param int $areaHeight
16+ * @param int $imageWidth
17+ * @param int $imageHeight
18+ * @return int;
19+ */
20+ public static function calculateRatio (int $ areaWidth , int $ areaHeight , int $ imageWidth , int $ imageHeight ) {
21+ if ($ areaHeight * $ imageWidth < $ areaWidth * $ imageHeight ) {
22+ $ areaSize = $ areaHeight ;
23+ $ imageSize = $ imageHeight ;
24+ }
25+ else {
26+ $ areaSize = $ areaWidth ;
27+ $ imageSize = $ imageWidth ;
28+ }
29+
30+ $ ratio = floor ($ areaSize / $ imageSize );
31+
32+ if ($ ratio < 1 ) {
33+ $ ratio = 1 ;
34+ }
35+
36+ return $ ratio ;
37+ }
38+
39+ /**
40+ * Calculates integer scaling ratios potentially different for X/Y axes
41+ * as a result of aspect-ratio correction (rectangular pixels).
42+ *
43+ * @param int $areaWidth
44+ * @param int $areaHeight
45+ * @param int $imageWidth
46+ * @param int $imageHeight
47+ * @param float $aspectX
48+ * @param float $aspectY
49+ * @return array(string => int)
50+ */
51+ public static function calculateRatios (int $ areaWidth , int $ areaHeight , int $ imageWidth , int $ imageHeight , float $ aspectX = 0.0 , float $ aspectY = 0.0 ) {
52+ if ($ imageWidth * $ aspectY === $ imageHeight * $ aspectX ) {
53+ $ ratio = self ::calculateRatio ($ areaWidth , $ areaHeight , $ imageWidth , $ imageHeight );
54+
55+ return new IntegerScaling \Ratios ($ ratio );
56+ }
57+
58+ $ maxRatioX = floor ($ areaWidth / $ imageWidth );
59+ $ maxRatioY = floor ($ areaHeight / $ imageHeight );
60+ $ maxWidth = $ imageWidth * $ maxRatioX ;
61+ $ maxHeight = $ imageHeight * $ maxRatioY ;
62+ $ maxWidthAspectY = $ maxWidth * $ aspectY ;
63+ $ maxHeightAspectX = $ maxHeight * $ aspectX ;
64+
65+ if ($ maxWidthAspectY === $ maxHeightAspectX ) {
66+ $ ratioX = $ maxRatioX ;
67+ $ ratioY = $ maxRatioY ;
68+ }
69+ else {
70+ $ maxAspectLessThanTarget = $ maxWidthAspectY < $ maxHeightAspectX ;
71+
72+ if ($ maxAspectLessThanTarget ) {
73+ $ ratioA = $ maxRatioX ;
74+ $ maxSizeA = $ maxWidth ;
75+ $ imageSizeB = $ imageHeight ;
76+ $ aspectA = $ aspectX ;
77+ $ aspectB = $ aspectY ;
78+ }
79+ else {
80+ $ ratioA = $ maxRatioY ;
81+ $ maxSizeA = $ maxHeight ;
82+ $ imageSizeB = $ imageWidth ;
83+ $ aspectA = $ aspectY ;
84+ $ aspectB = $ aspectX ;
85+ }
86+
87+ $ ratioBFract = $ maxSizeA * $ aspectB / $ aspectA / $ imageSizeB ;
88+ $ ratioBFloor = floor ($ ratioBFract );
89+ $ ratioBCeil = ceil ($ ratioBFract );
90+ $ parFloor = $ ratioBFloor / $ ratioA ;
91+ $ parCeil = $ ratioBCeil / $ ratioA ;
92+
93+ if ($ maxAspectLessThanTarget ) {
94+ $ parFloor = 1 / $ parFloor ;
95+ $ parCeil = 1 / $ parCeil ;
96+ }
97+
98+ $ commonFactor = $ imageWidth * $ aspectY / $ aspectX / $ imageHeight ;
99+ $ errorFloor = abs (1 - $ commonFactor * $ parFloor );
100+ $ errorCeil = abs (1 - $ commonFactor * $ parCeil );
101+
102+ if (abs ($ errorFloor - $ errorCeil ) < .001 ) {
103+ $ ratioB = abs ($ ratioA - $ ratioBFloor ) < abs ($ ratioA - $ ratioBCeil )
104+ ? $ ratioBFloor
105+ : $ ratioBCeil ;
106+ }
107+ else {
108+ $ ratioB = $ errorFloor < $ errorCeil
109+ ? $ ratioBFloor
110+ : $ ratioBCeil ;
111+ }
112+
113+ if ($ maxAspectLessThanTarget ) {
114+ $ ratioX = $ ratioA ;
115+ $ ratioY = $ ratioB ;
116+ }
117+ else {
118+ $ ratioX = $ ratioB ;
119+ $ ratioY = $ ratioA ;
120+ }
121+ }
122+
123+ if ($ ratioX < 1 ) {
124+ $ ratioX = 1 ;
125+ }
126+
127+ if ($ ratioY < 1 ) {
128+ $ ratioY = 1 ;
129+ }
130+
131+ return new IntegerScaling \Ratios ($ ratioX , $ ratioY );
132+ }
133+ }
0 commit comments