«

Printing images in the terminal with 9 lines of Ruby

There are many ways to bringing graphics into the text-based environment of the terminal. They range from libraries like curses to ASCII art, clever use of characters based on their visual intensity and terminal colours. This one is based on the last approach and makes it as simple as 9 lines of Ruby.

Let’s go straight to the code:

require "tco"
require "rmagick"

img = Magick::Image::read(ARGV[0]).first
img.each_pixel do |pixel, col, row|
  c = [pixel.red, pixel.green, pixel.blue].map { |v| 256 * (v / 65535.0) }
  pixel.opacity == 65535 ? print("  ") : print("  ".bg c)
  puts if col >= img.columns - 1
end

This example combines two gems: rmagick to read the images and tco to map their pixels from RGB to the extended colour palette available in most terminals. It goes through each pixel and just writes it out using tco’s string extension that sets the appropriate background colour. A pixel is approximated with two blank spaces, so the results depends on the proportions of your console font.

The conditional on line 7 will leave out all completely opaque pixels, in case your image is a PNG with transparent background.

And this is how it looks:

Pokemons in the terminal
Pokemon: Woot!

The catpix gem

I extended the above code with a few more features like automatic downsizing of the image based on the width of the terminal window, centering and adding custom background colours and turned it into a small gem called catpix.

require 'catpix'

Catpix::print_image "pokemon.png",
  :limit_x => 1.0,
  :limit_y => 0,
  :center_x => true,
  :center_y => true,
  :bg => "white",
  :bg_fill => true

Find the full description of the API at RubyDoc.

Here’s one more example with a photo of some flowers in my window, straight from my phone that was downsized to fit by catpix:

My window in the terminal
It's the 21st century. Of course it's responsive.

Is this really good for anything?

The possibilities are endless! Although the resolution of terminal screens usually isn’t that good, which is somewhat limiting. Still, here are a few ideas you might or might not want to use.

1. Rickroll people in the terminal

People won’t fall for your Rickrolls as easily nowadays. Like this guy on Reddit, you need to be increasingly more creative to pull one off. From now on, you can bring them into the terminal, where people expect them the least:

Rick Astley
Rick Astley: Never gonna give you up, never gonna let you down...

2. Access denied

Do you feel that the one-line error just isn’t enough to make it clear to users that credentials are required to perform this operation? Let Gandalf do the talking instead:

You shall not pass
Gandalf the Grey: You've got two more tries mate.

3. Wrong usage

People keep getting the command line options wrong, even through they make perfect sense? Like -d to create a file or -r to write into it. Maybe they’ll learn faster if you add this:

Facepalm
Patrick Stewart: Oh dear...

4. Something went wrong?

Indeed, some error messages aren’t easy to pass to the user. No matter how many times you ask them to back up their files, they’ll never do it. If something like this happens, take some pressure off your customer service team by sugarcoating the message a little:

Fluffy kitty
Chester: Please don't kill me!

What’s next?

I would love to see your ideas on using images in the terminal. Post them in the comments below or tweet at @radekpazdera.

You’ll find the catpix and tco gems on GitHub, both licensed under MIT. Enjoy!