Penlets.com provides resources for users and developers of the Pulse smart pen from LiveScribe.

 

Subscribe: RSS Feed - Developers Group

Tutorial

Loading and Displaying an Image

Tutorial by Robert Hanson

In this tutorial we are going to explain how to display an image in the OLED display of the Pulse pen. Thankfully, this is a simple task. If you plan on following along and coding this as we go, now is the time to break out your IDE and create a new project.

As usual, we begin with our base application. We need to import the usual Penlet, Display, and ScrollLabel classes along with a few specific to this tutorial. The standard Java InputStream and IOException classes will be utilized in reading the image from the pen so that we can display it. When we load the image, we will store it as an object of type Image, a class specific to the LiveScribe API.

package com.penlets.graphics;

import java.io.IOException;
import java.io.InputStream;

import com.livescribe.display.Display;
import com.livescribe.display.Image;
import com.livescribe.penlet.Penlet;
import com.livescribe.penlet.PenletStateChangeException;
import com.livescribe.ui.ScrollLabel;

public class ImageDemo extends Penlet
{
    private Display display;
    private ScrollLabel label;

    public void initApp () throws PenletStateChangeException
    {
        this.display = this.context.getDisplay();
        this.label = new ScrollLabel();
    }

    public void activateApp (int reason, Object[] args)
    {
        this.display.setCurrent(label);
    }

    public void deactivateApp (int reason) { }

    public void destroyApp () throws PenletStateChangeException { }
}

You may have noticed that in the activateApp() method we add our ScrollLabel() to the pen's display, but we didn't draw anything in it. So that is what we need to do next. To promote reuse we create a new method loadImage() , which takes a path argument, and call it in initApp() . Note that the path is an absolute path starting with "/images/". This is required if you want the build scripts that came with the SDK to save you some work. We will explain all of this in a minute.

With an Image object in hand we call draw() on the ScrollLabel with three arguments. The first is the image that we want displayed. The second argument is the text that we want displayed, but because we don't actually want any text displayed we pass a null value. The third argument is a flag indicating if we want the ScrollLabel to scroll the display. This can be set to true if your image is wider than the 98 pixel display width, but here we set it to false, no scrolling.

public void initApp () throws PenletStateChangeException
{
    this.display = this.context.getDisplay();
    this.label = new ScrollLabel();

    Image image = loadImage("/images/penlets.arw");
    this.label.draw(image, null, false);
}

private Image loadImage (String imagePath)
{
	return null;  // TO-DO
}

In the code listing we referenced the image "/images/penlets.arw", but we didn't tell you where that came from yet, and what an "arw" file is. In your standard project setup you will have a folder /res in your project. Under this directory you need to create an images directory, the path withing the project being /res/images/ . You need to place all of your TIFF and BMP files. When you run the deploy the application to the pen using the ant task supplied with the SDK it will convert all of these files into ARW files and place them in the JAR that is created.

Details for image development The viewable area of the Pulse display is 98 pixels wide by 18 pixels high. The image files must have an extension of "tiff" (two-"f"s) or "bmp", and they must be lower-case. All other extensions are ignored for the purpose of converting them to "arw". Images must be black-and-white, grayscale will not work. Items shown in the pen's display are typically white on a black background, your images will likely be the same unless you want a "negative" look.

There is one small but important caveat when adding images to your project. The images must be only black and white, so be sure to set this in your image editor. Most image editors will either have an explicit black/white mode, or an indexed color mode that allows you to specify a 1 bit color depth. Do not confuse this with "grayscale", which will not work.

Using Gimp Set the correct mode under Tools > Mode on the menu bar, and select "Indexed". This will launch a dialog box, in which you need to select "Use black and white (1-bit) palette". Using MS Paint Set the correct mode under Image > Attributes on the menu bar, and select "Black and white".

The last piece of the puzzle is to implement the loadImage() method. Unfortunately the code is a bit verbose due to the nature of Java's overuse of I/O exceptions as we can see below.

private Image loadImage (String imagePath)
{
    Image image = null;
    InputStream stream = getClass().getResourceAsStream(imagePath);
    try {
        image = Image.createImage(stream);
    }
    catch (IOException e) {
        e.printStackTrace();
    }
    finally {
        if (stream != null) {
            try {
                stream.close();
            }
            catch (IOException e) { }
            stream = null;
        }
    }
    return image;
}

The only code of real importance is the call to getClass().getResourceAsStream() , which returns an handle from which the image file can be read, and Image.createImage() , which reads the image data from the stream and creates the Image object. The rest of it is just to handle any exception that might be thrown, and ensure that the data stream is properly closed.

If you followed along with us you should now have an application that can be deployed to the pen, and an image should be displayed. If things didn't go right, double check that the image is set to indexed color and that it is properly named. If that doesn't help, try adding some logging to the code to help isolate the problem.

Good luck, and happy coding.

Comments (View)
blog comments powered by Disqus

Project Information

Tested for use with: JaveOne-SDK

Download the source code for this tutorial.
Download Source Code (zip)

New Tutorials

Using a Shared Library
Learn how to create a library of utils that you can share between projects.

Capturing Drawn Shapes
Learn how to capture shapes drawn by the pen and determine relationships.

Penlets 101
Never written a penlet before? Then start here with Penlets 101!

Creating a Custom Vocabulary
Learn how to create a custom vocabulary for your ICR applications.

Using Properties Files
J2ME lacks a Properties class. In this tutorial we roll our own, along with split and chomp functions.