After I got rid of most boot messages, I wanted to display a splash screen.

Syslinux can show a splash screen but it doesn't stay around until X starts. I could have taken the easy route and put Usplash or Splashy into Tiny Core Linux on my USB stick.

But no! I took another route. I used Zgv. Zgv is an SVGAlib-based image viewer, so it runs on the Linux console. Feed it an image early on in the Tiny Core init.d scripts and voila, a splash screen!


It wasn't all plain sailing though. The first thing was to get SVGAlib compiling on a modern Linux distribution (let's assume Ubuntu here). Of course, I had to make some patches. There wasn't much to fix:

  • Only build static libraries. I didn't need to use SVGAlib with anything else on Tiny Core Linux.

  • Don't bother with assembly optimizations.

  • Various type, macro and syntax changes - probably due to a tightening-up of compiler rules.


I also patched Zgv - not to fix compile errors, but to:

  • Support LSS16 image files. LSS16 is an arbitrary format which Syslinux supports for displaying splash screens. I wanted to use the same files in Syslinux later on if I wanted to.

    I implemented the main logic for loading LSS16 images as separate source and header files.

  • Remove support for JPEG, PNG and TIFF images in Zgv. I didn't need these libraries so it was pointless to add them to Tiny Core Linux and load them from the USB stick.

  • Add support for 640 x 480 x 16 colours planar VGA mode.

    SVGALib's vga_getmodeinfo returns 0 bytes per pixel for planar VGA modes. For my graphics adapter it was only returning one 640 x 480 mode, and it was planar.

    Since I was only going to be using this mode for 640 x 480, I made a hack and changed only the graphics mode selection algorithm. From the patch:

    +  if(bpp==4) bytepp=0; else bytepp=(bpp+7)/8;
  • Don't dither LSS16 images to 16 colours! In 16 colour mode, Zgv dithers images, even if they have 16 colours or less. It defines its own palette and maps the image onto it. Obviously, it's better to use the 16 colours in the image itself.

  • Fix a SEGV, caused by not setting a global (image_palette).

Making LSS16 files

I created my splash screen in Inkscape as a vector graphic, splash.svg. Here's the script I used for creating a LSS16 file, splash.rle, from it:

inkscape -e splash-pic.png -w 300 -h 300 -b '#000000' splash.svg
convert splash-pic.png \
        -bordercolor '#000000' \
        -border 170x40 \
        -gravity north \
        -background '#000000' \
        -extend 640x480 \
        -gravity south \
        -fill '#ffffff' \
        -pointsize 30 \
        -annotate +0+50 'Almost there, just a few moments...' \
convert splash.png -colors 16 splash.ppm
ppmtolss16 '#000000=0' '#ffffff=7' < splash.ppm > splash.rle

In other words:

  1. Export the file from Inkscape, 300 x 300 on black background.

  2. Use ImageMagick to:

    1. Add a border around the image - 40px of space at the top and extending the width to 640px by adding 170px either side.
    2. Extend the height of the image to 480px.
    3. Add a message 50px from the bottom of the image.
  3. Use ImageMagick to convert the image to 16 color PPM format.

  4. Use ppmtolss16 to convert the PPM image to LSS16 format. ppmtolss16 comes with Syslinux. The .rle extension because LSS16 uses run-length encoding compression.

    Note how I set the background colour to index 0 and the foreground color to index 7. Zgv doesn't treat these indices as special, but Syslinux sets the console's text foreground and background to the colours at these indices.

Displaying the Splash Screen in Tiny Core

Finally, we need to call Zgv to display the image while Tiny Core Linux is loading. I do this by putting the following at the start of /etc/init.d/tc-config:

[ -f /proc/cmdline ] || /bin/mount /proc
if grep -q quiet /proc/cmdline
  echo -en "\033[2J\033[1;1H"
  exec > /dev/null
  if ! ps -o comm | grep zgv
    sh -c "zgv -p -m \"640 480 4\" --viewer-16col-colour /usr/share/splash.rle &"

This clears the screen, homes the cursor, redirects output from the script to /dev/null and then runs Zgv. -p hides the loading progress bar. -m selects the display mode to 640 x 480 x 4 bits per pixel. --viewer-16col-colour seems a bit superfluous given that it knows there are 4 bits per pixel, but Zgv needs it anyway.

To stop Zgv before X loads, I put the following at the end of /etc/init.d/tc-config:

if grep -q quiet /proc/cmdline
  sudo killall -INT zgv
  while ps -o comm | grep zgv; do sleep 1; done

Note I only run Zgv if quiet was passed as a kernel boot parameter.

You might want to remaster your Tiny Core image to put these changes in.

blog comments powered by Disqus