use
5.008;
our
$VERSION
= 0.05;
my
$termcolors
= {
16
=> [0 , 0 , 0],
52
=> [95 , 0 , 0],
88
=> [135 , 0 , 0],
17
=> [0 , 0 , 95],
53
=> [95 , 0 , 95],
89
=> [135 , 0 , 95],
18
=> [0 , 0 , 135],
54
=> [95 , 0 , 135],
90
=> [135 , 0 , 135],
19
=> [0 , 0 , 175],
55
=> [95 , 0 , 175],
91
=> [135 , 0 , 175],
20
=> [0 , 0 , 215],
56
=> [95 , 0 , 215],
92
=> [135 , 0 , 215],
21
=> [0 , 0 , 255],
57
=> [95 , 0 , 255],
93
=> [135 , 0 , 255],
22
=> [0 , 95 , 0],
58
=> [95 , 95 , 0],
94
=> [135 , 95 , 0],
23
=> [0 , 95 , 95],
59
=> [95 , 95 , 95],
95
=> [135 , 95 , 95],
24
=> [0 , 95 , 135],
60
=> [95 , 95 , 135],
96
=> [135 , 95 , 135],
25
=> [0 , 95 , 175],
61
=> [95 , 95 , 175],
97
=> [135 , 95 , 175],
26
=> [0 , 95 , 215],
62
=> [95 , 95 , 215],
98
=> [135 , 95 , 215],
27
=> [0 , 95 , 255],
63
=> [95 , 95 , 255],
99
=> [135 , 95 , 255],
28
=> [0 , 135 , 0],
64
=> [95 , 135 , 0],
100
=> [135 , 135 , 0],
29
=> [0 , 135 , 95],
65
=> [95 , 135 , 95],
101
=> [135 , 135 , 95],
30
=> [0 , 135 , 135],
66
=> [95 , 135 , 135],
102
=> [135 , 135 , 135],
31
=> [0 , 135 , 175],
67
=> [95 , 135 , 175],
103
=> [135 , 135 , 175],
32
=> [0 , 135 , 215],
68
=> [95 , 135 , 215],
104
=> [135 , 135 , 215],
33
=> [0 , 135 , 255],
69
=> [95 , 135 , 255],
105
=> [135 , 135 , 255],
34
=> [0 , 175 , 0],
70
=> [95 , 175 , 0],
106
=> [135 , 175 , 0],
35
=> [0 , 175 , 95],
71
=> [95 , 175 , 95],
107
=> [135 , 175 , 95],
36
=> [0 , 175 , 135],
72
=> [95 , 175 , 135],
108
=> [135 , 175 , 135],
37
=> [0 , 175 , 175],
73
=> [95 , 175 , 175],
109
=> [135 , 175 , 175],
38
=> [0 , 175 , 215],
74
=> [95 , 175 , 215],
110
=> [135 , 175 , 215],
39
=> [0 , 175 , 255],
75
=> [95 , 175 , 255],
111
=> [135 , 175 , 255],
40
=> [0 , 215 , 0],
76
=> [95 , 215 , 0],
112
=> [135 , 215 , 0],
41
=> [0 , 215 , 95],
77
=> [95 , 215 , 95],
113
=> [135 , 215 , 95],
42
=> [0 , 215 , 135],
78
=> [95 , 215 , 135],
114
=> [135 , 215 , 135],
43
=> [0 , 215 , 175],
79
=> [95 , 215 , 175],
115
=> [135 , 215 , 175],
44
=> [0 , 215 , 215],
80
=> [95 , 215 , 215],
116
=> [135 , 215 , 215],
45
=> [0 , 215 , 255],
81
=> [95 , 215 , 255],
117
=> [135 , 215 , 255],
46
=> [0 , 255 , 0],
82
=> [95 , 255 , 0],
118
=> [135 , 255 , 0],
47
=> [0 , 255 , 95],
83
=> [95 , 255 , 95],
119
=> [135 , 255 , 95],
48
=> [0 , 255 , 135],
84
=> [95 , 255 , 135],
120
=> [135 , 255 , 135],
49
=> [0 , 255 , 175],
85
=> [95 , 255 , 175],
121
=> [135 , 255 , 175],
50
=> [0 , 255 , 215],
86
=> [95 , 255 , 215],
122
=> [135 , 255 , 215],
51
=> [0 , 255 , 255],
87
=> [95 , 255 , 255],
123
=> [135 , 255 , 255],
124
=> [175 , 0 , 0],
160
=> [215 , 0 , 0],
196
=> [255 , 0 , 0],
125
=> [175 , 0 , 95],
161
=> [215 , 0 , 95],
197
=> [255 , 0 , 95],
126
=> [175 , 0 , 135],
162
=> [215 , 0 , 135],
198
=> [255 , 0 , 135],
127
=> [175 , 0 , 175],
163
=> [215 , 0 , 175],
199
=> [255 , 0 , 175],
128
=> [175 , 0 , 215],
164
=> [215 , 0 , 215],
200
=> [255 , 0 , 215],
129
=> [175 , 0 , 255],
165
=> [215 , 0 , 255],
201
=> [255 , 0 , 255],
130
=> [175 , 95 , 0],
166
=> [215 , 95 , 0],
202
=> [255 , 95 , 0],
131
=> [175 , 95 , 95],
167
=> [215 , 95 , 95],
203
=> [255 , 95 , 95],
132
=> [175 , 95 , 135],
168
=> [215 , 95 , 135],
204
=> [255 , 95 , 135],
133
=> [175 , 95 , 175],
169
=> [215 , 95 , 175],
205
=> [255 , 95 , 175],
134
=> [175 , 95 , 215],
170
=> [215 , 95 , 215],
206
=> [255 , 95 , 215],
135
=> [175 , 95 , 255],
171
=> [215 , 95 , 255],
207
=> [255 , 95 , 255],
136
=> [175 , 135 , 0],
172
=> [215 , 135 , 0],
208
=> [255 , 135 , 0],
137
=> [175 , 135 , 95],
173
=> [215 , 135 , 95],
209
=> [255 , 135 , 95],
138
=> [175 , 135 , 135],
174
=> [215 , 135 , 135],
210
=> [255 , 135 , 135],
139
=> [175 , 135 , 175],
175
=> [215 , 135 , 175],
211
=> [255 , 135 , 175],
140
=> [175 , 135 , 215],
176
=> [215 , 135 , 215],
212
=> [255 , 135 , 215],
141
=> [175 , 135 , 255],
177
=> [215 , 135 , 255],
213
=> [255 , 135 , 255],
142
=> [175 , 175 , 0],
178
=> [215 , 175 , 0],
214
=> [255 , 175 , 0],
143
=> [175 , 175 , 95],
179
=> [215 , 175 , 95],
215
=> [255 , 175 , 95],
144
=> [175 , 175 , 135],
180
=> [215 , 175 , 135],
216
=> [255 , 175 , 135],
145
=> [175 , 175 , 175],
181
=> [215 , 175 , 175],
217
=> [255 , 175 , 175],
146
=> [175 , 175 , 215],
182
=> [215 , 175 , 215],
218
=> [255 , 175 , 215],
147
=> [175 , 175 , 255],
183
=> [215 , 175 , 255],
219
=> [255 , 175 , 255],
148
=> [175 , 215 , 0],
184
=> [215 , 215 , 0],
220
=> [255 , 215 , 0],
149
=> [175 , 215 , 95],
185
=> [215 , 215 , 95],
221
=> [255 , 215 , 95],
150
=> [175 , 215 , 135],
186
=> [215 , 215 , 135],
222
=> [255 , 215 , 135],
151
=> [175 , 215 , 175],
187
=> [215 , 215 , 175],
223
=> [255 , 215 , 175],
152
=> [175 , 215 , 215],
188
=> [215 , 215 , 215],
224
=> [255 , 215 , 215],
153
=> [175 , 215 , 255],
189
=> [215 , 215 , 255],
225
=> [255 , 215 , 255],
154
=> [175 , 255 , 0],
190
=> [215 , 255 , 0],
226
=> [255 , 255 , 0],
155
=> [175 , 255 , 95],
191
=> [215 , 255 , 95],
227
=> [255 , 255 , 95],
156
=> [175 , 255 , 135],
192
=> [215 , 255 , 135],
228
=> [255 , 255 , 135],
157
=> [175 , 255 , 175],
193
=> [215 , 255 , 175],
229
=> [255 , 255 , 175],
158
=> [175 , 255 , 215],
194
=> [215 , 255 , 215],
230
=> [255 , 255 , 215],
159
=> [175 , 255 , 255],
195
=> [215 , 255 , 255],
231
=> [255 , 255 , 255],
232
=> [8 , 8 , 8],
233
=> [18 , 18 , 18],
234
=> [28 , 28 , 28],
235
=> [38 , 38 , 38],
236
=> [48 , 48 , 48],
237
=> [58 , 58 , 58],
238
=> [68 , 68 , 68],
239
=> [78 , 78 , 78],
240
=> [88 , 88 , 88],
241
=> [98 , 98 , 98],
242
=> [108 , 108 , 108],
243
=> [118 , 118 , 118],
244
=> [128 , 128 , 128],
245
=> [138 , 138 , 138],
246
=> [148 , 148 , 148],
247
=> [158 , 158 , 158],
248
=> [168 , 168 , 168],
249
=> [178 , 178 , 178],
250
=> [188 , 188 , 188],
251
=> [198 , 198 , 198],
252
=> [208 , 208 , 208],
253
=> [218 , 218 , 218],
254
=> [228 , 228 , 228],
255
=> [238 , 238 , 238],
};
my
$pal
= GD::Image->new();
my
@colorlookup
;
foreach
my
$k
(
keys
( %{
$termcolors
} )){
$pal
->colorAllocate(
$termcolors
->{
$k
}->[0],
$termcolors
->{
$k
}->[1],
$termcolors
->{
$k
}->[2]);
push
(
@colorlookup
,
$k
);
}
sub
convert {
my
(
$img
,
$opts
) =
@_
;
my
$gdimg
;
my
$utf8
= 0;
if
(
$opts
){
if
(
$opts
->{scale_ratio} ||
$opts
->{scale_x} ){
my
$origimg
= GD::Image->new(
$img
);
unless
(
$origimg
){
return
wantarray
? () : 0;
}
my
(
$width
,
$height
) =
$origimg
->getBounds();
my
$ratio
;
if
(
$opts
->{scale_ratio} ){
$ratio
=
$opts
->{scale_ratio};
}
elsif
(
$opts
->{scale_x} ){
$ratio
=
$opts
->{scale_x} /
$width
;
}
$gdimg
= GD::Image->new(
$width
*
$ratio
,
$height
*
$ratio
);
if
(
$origimg
->transparent() >= 0 ){
$gdimg
->colorAllocate(
$origimg
->rgb(
$origimg
->transparent()));
$gdimg
->transparent(
$origimg
->transparent());
}
$gdimg
->copyResized(
$origimg
, 0,0,0,0,
$width
*
$ratio
,
$height
*
$ratio
,
$width
,
$height
);
}
if
(
$opts
->{utf8} ){
$utf8
= 1;
}
}
unless
(
$gdimg
){
$gdimg
= GD::Image->new(
$img
);
unless
(
$gdimg
){
return
wantarray
? () : 0;
}
}
return
convert_from_gdimg(
$gdimg
,
$utf8
);
}
sub
get_term256color {
my
(
$r
,
$g
,
$b
) =
@_
;
return
$colorlookup
[
$pal
->colorClosest(
$r
,
$g
,
$b
)];
}
sub
gdimg_to_ansi {
my
(
$img
,
$color_check
) =
@_
;
my
@termimg
;
my
$char
=
' '
;
my
(
$width
,
$height
) =
$img
->getBounds();
for
(
my
$i
=0;
$i
<
$height
;
$i
++ ){
my
$rowstring
;
my
$localstring
;
my
$curcolor
= 0;
for
(
my
$j
=0;
$j
<
$width
;
$j
++ ){
my
$newcolor
=
$color_check
->(
$j
,
$i
);
if
(
$newcolor
!=
$curcolor
){
$rowstring
.=
$curcolor
>= 0 ? bg(
$curcolor
,
$localstring
) : clear() .
$localstring
;
$curcolor
=
$newcolor
;
$localstring
=
''
;
}
$localstring
.=
$char
;
}
$rowstring
.=
$curcolor
>= 0 ? bg(
$curcolor
,
$localstring
) : clear() .
$localstring
;
push
(
@termimg
,
$rowstring
);
}
return
@termimg
;
}
sub
gdimg_to_utf8 {
my
(
$img
,
$color_check
) =
@_
;
my
@termimg
;
my
(
$width
,
$height
) =
$img
->getBounds();
for
(
my
$i
=0;
$i
<
$height
;
$i
+=2 ){
my
$rowstring
;
my
$localstring
;
my
$curcolor
= 0;
for
(
my
$j
=0;
$j
<
$width
;
$j
++ ){
my
$colortop
=
$color_check
->(
$j
,
$i
);
my
$colorbottom
=
$color_check
->(
$j
,
$i
+1);
if
(
$colortop
==
$colorbottom
){
$rowstring
.=
$colortop
>= 0 ? bg(
$colortop
,
' '
) : clear() .
' '
;
}
elsif
(
$colortop
!=
$colorbottom
){
if
(
$colortop
>= 0 &&
$colorbottom
>= 0 ){
$rowstring
.= bg(
$colorbottom
, fg(
$colortop
,
'▀'
));
}
elsif
(
$colortop
>= 0 &&
$colorbottom
< 0 ){
$rowstring
.= clear() . fg(
$colortop
,
'▀'
);
}
elsif
(
$colortop
< 0 &&
$colorbottom
>= 0 ){
$rowstring
.= clear() . fg(
$colorbottom
,
'▄'
);
}
}
}
push
(
@termimg
,
$rowstring
);
}
return
@termimg
;
}
sub
convert_from_gdimg {
my
(
$img
,
$utf8
) =
@_
;
my
$transparent
=
$img
->transparent();
my
$color_check
;
if
(
$transparent
>= 0 ){
$color_check
=
sub
{
my
(
$j
,
$i
) =
@_
;
my
$ptotest
=
$img
->getPixel(
$j
,
$i
);
if
(
$img
->colorExact(
$img
->rgb(
$ptotest
) ) < 0 ){
return
-1;
}
else
{
return
$colorlookup
[
$pal
->colorClosest(
$img
->rgb(
$ptotest
))];
}
};
}
else
{
$color_check
=
sub
{
my
(
$j
,
$i
) =
@_
;
my
$ptotest
=
$img
->getPixel(
$j
,
$i
);
return
$colorlookup
[
$pal
->colorClosest(
$img
->rgb(
$ptotest
))];
};
}
my
@termimg
=
$utf8
? gdimg_to_utf8(
$img
,
$color_check
) : gdimg_to_ansi(
$img
,
$color_check
);
return
wantarray
?
@termimg
:
join
(
"\n"
,
@termimg
);
}
1;