@@ -8,42 +8,41 @@ function _charof(alpha)
88 alpha_chars[clamp (idx + 1 , 1 , length (alpha_chars))]
99end
1010
11- function downscale_small ( img:: AbstractMatrix{<:Colorant} , maxheight:: Int , maxwidth:: Int )
11+ function downscale ( :: SmallBlocks , img:: AbstractMatrix{<:Colorant} , maxheight:: Int , maxwidth:: Int )
1212 maxheight = max (maxheight, 5 )
1313 maxwidth = max (maxwidth, 5 )
1414 h, w = map (length, axes (img))
1515 while ceil (h/ 2 ) > maxheight || w > maxwidth
1616 img = restrict (img)
1717 h, w = map (length, axes (img))
1818 end
19- img
19+ img, length ( 1 : 2 : h), w
2020end
2121
22- function downscale_big ( img:: AbstractMatrix{<:Colorant} , maxheight:: Int , maxwidth:: Int )
22+ function downscale ( :: BigBlocks , img:: AbstractMatrix{<:Colorant} , maxheight:: Int , maxwidth:: Int )
2323 maxheight = max (maxheight, 5 )
2424 maxwidth = max (maxwidth, 5 )
2525 h, w = map (length, axes (img))
2626 while h > maxheight || 2 w > maxwidth
2727 img = restrict (img)
2828 h, w = map (length, axes (img))
2929 end
30- img
30+ img, h, 2 w
3131end
3232
33- function downscale_small ( img:: AbstractVector{<:Colorant} , maxwidth:: Int )
33+ function downscale ( :: SmallBlocks , img:: AbstractVector{<:Colorant} , maxwidth:: Int )
3434 maxwidth = max (maxwidth, 5 )
35- while size (img, 1 ) > maxwidth
35+ while length (img) > maxwidth
3636 img = restrict (img)
3737 end
38- img
38+ img, 1 , length (img)
3939end
4040
41- function downscale_big (img:: AbstractVector{<:Colorant} , maxwidth:: Int )
42- maxwidth = max (maxwidth, 5 )
43- inds = axes (img, 1 )
44- w = length (inds)
45- n = 3 w > maxwidth ? floor (Int,maxwidth/ 6 ) : w
46- img[(0 : n- 1 ) .+ first (inds)], img[(- n+ 1 : 0 ) .+ last (inds)], w
41+ function downscale (:: BigBlocks , img:: AbstractVector{<:Colorant} , maxwidth:: Int )
42+ maxwidth = max (maxwidth, 5 )
43+ w = length (img)
44+ n = 3 w > maxwidth ? maxwidth ÷ 6 : w
45+ return img, 1 , n < w ? 3 (2 n + 1 ) : 3 w
4746end
4847
4948"""
@@ -75,21 +74,21 @@ The function returns a tuple with three elements:
7574"""
7675
7776function ascii_encode (
78- :: SmallBlocks ,
77+ enc :: SmallBlocks ,
7978 colordepth:: TermColorDepth ,
8079 img:: AbstractMatrix{<:Colorant} ,
8180 maxheight:: Int = 50 ,
8281 maxwidth:: Int = 80 )
83- img = downscale_small ( img, maxheight, maxwidth)
82+ img, hh, ww = downscale (enc, img, maxheight, maxwidth)
8483 h, w = map (length, axes (img))
8584 yinds, xinds = axes (img)
8685 io = PipeBuffer ()
8786 for y in first (yinds): 2 : last (yinds)
8887 print (io, Crayon (reset = true ))
8988 for x in xinds
90- fgcol = _colorant2ansi (img[y,x], colordepth)
89+ fgcol = _colorant2ansi (img[y, x], colordepth)
9190 bgcol = if y+ 1 <= last (yinds)
92- _colorant2ansi (img[y+ 1 ,x], colordepth)
91+ _colorant2ansi (img[y+ 1 , x], colordepth)
9392 else
9493 # if reached it means that the last character row
9594 # has only the upper pixel defined.
@@ -99,38 +98,38 @@ function ascii_encode(
9998 end
10099 println (io, Crayon (reset = true ))
101100 end
102- replace .( readlines (io), Ref ( " \n " => " " )) :: Vector{String} , length ( 1 : 2 : h), w
101+ readlines (io), hh, ww
103102end
104103
105104function ascii_encode (
106- :: BigBlocks ,
105+ enc :: BigBlocks ,
107106 colordepth:: TermColorDepth ,
108107 img:: AbstractMatrix{<:Colorant} ,
109108 maxheight:: Int = 50 ,
110109 maxwidth:: Int = 80 )
111- img = downscale_big ( img, maxheight, maxwidth)
110+ img, hh, ww = downscale (enc, img, maxheight, maxwidth)
112111 h, w = map (length, axes (img))
113112 yinds, xinds = axes (img)
114113 io = PipeBuffer ()
115114 for y in yinds
116115 print (io, Crayon (reset = true ))
117116 for x in xinds
118- color = img[y,x]
117+ color = img[y, x]
119118 fgcol = _colorant2ansi (color, colordepth)
120119 chr = _charof (alpha (color))
121120 print (io, Crayon (foreground = fgcol), chr, chr)
122121 end
123122 println (io, Crayon (reset = true ))
124123 end
125- replace .( readlines (io), Ref ( " \n " => " " )) :: Vector{String} , h, 2 w
124+ readlines (io), hh, ww
126125end
127126
128127function ascii_encode (
129- :: SmallBlocks ,
128+ enc :: SmallBlocks ,
130129 colordepth:: TermColorDepth ,
131130 img:: AbstractVector{<:Colorant} ,
132131 maxwidth:: Int = 80 )
133- img = downscale_small ( img, maxwidth)
132+ img, hh, ww = downscale (enc, img, maxwidth)
134133 io = PipeBuffer ()
135134 print (io, Crayon (reset = true ))
136135 for i in axes (img, 1 )
@@ -140,35 +139,88 @@ function ascii_encode(
140139 print (io, Crayon (foreground = fgcol), chr)
141140 end
142141 println (io, Crayon (reset = true ))
143- replace .( readlines (io), Ref ( " \n " => " " )) :: Vector{String} , 1 , size (img, 1 )
142+ readlines (io), hh, ww
144143end
145144
146145function ascii_encode (
147- :: BigBlocks ,
146+ enc :: BigBlocks ,
148147 colordepth:: TermColorDepth ,
149148 img:: AbstractVector{<:Colorant} ,
150149 maxwidth:: Int = 80 )
151- left, right, w = downscale_big ( img, maxwidth)
152- inds = axes (left, 1 )
153- n = length (left)
150+ img, hh, ww = downscale (enc, img, maxwidth)
151+ w = length (img )
152+ n = ww ÷ 3 == w ? w : ww ÷ 6
154153 io = PipeBuffer ()
154+ # left or full
155155 print (io, Crayon (reset = true ))
156- for i in (0 : n- 1 ) .+ first (inds )
157- color = left [i]
156+ for i in (0 : n- 1 ) .+ firstindex (img )
157+ color = img [i]
158158 fgcol = _colorant2ansi (color, colordepth)
159159 chr = _charof (alpha (color))
160160 print (io, Crayon (foreground = fgcol), chr, chr, " " )
161161 end
162- if n < w
162+ if n < w # right part
163163 print (io, Crayon (reset = true ), " … " )
164- for i in (- n+ 1 : 0 ) .+ last (inds )
165- color = right [i]
164+ for i in (- n+ 1 : 0 ) .+ lastindex (img )
165+ color = img [i]
166166 fgcol = _colorant2ansi (color, colordepth)
167167 chr = _charof (alpha (color))
168168 print (io, Crayon (foreground = fgcol), chr, chr, " " )
169169 end
170170 end
171171 println (io, Crayon (reset = true ))
172- width = n < w ? 3 (length (1 : n) + 1 + length (w- n+ 1 : w)) : 3 w
173- replace .(readlines (io), Ref (" \n " => " " )):: Vector{String} , 1 , width
172+ readlines (io), hh, ww
173+ end
174+
175+ """
176+ ascii_display([stream], img, [depth::TermColorDepth], [maxsize])
177+
178+ Displays the given image `img` using unicode characters and terminal colors.
179+ `img` has to be an array of `Colorant`.
180+
181+ - `maxheight` and `maxwidth` specify the maximum numbers of
182+ string characters that should be used for the resulting image.
183+ Larger images are downscaled automatically using `restrict`.
184+
185+ If working in the REPL, the function tries to choose the encoding
186+ based on the current display size. The image will also be
187+ downsampled to fit into the display (using `restrict`).
188+ """
189+
190+ # colorant matrix
191+ function ascii_display (
192+ io:: IO ,
193+ img:: AbstractMatrix{<:Colorant} ,
194+ colordepth:: TermColorDepth ,
195+ maxsize:: Tuple = displaysize (io))
196+ io_h, io_w = maxsize
197+ img_h, img_w = map (length, axes (img))
198+ enc = img_h <= io_h - 4 && 2 img_w <= io_w ? BigBlocks () : SmallBlocks ()
199+ # @sync for row in img_rows
200+ # buffer = ascii_encode(enc, colordepth, img[row, :], io_w)
201+ # @async print(io, buffer)
202+ # end
203+ str, = ascii_encode (enc, colordepth, img, io_h - 4 , io_w)
204+ for (idx, line) in enumerate (str)
205+ print (io, line)
206+ idx < length (str) && println (io)
207+ end
174208end
209+
210+ # colorant vector
211+ function ascii_display (
212+ io:: IO ,
213+ img:: AbstractVector{<:Colorant} ,
214+ colordepth:: TermColorDepth ,
215+ maxsize:: Tuple = displaysize (io))
216+ io_h, io_w = maxsize
217+ img_w = length (img)
218+ enc = 3 img_w <= io_w ? BigBlocks () : SmallBlocks ()
219+ str, = ascii_encode (enc, colordepth, img, io_w)
220+ for (idx, line) in enumerate (str)
221+ print (io, line)
222+ idx < length (str) && println (io)
223+ end
224+ end
225+
226+ ascii_display (io:: IO , img:: AbstractArray{<:Colorant} ) = ascii_display (io, img, colormode[])
0 commit comments