Dr. Dobb's Journal
Update: Intel is no longer giving these libraries away for free - be prepared to fork out real money for this code. Does this render the information in this article useless? I don't know, add your comments below!
In this article I take a look at Intel's Win32 JPEG Library, and present a slide-show app I built to test it. I found it quite easy to render JPEG images using this library, and I think the demo code I provide will provide you with a good starting point for your own work. I'll also perform a short comparison of Intel's library against Microsoft's standard IPicture component, both in terms of performance and ease of use.
Intel's Performance Libraries
Not too many people are aware of the fact that Intel dedicates a substantial amount of energy to its software products. As you would expect, most of the software Intel creates is designed to pull through more hardware sales, not to generate revenue of its own. One good example of this is Intel's JPG Library.
Intel added the MMX instruction sets to their CPU chips starting with their
486 Pentium MMX processors. The MMX instructions are designed to speed up certain operations needed in multimedia applications. One of these is the Inverse Discrete Cosine Transform (IDCT), which is used to when decoding JPEG images.
Developers typically can't take advantage of extended instruction sets in products designed for a widespread market, because they can't count on their target machines having the correct extensions. Companies like Intel or AMD can still leverage their proprietary processor features by providing device drivers, browser plugins, or other components, but this doesn't completely satisfy their desire for market penetration.
For example, my sample slide-show program doesn't use operating system components to decode JPEG files, meaning I can't take advantage of the MMX instruction set without writing specific routines to detect the target processor type, then branch to one of two different decoders depending on the result.
Intel correctly figures that they can convince me to offer support for their hardware if they dish it up on a silver platter, and that's exactly what they do with their series of Performance Libraries. At this time, Intel is offering the following roster of libraries:
Intel Integrated Performance Primitives - an abstraction layer for multimedia processing.
Intel Math Kernel Library - linear algebra and FFT routines.
Intel Recognition Primitives Library - code for speech and character recognition software.
Intel Signal Processing Library - access to Intel CPU functionality similar to that used in Digital Signal Processors.
Intel Image Processing Library - image manipulation functions, including filtering, thresholding, morphing, FFT, and DCT.
Intel JPEG Library - encoding and decoding of JPEG images.
All of these libraries have processor specific routines for various families of Intel CPUs, and all have generic code that will also run on any standard Intel Architecture CPU.
What's the Catch
In a clear case of enlightened self-interest, Intel is making these libraries freely available to software developers. You will have to go through a licensing procedure to in order to redistribute the libraries with your products, but as far as I can tell there aren't any circumstances under which Intel will require payments or royalties.
Support is another matter, as you might expect. Intel's web site has FAQ material, known issues, and so on. Talking to a person will require subscription to a premium support service.
Where to go
You can find Intel's JPEG library on their Web site, www.intel.com, by following the links to
Products/Software/Performance Libraries. At the time this article is going to press, the direct link is at:
The library has many of the niceties that you would expect from Intel. Figure 1 shows one of the first screens from the professional installation program, which naturally allows for a full uninstall as well.
Figure 1 - Installing the Library
As you install the library, you'll also see that it includes examples, white papers, documentation, and support for C/C++, Visual Basic, and Delphi.
Using the Library - an Example
I originally stumbled upon Intel's library while searching for a solution to a pressing problem. My friend Darrick Deel and I were intent on supplying some entertainment to a company shindig at Cisco's development offices in Dallas. We were going to act as roving digital photographers, snapping candid shots of our coworkers as they engaged in atypical mirth and merriment.
Our goal was to use a notebook PC and a projector to randomly display shots of partygoers during the event. What we needed was a slideshow
program that would randomly display JPEG photos from a directory tree. We were hoping for a program that would run in unattended mode, but would still be able to periodically scan the photo archive looking for new shots. This would allow Darrick and I to add photos across the network without having to break into the show.
Slideshow software is easy to come by. As Figure 2 shows, a simple search on a popular download site turns up literally hundreds of possibilities. A surprisingly large percentage of this software is either free or quite cheap.
Figure 2- Searching for Slide Show Software
Despite the bountiful selection of software, Darrick and I were suffering from the Goldilocks syndrome - nothing we tried out was just right. Following in an age-old tradition among programmers, I decided to reinvent the wheel. Having recently downloaded Intel's JPEG Library, I knew I had just the tool I needed to make a quick
job of it.
Using Intel's Library
The library ships from Intel with a pretty decent manual in PDF format, and a nicely fleshed out sample program called JPGView. The manual is full of code fragments that do a good job of illustrating the various features of the library. After reading the manual and examining the sample code, the process of displaying a JPEG image on the screen looked pretty straightforward:
Initialize the library.
Read the JPEG file header to get the basic image information, including size and color space.
Set up the various members of the data structure that will hold a Win32 Device Independent Bitmap (DIB.)
Read the JPEG image data into the DIB.
Display the DIB.
The first four steps here are accomplished in a single routine I wrote called CreateImage. This function takes an input file name as a parameter and returns a pointer to a JPEG_CORE_PROPERTIES structure, which is where the Intel library stores all its information.
The final step is done in the WM_PAINT handler for the program's WndProc. Since the first four steps create a fully functional DIB, all the WM_PAINT handler has to do is set up some parameters and draw the DIB to the output device context.
I put this knowledge together in an imaginatively named program called SlideShow. Although the code is built using Visual C++, it doesn't use MFC, so you should have good luck using the program with Brand X C++ compilers.
SlideShow starts off as a console program that takes a directory name as a command line argument. That directory name should be the root directory of your album of JPEG files. Slideshow then creates a full-screen main window, starts a five second timer, and proceeds to process the message loop.
Other than a little bit of glue code, the message handling routine for this program really only cares about two messages: WM_PAINT and WM_TIMER.
The main window of SlideShow gets a timer tick once every five seconds. It has three main jobs to do when this timer tick occurs:
If needed, reload the list of pictures to display.
Destroy the current picture object.
Create a new picture object.
SlideShow keeps a list of all the pictures it finds in the JPEG directory in a C++ vector named WindowData::picture_names. It also keeps an index of the next picture to decode in WindowData::current_picture. As soon as the timer handler is entered, it checks to see if the current_picture value is at or past the end of the picture_names vector. If it is, the current contents of the vector are erased and the picture directories are scanned for a new list of picture names. (Note that this happens naturally the first time the WM_TIMER tick is processed.) The picture names are randomized so the sequences aren't repeated each time the program is executed.
After potential maintenance of the image name list, it's a simple matter to delete the current image and create a new one. CreateImage,
described a bit earlier in this article, does all the processing needed to load the JPEG image into a Device Independent Bitmap. This new image is ready to be painted on the screen, and I force that to happen by calling the Windows API function, InvalidateRect(). This forces a WM_PAINT message to be sent to the main window.
The WM_PAINT message means it is time to paint the JPEG image onto the screen. I've characterized this as being an easy task since the image is now in a DIB, and examination of the WM_PAINT handler in Listing 1 bears this out.
The actual painting is done via a call to Windows API function StretchDIBits(). This routine not only copies the image to the screen, but scales it as well. There are a dozen or so lines of code that set up the call to this function. I scale the image so that it fills as much of the screen as possible without clipping any bits, filling any unused space with the desktop background color.
Figure 3 shows what this looks like on the screen of a PC. The program quietly paints a new random image on the screen every five seconds. The machine shown here is a modified I-opener, which runs Windows 98 and has full network access. With no cooling fan to create ambient noise, the I-opener is an ideal desktop photo album.
Figure 3 - The Slideshow in Action
Making Windows into Objects
If you are used to using MFC for all of your C++ projects under Windows, you might find this to-the-API program a bit different. One thing I did to try and make it a little more structured is to encapsulate the Window data in a C struct, which could just as easily be a class.
When the program first starts, I create a WindowData object, which contains all the information regarding the currently selected
picture, the list of file names, and so on. When the window is created, I stuff a pointer to this object into the GWL_USERDATA DWORD owned by the window. From that point on, every time I enter the WndProc I can get a pointer to the structure, eliminating the need for global variables.
Integrating with Visual Studio
The download package for this program contains a project file, but you may need to do a bit of modification after you install Intel's JPG Library.
First of all, the SlideShow.cpp file includes Intel's header file, ijl.h, as shown in this section of code from the source file:
using namespace std;
Naturally, this file won't be in your normal include path. I take care of this by going to the Project|Settings dialog in Visual C++, selecting the C/C++ pane, then the Preprocessor category. You should then enter Intel's header directory in the Additional Include Directories edit box. If you take the default installation, your dialog will look like Figure 4.
Figure 4 - Configuring the Include Path
The project file I built for SlideShow includes the static library, ijl5l.lib. If you took the default path for Intel's install, you don't need to make any changes whatsoever. Figure 5 shows the path that is defined in the current project.
If you would like to use Intel's DLL instead of the static library, or if you chose a different install path, you'll need to delete the current library from the project. After deleting, use menu option Project|Add to Project|Files to add the correct library.
Figure 5 - The correct properties for the Intel Library in Visual Studio
Intel vs. Microsoft
There are any number of reasons you might choose to use Intel's library to display JPEG images. But what about Microsoft's solution? Does the standard distribution of Windows come with components that can perform just as well?
As it happens, Microsoft ships with a standard COM object called IPicture that shares much of the functionality with Intel's library. It not only handles JPEG files, but works with GIF, BMP, and other formats as well.
Ease of use
To get a handle on its ease of use, I reworked my SlideShow.cpp to use an all Micrsoft solution. The resulting program, SlideShowMS.cpp (available for download) shares the same structure, and is probably nearly identical in terms of structure and complexity. The major changes are:
Microsoft's image data is stored in the IPicture component, Intel's is in a JPEG_CORE_PROPERTIES structure.
Reading the file data requires two steps and a bit of coding for Intel. Microsoft makes reading easier with the simple OleLoadPicture function, but loses points for not reading from standard files. Setting up the IStream object Microsoft needs throws away any advantage they have in this area.
I used a standard Windows GDI function to draw the Intel object to the screen. IPicture has a Render method that is somewhat easier to use and requires less setup.
After examining these points, I think you'll agree that there's no clear winner here. If all that matters to you is how much work you have to perform to solve your imaging problems, you can stick with your personal preference and not worry about making a big mistake.
When it comes to decoding JPEG files and rendering them to the screen, Intel's library stole the show. I ran the Slideshow program through a batch of 20 JPEG files that were mostly 1600x1200 pixels in size. My non-scientific test game the following performance results:
|CPU||Intel Batch Time||Microsoft Test Time|
|AMD K6-450||13 seconds||28 seconds|
|WinChip 200||50 seconds||130 seconds|
|Celeron 600||8 seconds||15 seconds|
Table 1 - Benchmark results
Intel's library seems to take Microsoft's time and cut it in half! It appears that Intel's attention to performance paid off. (Interestingly, I would have expected to see a bigger delta between Intel and Microsoft on the Celeron CPU, but was disappointed.)
I'm sure there are ways to tweak my SlideShowMS program to get better performance from Microsoft's implementation. But the point of this article is to look at an off-the-shelf solution for use by programmers who may not be graphics experts. And for a straightforward implementation, Intel appears to really deliver when it comes to CPU cycles.
What about IJG?
The JPEG file format enjoys great acceptance in the software world. This is due in no small part to the availability of the Independent JPEG Group's (IJG) source code. The IJG created a non-commercial source code package that has been used as a reference and/or library by literally hundreds of programs out there. It enjoys a great deal of respect for its flexibility and feature depth.
Intel knows that many developers have already integrated the IJG code into their products, so they have created a 26-page white paper that discusses what you need to perform open-heart library replacement. There are major structural differences between the two sets of code, so this isn't an exercise for the faint of heart. But it can be done.
I found Intel's library quite easy to work with, which is probably evident given the length of my sample application. While I didn't do too much objective performance testing, I was happy with the speed I achieved when decoding and displaying multi-megapixel JPEG files on various PCs.
My satisfaction with the library is certainly only enhanced by the absence of a price tag. Intel's JPG library is definitely part of my image processing toolbox, you might want to add it to yours as well.