Last active
December 21, 2015 14:29
-
-
Save heptal/6320350 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"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