1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Pixeler |
5
|
|
|
* |
6
|
|
|
* UTF-8 Dot matrix renderer. |
7
|
|
|
* |
8
|
|
|
* @package pixeler |
9
|
|
|
* @author [email protected] |
10
|
|
|
* @version 1.0 |
11
|
|
|
* @copyright Stefano Azzolini - 2014 - http://dreamnoctis.com |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
namespace Pixeler; |
15
|
|
|
|
16
|
|
|
class Image extends Matrix { |
17
|
|
|
const DITHER_NONE = 0, |
18
|
|
|
DITHER_ERROR = 1; |
19
|
|
|
|
20
|
|
|
public function __construct($img, $resize=1.0, $invert=false, $weight = 0.5, $dither=self::DITHER_ERROR){ |
21
|
|
|
$ext = strtolower(pathinfo($img, PATHINFO_EXTENSION)); |
22
|
|
|
if ($ext == 'jpg') $ext = 'jpeg'; |
23
|
|
|
$imagecreator = 'imagecreatefrom' . $ext; |
24
|
|
|
|
25
|
|
|
if (!function_exists($imagecreator)) |
26
|
|
|
throw new \Exception('Image format not supported.', 1); |
27
|
|
|
|
28
|
|
|
$im = $imagecreator($img); |
29
|
|
|
$w = imagesx($im); |
30
|
|
|
$h = imagesy($im); |
31
|
|
|
|
32
|
|
|
// Resize image |
33
|
|
|
$nw = ceil($resize * $w); |
34
|
|
|
$nh = ceil($resize * $h * 0.75); |
35
|
|
|
$new_img = imagecreatetruecolor($nw, $nh); |
36
|
|
|
imagesavealpha ($new_img, true); |
37
|
|
|
imagealphablending ($new_img, false); |
38
|
|
|
imagefill ($new_img, 0, 0, imagecolorallocate($new_img, 255, 255, 255)); |
39
|
|
|
imagecopyresized ($new_img, $im, 0, 0, 0, 0, $nw, $nh, $w, $h); |
40
|
|
|
imagedestroy ($im); |
41
|
|
|
$im = $new_img; |
42
|
|
|
$w = $nw; $h = $nh; |
43
|
|
|
|
44
|
|
|
// Init Dot Matrix |
45
|
|
|
parent::__construct($w, $h); |
46
|
|
|
|
47
|
|
|
// Create the color matrix |
48
|
|
|
$color_img_w = ceil($w/2); |
49
|
|
|
$color_img_h = ceil($h/4); |
50
|
|
|
|
51
|
|
|
// Lower precision -> faster palette lookup -> uglier colors. |
52
|
|
|
$min_color_precision = 20; |
53
|
|
|
|
54
|
|
|
$color_img = imagecreatetruecolor($color_img_w, $color_img_h); |
55
|
|
|
imagesavealpha ($color_img, true); |
56
|
|
|
imagealphablending ($color_img, false); |
57
|
|
|
imagefill ($color_img, 0, 0, imagecolorallocate($color_img, 255, 255, 255)); |
58
|
|
|
imagecopyresized ($color_img, $im, 0, 0, 0, 0, $color_img_w, $color_img_h, $w, $h); |
59
|
|
|
|
60
|
|
|
// ANSI 8bit Palette |
61
|
|
|
$ansi256palette = [ |
62
|
|
|
0x000000,0x800000,0x008000,0x808000,0x000080,0x800080,0x008080,0xc0c0c0, |
63
|
|
|
0x808080,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00ffff,0xffffff, |
64
|
|
|
0x000000,0x00005f,0x000087,0x0000af,0x0000d7,0x0000ff,0x005f00,0x005f5f, |
65
|
|
|
0x005f87,0x005faf,0x005fd7,0x005fff,0x008700,0x00875f,0x008787,0x0087af, |
66
|
|
|
0x0087d7,0x0087ff,0x00af00,0x00af5f,0x00af87,0x00afaf,0x00afd7,0x00afff, |
67
|
|
|
0x00d700,0x00d75f,0x00d787,0x00d7af,0x00d7d7,0x00d7ff,0x00ff00,0x00ff5f, |
68
|
|
|
0x00ff87,0x00ffaf,0x00ffd7,0x00ffff,0x5f0000,0x5f005f,0x5f0087,0x5f00af, |
69
|
|
|
0x5f00d7,0x5f00ff,0x5f5f00,0x5f5f5f,0x5f5f87,0x5f5faf,0x5f5fd7,0x5f5fff, |
70
|
|
|
0x5f8700,0x5f875f,0x5f8787,0x5f87af,0x5f87d7,0x5f87ff,0x5faf00,0x5faf5f, |
71
|
|
|
0x5faf87,0x5fafaf,0x5fafd7,0x5fafff,0x5fd700,0x5fd75f,0x5fd787,0x5fd7af, |
72
|
|
|
0x5fd7d7,0x5fd7ff,0x5fff00,0x5fff5f,0x5fff87,0x5fffaf,0x5fffd7,0x5fffff, |
73
|
|
|
0x870000,0x87005f,0x870087,0x8700af,0x8700d7,0x8700ff,0x875f00,0x875f5f, |
74
|
|
|
0x875f87,0x875faf,0x875fd7,0x875fff,0x878700,0x87875f,0x878787,0x8787af, |
75
|
|
|
0x8787d7,0x8787ff,0x87af00,0x87af5f,0x87af87,0x87afaf,0x87afd7,0x87afff, |
76
|
|
|
0x87d700,0x87d75f,0x87d787,0x87d7af,0x87d7d7,0x87d7ff,0x87ff00,0x87ff5f, |
77
|
|
|
0x87ff87,0x87ffaf,0x87ffd7,0x87ffff,0xaf0000,0xaf005f,0xaf0087,0xaf00af, |
78
|
|
|
0xaf00d7,0xaf00ff,0xaf5f00,0xaf5f5f,0xaf5f87,0xaf5faf,0xaf5fd7,0xaf5fff, |
79
|
|
|
0xaf8700,0xaf875f,0xaf8787,0xaf87af,0xaf87d7,0xaf87ff,0xafaf00,0xafaf5f, |
80
|
|
|
0xafaf87,0xafafaf,0xafafd7,0xafafff,0xafd700,0xafd75f,0xafd787,0xafd7af, |
81
|
|
|
0xafd7d7,0xafd7ff,0xafff00,0xafff5f,0xafff87,0xafffaf,0xafffd7,0xafffff, |
82
|
|
|
0xd70000,0xd7005f,0xd70087,0xd700af,0xd700d7,0xd700ff,0xd75f00,0xd75f5f, |
83
|
|
|
0xd75f87,0xd75faf,0xd75fd7,0xd75fff,0xd78700,0xd7875f,0xd78787,0xd787af, |
84
|
|
|
0xd787d7,0xd787ff,0xd7af00,0xd7af5f,0xd7af87,0xd7afaf,0xd7afd7,0xd7afff, |
85
|
|
|
0xd7d700,0xd7d75f,0xd7d787,0xd7d7af,0xd7d7d7,0xd7d7ff,0xd7ff00,0xd7ff5f, |
86
|
|
|
0xd7ff87,0xd7ffaf,0xd7ffd7,0xd7ffff,0xff0000,0xff005f,0xff0087,0xff00af, |
87
|
|
|
0xff00d7,0xff00ff,0xff5f00,0xff5f5f,0xff5f87,0xff5faf,0xff5fd7,0xff5fff, |
88
|
|
|
0xff8700,0xff875f,0xff8787,0xff87af,0xff87d7,0xff87ff,0xffaf00,0xffaf5f, |
89
|
|
|
0xffaf87,0xffafaf,0xffafd7,0xffafff,0xffd700,0xffd75f,0xffd787,0xffd7af, |
90
|
|
|
0xffd7d7,0xffd7ff,0xffff00,0xffff5f,0xffff87,0xffffaf,0xffffd7,0xffffff, |
91
|
|
|
0x080808,0x121212,0x1c1c1c,0x262626,0x303030,0x3a3a3a,0x444444,0x4e4e4e, |
92
|
|
|
0x585858,0x606060,0x666666,0x767676,0x808080,0x8a8a8a,0x949494,0x9e9e9e, |
93
|
|
|
0xa8a8a8,0xb2b2b2,0xbcbcbc,0xc6c6c6,0xd0d0d0,0xdadada,0xe4e4e4,0xeeeeee |
94
|
|
|
]; |
95
|
|
|
|
96
|
|
|
$colormap = []; |
97
|
|
|
foreach ($ansi256palette as $rgb) $colormap[] = [ |
98
|
|
|
($rgb >> 16) & 0xFF, |
99
|
|
|
($rgb >> 8) & 0xFF, |
100
|
|
|
($rgb) & 0xFF |
101
|
|
|
]; |
102
|
|
|
$ansi256palette = $colormap; |
103
|
|
|
$colormap = []; |
|
|
|
|
104
|
|
|
|
105
|
|
|
// Find nearest match of passed RGB with ANSI palette |
106
|
|
|
$nearest = function($rgb) use ($ansi256palette, $min_color_precision){ |
107
|
|
|
$best = 0; $dist = 10000; |
108
|
|
|
foreach ($ansi256palette as $idx => $a) { |
109
|
|
|
$d = sqrt( |
110
|
|
|
pow($rgb['red']-$a[0],2) + pow($rgb['green']-$a[1],2) + pow($rgb['blue']-$a[2],2) |
111
|
|
|
); |
112
|
|
|
if($d < $dist) { |
113
|
|
|
$dist = $d; |
114
|
|
|
$best = $idx; |
115
|
|
|
if($d <= $min_color_precision) break; |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
return $best; |
119
|
|
|
}; |
120
|
|
|
|
121
|
|
|
// Read colors |
122
|
|
|
$c = $this->colors; |
123
|
|
|
for($y = $color_img_h; $y--;){ |
124
|
|
|
$y0 = $y * $color_img_w; |
125
|
|
|
for($x = $color_img_w; $x-- ;){ |
126
|
|
|
$c[ $y0 + $x ] = $nearest(imagecolorsforindex($color_img,imagecolorat($color_img, $x, $y))); |
127
|
|
|
} |
128
|
|
|
} |
129
|
|
|
$this->colors = $c; |
130
|
|
|
imagedestroy($color_img); |
131
|
|
|
|
132
|
|
|
// Invert image for dark backgrounds |
133
|
|
|
if ($invert) imagefilter($im, IMG_FILTER_NEGATE); |
134
|
|
|
|
135
|
|
|
|
136
|
|
|
$pixels = new \SplFixedArray($w * $h); |
137
|
|
|
for($y = $h ; $y-- ;){ |
138
|
|
|
for($x = $w, $y0 = $y * $w ; $x-- ;){ |
139
|
|
|
$pixels[$x + $y0] = imagecolorat($im, $x, $y); |
140
|
|
|
} |
141
|
|
|
} |
142
|
|
|
imagedestroy($im); |
143
|
|
|
|
144
|
|
|
$m = $this->matrix; |
145
|
|
|
switch($dither){ |
146
|
|
|
|
147
|
|
|
// Threshold 1-bit quantization |
148
|
|
|
case self::DITHER_NONE: |
149
|
|
|
default: |
150
|
|
|
$tresh = (0xffffff * $weight) & 0xffffff; |
151
|
|
|
$b = $invert?1:0; |
152
|
|
|
for ($y=0; $y < $h; $y++){ |
153
|
|
|
$y0 = $y * $w; $y1 = $y0 + $w; $y2 = $y1 + $w; |
|
|
|
|
154
|
|
|
for ($x=0; $x < $w; $x++) { |
155
|
|
|
$idx = $x + $y0; |
156
|
|
|
$m[$idx] = $pixels[$idx]<=$tresh?$pixels[$idx]:$b; |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
break; |
160
|
|
|
|
161
|
|
|
// Dither image with 1-bit Atkinson Dithering |
162
|
|
|
// Adapted from : https://gist.github.com/lordastley/1342627 |
163
|
|
|
case self::DITHER_ERROR: |
|
|
|
|
164
|
|
|
$tresh = (0xffffff * $weight) & 0xffffff; |
165
|
|
|
for ($y=0; $y < $h; $y++){ |
166
|
|
|
$y0 = $y * $w; $y1 = $y0 + $w; $y2 = $y1 + $w; |
167
|
|
|
for ($x=0; $x < $w; $x++) { |
168
|
|
|
$idx = $x + $y0; |
169
|
|
|
$old = $pixels[$idx]; |
170
|
|
|
|
171
|
|
|
if ($old > $tresh){ |
172
|
|
|
$error_diffusion = ($old - 0xffffff) >> 3; |
173
|
|
|
} else { |
174
|
|
|
$error_diffusion = $old >> 3; |
175
|
|
|
$m[$idx] = $old; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
|
179
|
|
|
$x1 = $x + 1; $x2 = $x + 2; $x_1 = $x - 1; |
180
|
|
|
|
181
|
|
|
foreach([ |
182
|
|
|
$x1 + $y0, |
183
|
|
|
$x2 + $y0, |
184
|
|
|
$x_1 + $y1, |
185
|
|
|
$x + $y1, |
186
|
|
|
$x1 + $y1, |
187
|
|
|
$x + $y2, |
188
|
|
|
] as $ofs) { |
189
|
|
|
if (isset($pixels[$ofs])) $pixels[$ofs] += $error_diffusion; |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
break; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
} |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVar
assignment in line 1 and the$higher
assignment in line 2 are dead. The first because$myVar
is never used and the second because$higher
is always overwritten for every possible time line.