JuliaImages / DitherPunk.jl

Dithering algorithms in Julia.
MIT License
60 stars 3 forks source link

Support dithering with ASCII characters #61

Open adrhill opened 2 years ago

adrhill commented 2 years ago

I've taken a brief look into how this is typically done. Usually people define a ramp of ASCII characters to approximate a gray-scale color ramp. In this sense, we can already dither with ASCII characters using the underlying IndirectArray:

using DitherPunk, TestImages, ImageCore, ImageTransformations

img = testimage("fabio_gray_256")
img = imresize(img, ratio=(1//6, 1//3))

ascii_ramp = split(" .:-=+*#%@", "")
cs = Gray.(range(0, 1, length=10)) # match length of ramp

d = dither(img, FloydSteinberg(), cs)
mat = ascii_ramp[d.index]

for r in eachrow(mat)
    println(join(r))
end

which prints the following (make sure your browser window is wide enough):

----::--------::-:-:-::-::-:--------:--=-=-=---:-----:::::-:-:--:-::::::.::.::.:::.::.
-=--::---------::::::::::::------------=--::-=-+=-----=--::-:-:-:-:::::.:.:.::.:.:.:.:
-=--::--------::::::::::::::----------=+++=+=+=-:---:-:-:--::--:-:::-:.:.:.:.:.:.:.:..
=---::-------:::::::::::::::-:-:--:=+==+=-=++++==+==+==--::::::-:-:::.:...:.:.:.:.:.:.
--=-::-:-------::::::::::::-:::--=====##*+======+=-----::-::.:::::::::..:.:.:.:.:.:.:.
-=--::--------:-::::::::-:-:-++=*+*%#*#*****++++++=-=-::-::.::.:-:::::.....:.:.:.:.:.:
-=--:::-----:--:-:-:--:::--=++***#*+++++++++*+=---=-:=:==:-:.:-:::.::.:.:.:.:.:.:.:.:.
=---::-:------:-::::::::-=+++*#*+=--:::-::::--=+==--=-:=-+:::-:::::.:::..:.:.:.:.:.:.:
----::::-:::.:::-:--:-:-=-***--:-:--=+====-::.-:++++-:.:::-:::--::.::::::.:.:.:.:.:..:
-=--::::::::::::::::::--=+=::::--+:.-----:-=-::.:::-::...::::::--=--:-:.:.:.::.:.:.:.:
--=::::::---:-::-:::-:=+=+=:=---::----::::=-:.+..::::.:::.:::::::=--:::::.::.:.:.:.:.:
-=---:::----:-::::-::=++=-=:::.:::==::----:-:-:::.::.::---------:..::::::::..:.:.:::.:
=-=-::::-:=--::-::::=+-=-::::.::-*#*#*+#**#*++**---:-=***+*++=+==:.:::-::::::.:.:..:..
-==-::::------:::---*++-::--:::-=*######%%##%%###########*+++=++=-::.::::::::.::.::.::
------::--=--:-:--=+*+=-=---:-:--+###%##%#%%#%%%%%##%#%#**+++=+=-:::::-:---::::.:.:.:.
-=---:::--==-----+*++-::-:::::::==*###%%#%##%##%#%%######***+++=-.:::-:-::::::-::.:.:.
=-----::--==--=+***+-:-=::.:-:-::=+*######%########%####***+++=+-:..:---==+--:::.:.:.:
--=:-:::---==*+#+#+=-++=:::-:...*+*########%%#%%#%#%%####***++===-.:.:---=----:.:.::..
=-----::--=++=#***-+++=:.:.....-+****#%%%%%#%#%#%#%##%#%#**++----=....:---=-::::::.::.
-=---:::-==+-*+**++*+=-::..:..:=**+++------==+=*#####+-::::::--===:.:..:..::-::::::.:.
-=---::---=+*****+*+*-:::.:....+****+=+#--:+-=-=*##*==++*:-*+--=+===+:..:::-::::-::.:.
=-=---::-=++*++*+**=+=-::::..::=*#%##%****#####+*##*++*+*#**+**+++-++=.:.:::--::-::..:
-=-:-:::-*+#+****#+*=+--::::..:=+*#%%%%%@%%%##*+*##+=++**###****+==#*+...:--:-==::::..
-----::---#*++****+++===-:--:..-+*##%%%%%#%#%#***##*==+**#*##**++=-**-..:::=--=+:-:::.
-=-:--::-=*++*****=++=++-=---:.:=+*##%#%%%#%##***##*+==******++++-=+:...::--+=+---::.:
----:::-=+*+**#**++=+*++-=-....:-=+**######%##***#**+==*****+++==-=...:.:.::=++--:::..
=----::===*+*****+=+*===+=-....::+=+**#*######***%%*+=+++*++++====-....:.:::==-==::::.
-=--:-:-=+#***#*++++-++=+=:.....-=++**#*###*%##=+**++=+*++*+++=====....::.::-----::::.
------:-*#*#*#+*++==*=++=::....::+++++**#**####**+==+++=+==++=====-......:::-:--:::.::
----===**+*+*#***++**+=:::::....-=*++*+*#*********=*+++==+=++==+==:......:::--:-::::.:
=----*+***++******++=---::::.....==*+*+*#*++=--=-=+----=++++==+==-=:.......::-:--:::-:
::=*++=*=++**#***+*==-=:-:::......=++*++***#*****++++++=+++=+===-===--......::-:-:::-:
-=*====++**##**#*+==-+-::::....... .=+++*#****++++==+==+==+===-++====++-=......::.:.::
--*==-=+**#**#**+=====-:-.:..........-=+=**########****+++===-+++====+++*++=..........
:=*+*+**%#####+=+=+++-:-::..:.........-=-=+***####%##**++==-++++==+++=+++++++=......:.
=+++**###*##++=#=+++-:---:.::.:.......:-+=+=+++**++++++=-=++++++++=++++++++++++....:..
**+*#%#***+**+*=*+=::.---.:.::.::......-==+====--------+==++++++++++++=+=++++=++:...::
+###***++*#**+*+---..:::..:::.::......::-+=++++==+****+++*++**+++++*++++++=+======:..:
#***+***##*+**==:-::::.::..:........:.---++++***#********+******++*+*+*++++=+++++++.:.
*****#***+**++-=-:-:::::...::.::.......--=+++++**********#####*+++*******+**+*+++===:.
*%*********+=*-::::::::.:.:.:......:..:::-+**+*+***#***#*#####*+=+#****+**+*++*+*++===
*=#**#***++---:::.:.:.:::....::.:....::.:+*****+*+***#*#*#*#*#++***+++++++*+**+*+*+**+
***#****++=--:=::::.:.:.::..:...:.....:--=********++*****######**+*+*++**+*++**+******

This might be worth adding to the docs.

However, when #60 is implemented, we can go one step further and use font rasterizers like FreeTypeAbstraction.jl to generate tiles from characters, average their color and return ASCII. This would also open up the possibility of supporting colored letters on colored background.