| Version: | 0.2 |
|---|---|
| Copyright: | Copyright (c) 2010 J.A. Roberts Tunney |
Run the following commands:
sudo apt-get install gcc python-imaging python-setuptools
sudo easy_install -U fabulous
If you’re not a Python programmer, you can use fabulous on the command line to accomplish certain tasks. When printing images or fancy text, the image will automatically be resized to fit inside your terminal.
Print an image:
python -m fabulous.image lolcat.png
Save image to a file: (perhaps to include in your /etc/motd)
python -m fabulous.image lolcat.png >lolcat.ansi.txt
Print fancy text:
python -m fabulous.text hello kitty
python -m fabulous.text --skew=4 --shadow hello kitty
python -m fabulous.text --help
The following information is for Python programmers who wish to use Fabulous’ developer API.
I allow you to print colorful and stylized text to your terminal. This module implements a high-level API for 4-bit and 8-bit colors.
Every wonder how this works? It’s actually really simple to do on your own so you might not even need fabulous:
>>> BOLD = '\x1b[1m'
>>> RED = '\x1b[31m'
>>> RESET = '\x1b[0m'
>>> BOLD + "~*~HELLO KITTY~*~" + RESET
'\x1b[22m~*~HELLO KITTY~*~\x1b[0m'
>>> BOLD + "~*~HELLO " + RED + "KITTY~*~" + RESET
'\x1b[22m~*~HELLO \x1b[31mKITTY~*~\x1b[0m'
If you do choose to use fabulous (and we hope you do!) here are some tips to make the most out of terminal colors.
Normally you’ll want to use the 4-bit palette (which consists of eight colors (black, red, green, yellow, blue, magenta, cyan, and white) because they work on all commonly used terminals and generally look good. These colors may change depending on your terminal theme and may also become brighter when used with bold text.
8-bit (256-color) gives you much more freedom to customize your program’s appearance. They work with the following terminals: gnome-terminal, kterm, xterm, and putty. These colors also do not change based on the terminal’s color theme. When distributing a program that uses these colors, you might want to take special care to choose colors that will be readable on both white and black backgrounds, unless of course you’re using “highlighted” color pairs which always seem to look good ;)
When printing colorized strings please remember that in some cases the user might be redirecting output to a log file. To avoid printing garbled data in these cases you can use sys.stdout.isatty() or sys.stderr.isatty() to make sure output is actually being sent to a terminal.
Colorized string-like object parent class
I helps strings with color code pretend the ANSI escape codes aren’t there until the string is actually printed (like a unicode string.) This is important when you need to determine length or slice the string.
Examples:
>>> str(red("hello"))
'\x1b[31mhello\x1b[39m'
>>> len(red("hello"))
5
>>> len(str(red("hello")))
15
>>> str(bold(red("hello")))
'\x1b[1m\x1b[31mhello\x1b[39m\x1b[22m'
>>> len(bold(red("hello")))
5
>>> len(bold("hello ", red("world")))
11
Functions (well, technically classes) that inherit from this class accept a list of arguments which may consist of:
8-bit Background Color
See ColorString256 for usage details
Strike-through Text (ANSI Code 5, Reverse 25)
Supported: kterm, xterm, Terminal.app, iTerm
Notes:
4-bit Blue Foreground (ANSI Code 34, Reverse 39)
Notes:
Bold Text (ANSI Code 1, Reverse 22)
This may also brighten 4-bit colors.
Supported: gnome-terminal, kterm, xterm, Terminal.app, iTerm, putty
Notes:
Gives you the polar opposite of your color
This isn’t guaranteed to look good, especially with brighter or high intensity colors.
For example:
>>> complement('red')
(0, 255, 76)
>>> complement((0, 100, 175))
(175, 101, 0)
I wrap the ANSI escape code around a list of numbers.
For example:
>>> esc(22, 39)
'\x1b[22;39m'
Makes Text Dimmer (ANSI Code 2, Reverse 22)
Supported: gnome-terminal, putty
8-bit Foreground Color
See ColorString256 for usage details
Swap Foreground and Background Colors (ANSI Code 7, Reverse 27)
Supported: gnome-terminal, kterm, xterm, Terminal.app, iTerm, putty
Italic Text (ANSI Code 3, Reverse 23)
Supported: none
Turns a color into an (r, g, b) tuple
The color argument may be specified in many common formats. Here are some examples:
>>> parse_color('white')
(255, 255, 255)
>>> parse_color('#ff0000')
(255, 0, 0)
>>> parse_color('#f00')
(255, 0, 0)
>>> parse_color((255, 0, 0))
(255, 0, 0)
>>> import grapefruit
>>> parse_color(grapefruit.Color((0.0, 1.0, 0.0)))
(0, 255, 0)
A passive wrapper that preserves proper length reporting
For example:
>>> len(plain("hello ", bold("kitty")))
11
Strike-through Text (ANSI Code 9, Reverse 29)
Supported: gnome-terminal
Underlined Text (ANSI Code 4, Reverse 24)
Supported: gnome-terminal, kterm, xterm, Terminal.app, iTerm, putty
Double-Underlined Text (ANSI Code 21, Reverse 24)
Supported: None
Notes:
I provide utilities for making your logs look fabulous.
Standard Python logging Handler for Transient Console Logging
Logging transiently means that verbose logging messages like DEBUG will only appear on the last line of your terminal for a short period of time and important messages like WARNING will scroll like normal text.
This allows you to log lots of messages without the important stuff getting drowned out.
This module integrates with the standard Python logging module.
Shortcut for setting up transient logging
I am a replica of logging.basicConfig which installs a transient logging handler to stderr.
I let you print TrueType text to your terminal. The easiest way to get started with me is by running:
jart@compy:~$ python -m fabulous.text --help
To make things simple, Fabulous comes with my favorite serif, non-serif, and monospace fonts:
IndUni-H-Bold: Open Source Helvetica Bold clone (sans-serif)
This is the real deal and not some cheap ripoff like Verdana. IndUni-H-Bold is the default because not only does it look great, but also renders perfectly. and is also used for the Fabulous logo. Commonly found on stret signs.
This font is licensed under the GPL. If you’re developing proprietary software you might want to ask its author or a lawyer if Fabulous’ use of IndUni-H would be considered a “GPL Barrier.”
cmr10: Computer Modern (serif)
Donald Knuth wrote 23,000 lines for the sole purpose of bestowing this jewel upon the world. This font is commonly seen in scholarly papers.
DejaVuSansMono: DejaVu Sans Mono (formerly Bitstream Vera Sans Mono)
At point size 8, this is my favorite programming/terminal font.
For other fonts, I’ll try my best to figure out where your font files are stored. If I have trouble finding your font, try using an absolute path with the extension. You could also try putting the font in your ~/.fonts folder and running fc-cache -fv ~/.fonts.
I get raised when the font-searching hueristics fail
This class extends the standard ValueError exception so you don’t have to import me if you don’t want to.
Renders TrueType Text to Terminal
I’m a sub-class of fabulous.image.Image. My job is limited to simply getting things ready. I do this by:
For example:
>>> assert Text("Fabulous", shadow=True, skew=5)
>>> txt = Text("lorem ipsum", font="IndUni-H-Bold")
>>> len(str(txt)) > 0
True
>>> txt = Text("lorem ipsum", font="cmr10")
>>> len(str(txt)) > 0
True
>>> txt = Text("lorem ipsum", font="DejaVuSansMono")
>>> len(str(txt)) > 0
True
| Parameters: |
|
|---|
Returns a list of all font files we could find
Returned as a list of dir/files tuples:
get_font_files() -> [('/some/dir', ['font1.ttf', ...]), ...]
For example:
>>> fabfonts = os.path.join(os.path.dirname(__file__), 'fonts')
>>> 'IndUni-H-Bold.ttf' in get_font_files()[fabfontdir]
True
>>> 'DejaVuSansMono.ttf' in get_font_files()[fabfontdir]
True
>>> 'cmr10.ttf' in get_font_files()[fabfontdir]
True
>>> assert len(get_font_files()) > 0
>>> for dirname, filename in get_font_files():
... assert os.path.exists(os.path.join(dirname, filename))
...
Sloppy way to turn font names into absolute filenames
This isn’t intended to be a proper font lookup tool but rather a dirty tool to not have to specify the absolute filename every time.
For example:
>>> path = resolve_font('IndUni-H-Bold')
>>> fontdir = os.path.join(os.path.dirname(__file__), 'fonts')
>>> indunih_path = os.path.join(fontdir, 'IndUni-H-Bold.ttf')
>>> assert path == indunih_path
This isn’t case-sensitive:
>>> assert resolve_font('induni-h') == indunih_path
Raises FontNotFound on failure:
>>> resolve_font('blahahaha')
Traceback (most recent call last):
...
FontNotFound: Can't find 'blahahaha' :'( Try adding it to ~/.fonts
Module for printing images to the terminal.
Printing image files to a terminal
I use PIL to turn your image file into a bitmap, resize it so it’ll fit inside your terminal, and implement methods so I can behave like a string or iterable.
When resizing, I’ll assume that a single character on the terminal display is one pixel wide and two pixels tall. For most fonts this is the best way to preserve the aspect ratio of your image.
All colors are are quantized by fabulous.xterm256 to the 256 colors supported by modern terminals. When quantizing semi-transparant pixels (common in text or PNG files) I’ll ask TerminalInfo for the background color I should use to solidify the color. Fully transparent pixels will be rendered as a blank space without color so we don’t need to mix in a background color.
I also put a lot of work into optimizing the output line-by-line so it needs as few ANSI escape sequences as possible. If your terminal is kinda slow, you’re gonna want to buy me a drink ;) You can use DebugImage to visualize these optimizations.
The generated output will only include spaces with different background colors. In the future routines will be provided to overlay text on top of these images.
Converts color codes into optimized text
This optimizer works by merging adjacent colors so we don’t have to repeat the same escape codes for each pixel. There is no loss of information.
| Parameter: | colors – Iterable yielding an xterm color code for each |
|---|
pixel, None to indicate a transparent pixel, or 'EOL' to indicate th end of a line.
| Returns: | Yields lines of optimized text. |
|---|
Resizes image to fit inside terminal
Called by the constructor automatically.
This module provides tools for probing terminal settings and configuring Fabulous.
Quick and easy access to some terminal information
I’ll tell you the terminal width/height and it’s background color.
You don’t need to use me directly. Just access the global term instance:
>>> assert term.width > 0
>>> assert term.height > 0
It’s important to know the background color when rendering PNG images with semi-transparency. Because there’s no way to detect this, black will be the default:
>>> term.bgcolor
(0.0, 0.0, 0.0, 1.0)
>>> import grapefruit
>>> isinstance(term.bgcolor, grapefruit.Color)
True
If you use a white terminal, you’ll need to manually change this:
>>> term.bgcolor = 'white'
>>> term.bgcolor
(1.0, 1.0, 1.0, 1.0)
>>> term.bgcolor = grapefruit.Color.NewFromRgb(0.0, 0.0, 0.0, 1.0)
>>> term.bgcolor
(0.0, 0.0, 0.0, 1.0)
Returns terminal dimensions
Don’t save this information for long periods of time because the user might resize their terminal.
| Returns: | Returns (width, height). If there’s no terminal to be found, we’ll just return (79, 40). |
|---|
Returns file descriptor number of terminal
This will look at all three standard i/o file descriptors and return whichever one is actually a TTY in case you’re redirecting i/o through pipes.
A very simple memoize decorator to optimize pure-ish functions
Don’t use this unless you’ve examined the code and see the potential risks.
Check for PIL library, printing friendly error if not found
We need PIL for the fabulous.text and fabulous.image modules to work. Because PIL can be very tricky to install, it’s not listed in the setup.py requirements list.
Not everyone is going to have PIL installed so it’s best that we offer as much help as possible so they don’t have to suffer like I have in the past :’(
Implements Support for the 256 colors supported by xterm as well as quantizing 24-bit RGB color to xterm color ids.
This module does not provide a high level API but rather a means of turning RGB tuples into an ANSI color code.
Color quantization is very very slow so when this module is loaded, it’ll attempt to automatically compile a speedup module using gcc. A logging message will be emitted if it fails and we’ll fallback on the Python code.
When this module is loaded it’ll automatically try to load some optimized C code unless the environment variable FABULOUS_NO_SPEEDUP is set.
Tries to compile/link the C version of this module
Like it really makes a huge difference. With a little bit of luck this should just work for you.
You need:
I implement functions to satisfy your darker side.
Gothic Poetry Generator
Uses Python generators to yield eternal angst.
When you need to generate random verbiage to test your code or typographic design, let’s face it... Lorem Ipsum and “the quick brown fox” are old and boring!
What you need is something with flavor, the kind of thing a depressed teenager with a lot of black makeup would write.
Completely pointless terminal renderer of rotating cube
Uses a faux 2D rendering technique to create what appears to be a wireframe 3d cube.
This doesn’t use the curses library, but rather prints entire frames sized to fill the entire terminal display.
Canvas object for drawing a frame to be printed
Rotating cube program
How it works:
- Create two imaginary ellipses
- Sized to fit in the top third and bottom third of screen
- Create four imaginary points on each ellipse
- Make those points the top and bottom corners of your cube
- Connect the lines and render
- Rotate the points on the ellipses and repeat