Return to: CLA Student Services | CLA Home | U of M Home

University of Minnesota

Digital Signage Project

Minions: Kendrick Erickson, Eric Perrino

In the middle of May 2006, we were tasked with putting together a digital sign that would display useful information for parents and students as they walked through Johnston Hall during new student orientation.

In addition to general requirements for digital signage (visibility, security, reliability, and general attraction), we also needed the ability to pull content from our in-house content management system, change that content on a regular basis, and manage the physical hardware remotely.


Crimson is our in-house content management system (CMS). It has many of the features of general CMS software: a non-technical user interface for writing and maintaining websites across the unit, version management, enforcing editorial workflow, templating, and content repositories. It also has several other features that are not common among available systems such as metadata management, ownership of content by several different groups, and the ability to lend your content or borrow from other groups.

Written in PHP, content in Crimson is stored in a MySQL database but represented internally as XML. Using XML transformations, we can represent content stored in the CMS in several different formats such as XHTML, RSS feeds, or text suitable for e-mail. Because the content is initially represented as XML, converting existing content in Crimson to new content types becomes a matter of creating a new XSL stylesheet.

Mac mini and Keynote

We decided that Mac OS X and Keynote would provide an adequate display framework, given the limited amount of time we had. Making our own graphical display software was not feasible. A tangible benefit to using Keynote is that its slides and transitions are much more visually appealing when compared to PowerPoint,'s Impress, or HTML. Keynote's native format is also XML, which means we only needed to create an XSL stylesheet to convert Crimson content to a usable Keynote presentation file.

Other benefits such as OS X's BSD foundation made it easier to update slide content from Crimson and develop supporting software. We'll also be able to expand the capabilities of the display framework later on by developing custom software using the Quartz 2D engine or OpenGL directly.

For hardware, we chose a 1.66 Ghz Intel Core Duo Mac mini. Part of the requirements for this project was a small form-factor machine that could be easily tucked away and may only have access to power. We knew that given the time constraints that we would not be able to build/find a suitable Mini-ITX or Micro-ATX computer for the project and still have time to build, test, and debug the software.

Monitor and Network Setup

For the display, we're using a Sony FWD-40LX1. It's a 42" LCD screen from Sony's B2B unit. Currently, it's mounted on a Peerless flat-panel stand, but will eventually be permanently mounted in the lobby of Johnston Hall. It has a RS-232 port which allows for remote administration of the display via a null-modem cable. To utilize the port, we needed a Mac-compatible RS-232 to USB adapter to connect it to the Mac mini.

We wrote a small application called mote that can power the display on or off, change inputs, and even control the lighted "SONY" logo on the front of the display from the command line. Sony has made the communication protocol available from their website. Since the University's wireless network requires a valid user name and password to access anything beyond the validation page, we also wrote a few scripts that keeps the Mac mini's login active and informs Crimson of any changes to its IP address.

Putting it all together

Our first order of business was extending Crimson's user interface to deal with some of the new features that creating a Keynote presentation would require. Things like being able select a different presentation for each physical display, set individual slide transitions and delays, and create groups of slides to form larger presentations (i.e., be able to add single slides as well as entire presentations to a new presentation recursively) were added to an existing RSS news feed module.

Once we were able to create XML containing both the content and slide parameters from Crimson, our focus turned to reverse-engineering Keynote's presentation file format and creating an XSL stylesheet to transform Crimson's XML. Apple has provided some documentation ([1], [2], [3]) regarding the APXL presentation format, but we found it to be somewhat out of date (referencing Keynote versions 1 or 2, rather than 3). Some postings to the OpenDarwin Keynote mailing list also suggest that the iWork suite (which Keynote is a part of) is very much a moving target and its formats may change from version to version. Armed with that knowledge and running into problems building a presentation file from scratch, we decided to build an APXL theme using Keynote (using "Save theme..." from the File menu).

By default, Keynote saves its presentation XML with minimal whitespace (i.e., two or three line breaks in the entire file) and gzipped. Those behaviors can be turned off by setting two parameters from a terminal:

defaults write SaveCompressionLevel 0
defaults write FormatXML YES

The resulting uncompressed presentation file was in our case (nine master slides) around 1.4MB, a bit unwieldy for our purposes. We found that the theme could be reduced significantly by removing empty elements from the XML and some unused default styles added by Keynote. We removed empty tags by calling the following bash script which used a few Perl regular expressions (they could stand to be combined into one shell script).

The bash script, called with your theme file as an argument:


if [ ! -e $1 ];
  echo "The file you specified does not exist.";
  exit 1;

echo -ne "Searching $1.";

./ $1 | xmllint -format - > refold.xml;
diff $1 refold.xml &> /dev/null;

while [ $? -eq 1 ];

  mv refold.xml $1;
  echo -ne ".";

  ./ $1 | xmllint -format - > refold.xml;
  diff $1 refold.xml &> /dev/null;


mv refold.xml $1;
echo " stable.";

And the Perl script called from the bash script:


#./ presentation.xml | xmllint -format - > refold.xml

open(BLARG, "$ARGV[0]");
 @lines = ;

$blarg = join("", @lines);

$blarg =~ s/>s*</></g;
$blarg =~ s/>s*<(?!sf:br)([wd:s]+)/>s*</></g;
print "$blarg";

After we removed empty elements, we then removed styles in the theme's stylesheet tag dealing with charts which were not part of any slide master we created. Performing those two actions resulted in a 400KB master slide template, making our application server much happier. We moved on to making an example presentation using our newly trimmed theme so we could reverse engineer slide content templates for the XSL stylesheet (as opposed to the master slide theme which is copied verbatim into the stylesheet).

We applied the same trimming steps above to the example slide template presentation. We noticed that the content slides had IDs that would conflict with each other should we use the same slide layout twice (i.e., slides derived from the same example slide). For each content slide, we needed to ensure that the sfa:ID was unique to the slide. This took the form of another script, which searches a range of lines for sfa:IDs, making sure that they are not referenced anywhere else in the APXL presentation before renaming them to something slightly more useful in an XSL stylesheet. There were a few cases where the slides did refer to each other, but were fixed by copying the offending elements to each slide and renaming their IDs.


# ./ index.apxl 13928-14195 slide-description | xmllint -format - > newindex.apxl

open(INDEX, "$ARGV[0]");
  @indexfile = ;

($start_line, $count) = split(/D+/, $ARGV[1]);

$count -= $start_line;

@examine = splice @indexfile, $start_line, $count;

print STDERR "Examining $count lines for references in $ARGV[0]...n";

foreach $line (@examine) {

# Find sfa:ID values.
  if($line =~ /sfa:ID="([w-]+)"/) {

    $id = $1;

    push @idlist, $id;

    $lineno = 1;
    foreach $origline (@indexfile) {
      $origline =~ s/^s+//;
      $origline =~ s/s+$//;
      push @matches, "t$lineno: $origline" if($origline =~ /"$id"/);

      $lineno += $count if($lineno == ($start_line - 1));

    if(scalar(@matches) gt 0) {
      print STDERR "$id appears in:n";
      print STDERR join "n", @matches;
      print STDERR "n";

    $outreferences += scalar(@matches);
    @matches = ();



if($outreferences gt 0) {
  print STDERR "The range you specified is not self-referential.n";

$rangetext = join "n", @examine;
@alphabet = (A..Z);

foreach $id (@idlist) {

  # Create a new ID.
  $id =~ /^[A-Z]+(?![a-z])([A-Za-z]+)-d+$/;

  $newids{$id} = "$ARGV[2]-" . $1 . "-" . $alphabet[$types{$1}-1];

  $rangetext =~ s/"$id"/"$newids{$id}"/g;


# Reintegrate the spliced array back into the collective.
splice @indexfile, $start_line, 0, ($rangetext);
# Concat and print to STDOUT.
print join "n", @indexfile;

print STDERR "Replacement complete.n";

After renaming the content slide IDs, all that was left was a long process of testing and debugging the transformation from Crimson content to a valid APXL presentation. One peculiarity we did find is that if you package an image along with your APXL file, the natural width and height (sf:naturalSize) must be correct for Keynote to properly resize the image to fit an object placeholder.

When the process of creating a valid Keynote presentation using our CMS was complete, we moved toward pushing content to the Mac mini. Since we couldn't hard wire it to the network, we had to use an access point in the lobby. As mentioned above, this brought a few logistical challenges in keeping the wireless authentication valid, handling reauthentication gracefully, or registering a change in the Mac mini's IP address with the CMS after a prolonged power failure or random DHCP reassignment.

Having guaranteed that we'll be able to contact the machine, we use SSH to push a complete Keynote presentation to the running user's home directory, and then call the following bash script and AppleScript to close Keynote, enable the screen saver, and load the new presentation. We use the screen saver to hide the desktop and Keynote user interface while it is transitioning between two different presentations. Be sure to disable the "Allow Expose, Dashboard and others to use screen" option in Keynote's Slideshow preferences, otherwise the screen saver will never be overtaken by the presentation.


PID=(`ps -ax | grep Keynote | grep -v grep | cut -b 1-5`)

if [ ! -z "$PID" ]; then
  kill $PID && echo "Keynote killed"
  echo "Keynote not running"

on run argv
  tell application "Keynote"
    set presentation to item 1 of argv
    do shell script "open /System/Library/Frameworks/ScreenSaver.framework/Resources/"
    GetURL presentation
    repeat with curDoc in slideshows
      if curDoc is not equal to slideshow then
          close curDoc
        end try
      end if
    end repeat
  end tell
end run

Our last task was to secure the Mac mini itself. We disabled many of its features, including Bluetooth, the remote, and any auto-launching features when inserting a CD. We also made sure that on a power failure, the machine would immediately activate the screen saver, and then automatically load the last playing presentation. We also preformed one last check of its frame rate capabilities.

We rolled the screen out on the first day of new student orientation, and have heard various ooh's and ahh's eminating from the lobby since then.


January 23, 2007

We've been working on the software display side of things. After working with Keynote's XML and given our current lack of precise control over content positioning, we decided to move to a mixture of Quartz Composer generated contexts along with custom OpenGL contexts written in Objective C. We've also since taken the LCD off of its stand and mounted the display near the doorway. We'll probably have another write up when we've finished the second phase of development on the signage project.

We'd be happy to answer any further questions you might have about the project, you can e-mail us at

2003-2007 Regents of the University of Minnesota. All rights reserved. Trouble seeing the text? | Contact U of M | Privacy
The University of Minnesota is an equal opportunity educator and employer. Last modified on