Hello, my name is Blanton Black, and I wrote an application called Gazr, which is an alternative browser for the Flickr photo sharing site.
In short, my goal for this project was to create a flowing visual experience.
In order to provide a fluid view of photos, I implemented my own widget. Similar in concept to Apple’s Cover Flow, my OpenGL based animation presents a continuous stream of photos. This allows a user to visually scan a potentially large photoset.
In terms of speed, it is not difficult to improve upon a browser based paged interface. Clicking through page after page of photos is time consuming. Gazr’s approaches is to download and cache thumbnails in the background, presenting them in a continuous animated interface. No more click and wait.
In terms of platform, the flickr browser is written in Java. However, the user interface is not based on Swing. Instead, Gazr uses bindings for the cross platform Qt application framework. In addition, 3D animation is provided by OpenGL. Both of these libraries sit on top of platform specific dynamic libraries. On the positive side, this gives the application a performance boost by providing hardware graphics acceleration. Unfortunately, this requires the distribution of platform specific libraries, but I will revisit this topic later.
Flickr provides various ways of browsing, ranging from searches, to groups, to tags. Nevertheless, this prototype focuses on Flickr users. The application starts by fetching a given user’s information. Then, Gazr will fetch the collection hierarchy, and display the information in a tree widget for browsing. It looks something like this.
And here is the interface. Collections and sets are on the upper left. Meanwhile, the view on the lower left provides the flowing animation of an individual photoset. Finally, clicking on a photo within the animation will load a larger version of the image on the right.
The scrolling animation uses a few tricks.
First there is the curve. The curve maps a scalar from 0 to 1 to a point in 3-dimensional space.
In this way, rendering a photo in 3D space is as simple as determining its position from 0 to 1, mapping it along the curve, and drawing it at its 3-dimensional position.
The animation’s velocity is controlled by the mouse. For example, you can click, drag, and release, to start the scrolling animation. This allows for a rapid or slow paced view of each photo. In addition, the user can slow down the process by clicking and holding, which decreases the velocity.
Yet another feature is the sound effect when the image is first dragged, which sounds like....
Next, I will cover some design details.
Here, we have the widget design. The user interface was developed with 2 major classes, plus one helper Vector class. That is slightly misleading, because the application framework is based on a MVC framework, plus a significant amount of code reuse.
Although I did not extend any of my own classes, there is a heavy amount of code reuse inherent in the Qt application framework.
For example, I could have written my own image display widget to provide scaling. However, the WebKit module already does this for me. Consequently, the large image display is really nothing more than a webkit browser window, with a black background, that is instructed to load images from the web.
Another example of the code reuse involves the MVC framework. For example, the main window renders collections and sets with a QTreeView. I considered creating my own model based upon the abstract interface, but soon discovered that this does not translate well to Java, due to its lack of pointers. So, instead of subclassing the abstract model, i created an instance of QStandardItemModel, which already implements the abstract class. Then, I use data from the flickr api to populate this model with titles, descriptions, and icons.
Using Qt’s reusable components significantly cuts back on the overall application complexity, allowing me to focus on data logic, which is contained within the flickr package.
Most of the application’s processing is contained here. Basically, the flickr package is a wrapper around xml services provided by flickr. It is not a 1 to 1 mapping with the Flickr REST API. Nevertheless, I would like to highlight the signals and slots pattern. For example, once the Flickr class resolves a user, the user class then provides a number of methods that will go out to the network. For each network operation, the user has a corresponding slot to received feedback from the network operations. The user object also has signals of its own, so that it may emit responses back to the above application.
One of the key requirements for a fluid experience is having an interface that never blocks. The Qt framework accomplishes this by providing an asynchronous networking library. In the sequence diagram above, notice that all of the messages are asynchronous. Nothing blocks. For example, when the application wants to show a photoset, it will call getPublicPhotos. The User object, in turn, asks the QNetwork library to fetch the data for a given url. Some time in the future, the network response replies with either an error or finished signal. In the case of a finished signal, the User will catch this in a signal slot, parse the xml data, and then emit its own signal to the main window, informing it that the photoset data is ready. At this point, the MainWindow can update the widgets with the pre-processed data. The entire application uses these non-blocking techniques.
Performance was a major design consideration. In order to keep the experience as fast as possible, Gazr uses two levels of caching.
First, the network system has a dedicated caching mechanism. By default, all network requests are fetched and stored to disk. For instance, downloading a full image can take several seconds. However, if the image is brought up again, the network subsystem can automatically load the image from disk.
Compared to a network request, loading an image from the disk is fast. However, loading from memory is even faster. Once again, Qt has a class specifically for this purpose. The pixmap cache stores a limited amount of data, such that going back and forth between two recent images is virtually instantaneous.
Both Jambi and the java opengl bindings consist of non-Java platform specific code. This complicates distribution by requiring the addition of platform specific jar files. For Jambi, this was straightforward. However, finding the right bindings for the opengl bindings proved difficult. In short, their website is a mess, such that finding the right pre-compiled libraries involved copious amounts of trial and error.
To get around this problem, I explored Java Web Start. In fact, you can try Gazr by navigating to the above URL. The provided XML file contains the necessary data to bootstrap the program over the web, without taking the time to perform an actual install. Most importantly, however, Web Start will download the appropriate support libraries for the specific system on which the program will run. In theory, as long as Java and Web Start are installed, Gazr should just work on most systems.
Finally, I have prepared a video demonstration. I would like to point out, however, that the screen capture program used a rather low frame rate. The actual program’s animation is significantly smoother.