Skip to content

Commit e321f3a

Browse files
committed
Initial commit.
0 parents  commit e321f3a

File tree

5 files changed

+201
-0
lines changed

5 files changed

+201
-0
lines changed

LICENSE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2020 Marat Tanalin (http://tanalin.com )
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Calculates integer ratios for pixel-perfect image upscaling with optional aspect-ratio correction.
2+
3+
See the project [webpage](http://tanalin.com/en/projects/integer-scaling/) for details.

composer.json

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"name": "marat-tanalin/integer-scaling",
3+
"version" : "1.2.1",
4+
"type": "library",
5+
"description": "Calculates integer ratios for pixel-perfect image upscaling with optional aspect-ratio correction.",
6+
"homepage": "http://tanalin.com/en/projects/integer-scaling/",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Marat Tanalin",
11+
"homepage": "http://tanalin.com"
12+
}
13+
],
14+
"keywords": [
15+
"integer-scaling",
16+
"pixel-perfect-scaling",
17+
"image-scaling",
18+
"algorithms",
19+
"graphics"
20+
],
21+
"require": {
22+
"php": "^7.2"
23+
},
24+
"autoload": {
25+
"psr-4": {
26+
"MaratTanalin\\": "src/"
27+
}
28+
}
29+
}

src/IntegerScaling.php

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
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+
}

src/IntegerScaling/Ratios.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
/*! Marat Tanalin | http://tanalin.com */
4+
5+
namespace MaratTanalin\IntegerScaling;
6+
7+
class Ratios
8+
{
9+
public $x, $y;
10+
11+
public function __construct(int $x, int $y = 0) {
12+
$this->x = $x;
13+
$this->y = 0 === $y ? $x : $y;
14+
}
15+
}

0 commit comments

Comments
 (0)