Skip to content

Instantly share code, notes, and snippets.

@heptal
Last active December 21, 2015 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heptal/6320350 to your computer and use it in GitHub Desktop.
Save heptal/6320350 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"language": "Julia",
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Rendering images in the terminal over the network\n",
"\n",
"This is a simple server written in Julia that, given an image url, displays images, including animated gifs, in the terminal:\n",
"\n",
"* Waits for incoming connections\n",
"* Asks for url\n",
"* Converts image into RGB byte array with ImageMagick\n",
"* Groups and maps RGB values to terminal color space\n",
"* Divide into frames for animation\n",
"* Renders color-escaped text representation of each frame\n",
"* Pushes frames out to client for ~10 seconds\n",
"* Asks for another url\n",
"\n",
"When the server is running, connect with `telnet` or `nc`:\n",
"\n",
"`nc localhost 8888`\n",
"\n",
"It will play the gif for about 10 seconds, then ask for more urls until you quit the session"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"function getframes(image::String, width=40)\n",
" # get number of frames \n",
" num_frames = int(strip(readall(`identify $image` |> `wc -l`)))\n",
" \n",
" # get pixel data as raw rgb bytes from ImageMagick's convert tool\n",
" RGB = int(readbytes(`convert $image -resize $width -coalesce RGB:-`))\n",
"\n",
" # group raw rgb bytes into lists for each pixel: [a,b,c,a,b,c...] -> [[a,b,c][a,b,c]...]\n",
" rgb_pixels = [[RGB[i], RGB[i+1], RGB[i+2]] for i=1:3:length(RGB)]\n",
" \n",
" # map rgb pixels into terminal colorspace:\n",
" map!(p -> [sum(int(p/50).*[36,6,1])+16], rgb_pixels)\n",
" \n",
" # calculate height and group by frame\n",
" height = int(length(rgb_pixels)/width/num_frames)\n",
" frame_pixels = [rgb_pixels[int((f-1)*width*height)+1:int(f*width*height)] for f=1:num_frames]\n",
" \n",
" # construct array of rendered images using escape codes\n",
" function render(frame)\n",
" join([\"\\e[48;5;$(p[1])m $(if (i%width==0) \"\\e[0m\\n\";else \"\";end)\" for (i,p) in enumerate(frame)])\n",
" end\n",
"\n",
" return [render(frame) for frame in frame_pixels]\n",
"end"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"text": [
"# methods for generic function getframes\n",
"getframes(image::String)\n",
"getframes(image::String,width) at In[3]:3"
]
}
],
"prompt_number": 3
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# read url from client\n",
"function handle_connection(conn)\n",
" # read image url\n",
" write(conn, \"\\nEnter image url: \")\n",
" url = strip(readline(conn))\n",
" frames = getframes(url)\n",
" frame_count = length(frames)\n",
" \n",
" # plays ~10 secs of gif based on number of frames\n",
" loops = (frame_count==1 || frame_count>100) ? 1 : int(100/frame_count)\n",
" \n",
" # write frames to client\n",
" for f in 1:loops\n",
" for frame in frames\n",
" write(conn, \"\\n\"^80)\n",
" write(conn, frame)\n",
" sleep(.1)\n",
" end\n",
" end\n",
"end"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 4,
"text": [
"# methods for generic function handle_connection\n",
"handle_connection(conn) at In[4]:4"
]
}
],
"prompt_number": 4
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# start server and handle connections\n",
"@async begin\n",
" server = listen(8888)\n",
" while true\n",
" sock = accept(server)\n",
" @async while true\n",
" handle_connection(sock)\n",
" end\n",
" end\n",
"end"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 5,
"text": [
"Task"
]
}
],
"prompt_number": 5
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment