Find Simplicity and Portability in PNGwriter Graphics Library

C++ applications of many stripes need to produce graphics files portably, efficiently, and without a lot of hassle. These graphics are generated as a result of computation and user input, what I used to call plots in the bad old days. The first thing a C++ developer might reach for to implement this function probably is the old Windows SDK’s rudimentary bitmap functions. Unfortunately, the Windows SDK bitmap functions are so rudimentary that the developer will quickly find himself or herself spending more time reading the help files than actually coding.

Enter PNGwriter, a very easy-to-use open source graphics library that uses PNG as its output format. For ease of use and portability, it’s tough to beat PNGwriter. The interface has been designed to be as simple and intuitive as possible. It supports the following:

  • Plotting and reading in the RGB (red, green, blue), HSV (hue, saturation, value/brightness), and CMYK (cyan, magenta, yellow, black) colorspaces
  • Basic shapes
  • Scaling
  • Bilinear interpolation
  • Full TrueType antialiased and rotated text support
  • Bezier curves
  • Opening existing PNG images
  • Much more

PNGwriter runs under Linux, Unix, Mac OS X, and Windows. It requires libpng and optionally FreeType2 for the text support. If you have a Debian Linux distro, you’ve already got PNGwriter on board. Otherwise, you need to download the source from the PNGwriter Sourceforge site. What’s more, if you can generate a series of related images, it’s easy to convert a stream of PNGs to a movie.

What Exactly Is a PNG, You Ask?

PNG, short for Portable Network Graphics, arose as an international standard in 1999 when the ever-increasing number of graphics formats started to become a problem.

Today, you’ll find PNG support in all Web browsers, office products, and photo editors. PNG was designed to be patent-free from the get-go, and yet to replace all existing lossless compression file types, such as GIF and TIFF to name just two.

PNG has a lot of flexibility and many features designed right into the specs, including the following:

  • Multiple CRCs so that file integrity can be checked without viewing
  • Signature that can detect the most common types of file corruption
  • Up to 50 percent better compression than GIF
  • Two-dimensional interlacing scheme
  • 1-, 2-, 4-, and 8-bit palette support (like GIF)
  • 1-, 2-, 4-, 8-, and 16-bit grayscale support
  • 24-bit and 48-bit true color support
  • Alpha-channel transparency in 8- and 16-bit modes
  • Gamma correction for cross-platform brightness control
  • Color correction for cross-platform precision color
  • Both compressed and uncompressed text chunks for copyright and other info

Setting Up PNGwriter

PNGwriter may be easy to use but setting it up for the Visual C++ environment involves a number of steps. In fact, you must follow a step-by-step procedure for it rather than use a makefile. PNG uses Zlib for lossless compression, so you’ll need to download Zlib. It uses pnglib as its base technology, so you’ll need to download pnglib too. Last, you should download FreeType to be able to mix text rendered in TrueType in with your graphics. For the sake of brevity, I disabled FreeType in my project because it had no Visual C++ makefiles. In the unlikely event that you use Cygwin or MinGW compilers, you can skip these steps.

In the end, I created a small batchfile:

set MYINCLUDES=/I D:\pngwriter-0.5.3\src /I D:\libpng-1.2.5
               /I D:\zlib /I D:\freetype-2.2.1\include

cl /c /TP /Z7 /EHsc /DNO_FREETYPE pngwriter.cc %MYINCLUDES%

cl example.c /TP /Z7 /EHsc %MYINCLUDES% /link libpng13.lib zlib.lib
                      pngwriter.obj

Note that there is no “pngwriter.lib”. It is a standalone sourcefile that you can compile separately or actually just #include into your sourcefile. For ease of debugging, I built it as a separate module. Note the /DNO_FREETYPE I used to disable FreeType.

Hello PNGwriter

It never hurts to start out with the simplest possible example code. In this case, I use the sinewave plot program to show how a PNG can be created programmatically:

 1 #include "pngwriter.h"
 2
 3 int main()
 4 {
 5    int i;
 6    pngwriter png(300,300,0,"test.png");
 7    for(i = 1; i < 300;i++)
 8    {
 9       png.plot(i,150+100*sin((double)i*9/300.0), 0.0, 0.0, 1.0);
10    }
11    png.close();
12    return 0;
13 }

What is going on here? I initialize a pngwriter class bitmap object in line 6 to be 300×300 pixels, a background color of black (zero), and an output filename named “test.png”. Then, I loop across the X axis, left to right, computing a sinewave Y value and plot it on line 9. There are two overloaded plot methods; one uses 16-bit ints for RGB and the other has doubles for color inputs from 0.0 to 1.0. In this case, I plot using the doubles (0.0, 0.0, 1.0), which means RED=0, GREEN=0, BLUE=100 percent. So, if you’ve been paying attention, you should expect a blue sinewave on a black background (see Figure 1).

Figure 1. Blue Sinewave on a Black Background

From this demo, it’s just a matter of doing more math to get things like Lorenz Attractor fractals.

The Webmaster’s Dilemma

One of the more boring aspects of being a modern webmaster is getting all the graphics to be the right size for a given purpose. I end up spinning out three to four sizes of every image I’m going to need so I have a good-looking rendition at 100 pix tall, 150 pix tall, and 200 pix tall. This quickly becomes a dull chore in programs like Paint Shop Pro, Photohhop, and so forth. How about a nice C program to resize your image for you and generate all the permutations your pages desire:

 1 #include "pngwriter.h"
 2
 3 int main(int argc, char * argv[])
 4 {
 5    for (int img_height=100; img_height<300; img_height+=50) {
 6       char filename[255];
 7       sprintf(filename,"scaled_%d", img_height);
 8       pngwriter image1(1,1,0,filename);
 9       image1.readfromfile(argv[1]);
10       std::cout << "Read file is:" << image1.getheight()
                   << " " << image1.get width() << "\n";
11       double factor = (double)img_height / image1.getheight();
12       image1.scale_k(factor);
13       std::cout << "New file is:" << image1.getheight()
                   << " " << image1.getwidth() << "\n";
14       image1.close();
15    }
16    return 0;
17 }
18

In line 9, I read a filename passed in on the command line into the pngwriter object called image1. I then compute a proper scale factor based on the ratio of the desired height to the actual height. In line 12, I scale proportionally to get the new desired height. In line 14, I write out a generated PNG file, which might be scaled_100.png, scaled_150.png, and so on.

Book Recommendation

PNG: The Definitive Guide by Greg Roelofs is exactly what the title says it is. Because Roelofs is the maintainer and prime mover of the libpng distribution and home page, he has a pretty good grasp of the subject matter. In the “Design of PNG” section, he includes detailed information on compression and filtering, gamma correction and precision color, and PNG options and extensions. In the “Programming PNG” section, he steps through three sample programs that implement PNG with the libpng C library. It is chock full of examples, sample code, and practical hands-on advice.

Just the Tip of the Iceberg

I have really only scratched the surface of the more interesting PNGwriter features. PNGwriter can give you HSV and CMYK translations of image data, plot TrueType text, handle Bezier curves, and many other functions limited only by your imagination. If PNGwriter lacks anything, it would be a complete build system for Visual C++ or else a site dedicated to providing binaries for all the versions of Visual C++ out there in common use.

About the Author

Victor Volkman has been writing for C/C++ Users Journal and other programming journals since the late 1980s. He is a graduate of Michigan Tech and a faculty advisor board member for Washtenaw Community College CIS department. Volkman is the editor of numerous books, including C/C++ Treasure Chest and is the owner of Loving Healing Press. He can help you in your quest for open source tools and libraries; just drop an e-mail to sysop@HAL9K.com.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read