How to use /dev/fb0 as a console from userspace, or output text to it

Several people have answered the parts of your question dealing with the kernel and putting images (rather than text) onto the framebuffer, but so far the rest remains unaddressed. Yes, you can use the kernel virtual terminal subsystem to make a so-called framebuffer console. But there are several tools that allow you to use the framebuffer device to make user-space virtual terminals. These include:

  • zhcon (Debian) — a userspace virtual terminal geared towards handling CJK I/O far better than the kernel subsystem. Its particular strength is in handling ISO 2022 non-UTF encodings; its particular weakness is UTF encodings.
  • fbterm (Debian) — a userspace virtual terminal that has spawned several forks including jfbterm. It has a bunch of CJK input method plug-ins.
  • bogl-bterm (Debian) — a userspace virtual terminal that has spawned forks such as niterm.
  • Ali Gholami Rudi's fbpad — a minimalist userspace virtual terminal that has no dependencies on X libraries.
  • The console-terminal-emulator and console-fb-realizer tools in nosh — a userspace virtual terminal aimed at replicating Linux and FreeBSD/PC-BSD kernel virtual terminals. It too has no dependencies on X libraries.
  • kmscon — a userspace virtual terminal that is closely linked to the logind server in systemd and its notions of "seats".

Ali Gholami Rudi in particular has produced more than just a terminal emulator for framebuffer work. He also wrote a direct-to-framebuffer PDF viewer, VNC viewer, media player, and Quran reader.

A full side-by-side comparison is outwith the scope of this answer; but here are some points that are relevant to the question:

  • As noted, several of the user-space virtual terminal programs make use of X libraries for font handling, keyboard mapping, CJK input methods, and so forth. They are not X clients, but they have dependencies from X libraries. fbpad and the nosh tools by design do not make use of any X libraries.
  • The programs that use X libraries for font handling do of course use X fonts. The others make other arrangements.
    • bogl-bterm and fbpad both have their own idiosyncratic font formats. One converts BDF fonts to BOGL fonts with the bdftobogl tool; and one converts TTF to the "tinyfont" fonts that are used by fbpad with the ft2tf (Arch) tool.
    • The nosh console-fb-realizer tool uses the same "vt" fonts as the new FreeBSD 10.1 kernel virtual terminal subsystem does, and thus shares the FreeBSD font manipulation tool vtfontcvt for converting BDF fonts.
  • The programs that use X libraries use X keyboard mapping. As for the others:
    • The nosh tools have their own idiosyncratic keyboard map format, intended to provide a full ISO 9995-3 capable keyboard with the ISO "common" group 2. One converts BSD kbdmap files to this format with the console-convert-kbdmap tool. Again, these kbdmap files are the ones used with the FreeBSD/PC-BSD vt subsystem.
    • fbpad doesn't do its own keyboard mapping at all, and relies upon the presence of the kernel virtual terminal subsystem and its keyboard mapping mechanism for that.
  • There's some variance in invocation and required privileges:
    • zhcon, fbterm, bogl-bterm, fbpad, and kmscon work on the basis that the terminal emulator spawns the shell/login program on the terminal, directly, as a child process. They need superuser privileges in order to spawn login.
    • The nosh tools were designed to integrate with an existing /etc/ttys (BSD), /etc/inittab (Linux system 5 init), or other system, to which they leave the job of spawning getty/login/shell. console-fb-realizer only needs enough privileges to open the framebuffer and input event devices, which need not be superuser privileges, and to access the FIFOs and ordinary files maintained by console-terminal-emulator, which in turn doesn't need any special privileges at all.

All of these are terminal emulators of course. If you want to take the terminal emulation out and put text on the framebuffer more directly, you have some choices:

  • bogl-bterm is of course based upon Ben Pfaff's Ben's Own Graphics Library a framebuffer I/O library designed for use in system setup/rescue environments (and "for GUIs in PDAs"). You can of course write programs that use that directly.
  • For a halfway house between writing a program that makes use of a framebuffer library to do its own rendering and a program that spits out escape sequences to what it thinks is a terminal: The nosh user-space virtual terminal is modular, and splits apart into component pieces. One can simply not use console-terminal-emulator.

    console-fb-realizer uses a display file with a character cell array, like /dev/vcsa* but an ordinary file (not a character special device file) and with Unicode code points, ECMA-48 attributes, and 24-bit RGB colour. So one can run it up and just write character+attribute+colour directly into the character cell array file, letting console-fb-realizer do the font rendering to the framebuffer.

    As an aside: Observe that this is the opposite of integration with BRLTTY, which uses console-terminal-emulator but doesn't run console-fb-realizer.


To use the framebuffer as console you need the fbdev module. You may have to recompile your kernel.

You may also be interested in the DirectFB project, which is a library that makes using the framebuffer easier. There are also applications and GUI environments written for it already.


If you can cat /dev/urandom > /dev/fb0 and get random pixels on the screen, you have all you need.

In my case I needed to dump some text info. I tested this in busybox and raspi, so it might work for you. The answer might be a little bit long, since if you don't use some console you will need to print the pixels of chars yourself. Luckily someone have done the hard job, so we just need to combine it.

In busybox or in your raspi you should have a fbset binary. This might help you to find out your settings as screen dimensions.

In my embedded looks like this:

# fbset

mode "480x272-1"
    # D: 0.104 MHz, H: 0.207 kHz, V: 0.657 Hz
    geometry 480 272 480 272 16
    timings 9600000 3 3 0 32 17 11
    accel false
    rgba 5/0,6/5,5/11,0/0
endmode

The important part here is the width 480 and height 272 pixels.

As you mentioned, you can fulfill the screen with cat /dev/urandom > /dev/fb0

and you can clear it with cat /dev/zeros > /dev/fb0

Than clear your screen, we must assure you get the dimensions properly.

By chance my busybox had a fbsplash binary that get as input a .ppm file.

Correct if I am wrong, but it seems that fb0 accepts this format. Taking a look on Portable Anymap on Wikipedia, there are several "subformats"... fbsplash uses a fancy one with color, and so on... but we want to be able to just print something readable. Let's use the P1 coded in ASCII for the sake of simplicity. If we could print a vertical line, we would know our dimensions are correct. Let's try it:

A vertical line in a ppm type P1 should look like this:

P1
480 272
f 0 0 0 0 ... 0 
f 0 0 0 0 ... 0
... 
f 0 0 0 0 ... 0

So, there will be 272 lines, 959 chars wide. The documentation says it should be 1 instead of f... on busybox and raspi f was brighter.

It is important that you have no space after the 0's... This task can be a bit tedious... you better use a text editor that helps you. In vim, you can copy the first two lines, go to command mode (esc), than type the following chars:

of(esc)479a 0(esc)yy271p

Of course, I am using my dimensions, you should use yours. Cat this file to /dev/fb0, it should looks like: Vertical line screen

Ok, I am cheating... it is not just one line there... it's about 8... but when it does not work (we have wrong dimensions or we have space at the end, to have just one line is much easier).

If you got that far, we have just to print the right pixels to see as chars. Thanks to Marcel Sondaar and his repo on GitHub we won't need to draw each char.

With a small tweak one expand his simple program to print f instead of X and 0 instead of spaces, insert spaces between each char, add the header and we have a .ppm file with the letter corresponding its charcode.

One small step further and you don't get a char as input, but a line. Cat a file, pipe to your program and output to /dev/fb0 and you get a text output:

Example of text output

I test this solution also on a raspberry pi and it worked. The system tells me I don't have reputation to post more than 2 links. Until I get this, you must rely on my word :D