You'll find a short tutorial on how to include image decoding capability in your programs on this page.
[Note for MSVC users: The place most people seem to get stuck in first is in the project settings. The best thing to do when you get obscure compiler and linker errors is probably to compare the project settings of your project with the settings in the sample projects. In particular, make sure paintlib and your program are being built with the same MFC version (static or dynamic? multi- or single-threaded?) and use the same alignment settings.]
In the simplest case, what you need to do to use paintlib is this:
#include "anydec.h" #include "winbmp.h" // Create a decoder. CAnyPicDecoder Decoder; // Create a bitmap object. CWinBmp Bmp; // Tell the decoder to fill the bitmap object with data. Decoder.MakeBmpFromFile ("foo.jpg", &Bmp, 32); // Do something with the bitmap. Bmp.Draw (pdc, 0, 0);
Look at the code for a moment. It's not complicated. Yet. (The example is for windows because there's an easy "Do something with the bitmap" step in this case. The fragment also crashes if an error occurs while decoding. I'll get to the rest in a minute.)
Of course, you can use one decoder to decode several bitmap objects. It makes sense to create a decoder during program initialization and use it until the program terminates. Be warned, however, that the decoder class is not thread-safe. In multi-threaded environments, you need to create one decoder per thread.
When you create the bitmap object, you're also selecting the storage format for the bitmap. Let me explain this. The decoder takes a CBmp as parameter to MakeBmpFromFile. Because CBmp is an abstract base class, there can be no objects of the class. It just exists to define an interface for derived classes. Whenever it needs to store data, it asks the bitmap object for the address to place it. So if you create a CWinBmp and pass it to MakeBmpFromFile, the storage format is a windows DIB (Device Independent Bitmap). We could also have passed a CAnyBmp and stored the data in an OS-independent format. There's a third bitmap class - CDIBSection - for use when you want to decode to a windows DIB section.
Needless to say that you can also define your own bitmap storage formats by deriving from CBmp. (If all this doesn't make sense, ignore what I've just said. Just remember that you can safely pass CWinBmps, CAnyBmps, or objects of any other CBmp-derived class to MakeBmpFromFile() and the bitmap data will arrive in the object in the format defined by the class. ;-)
The last parameter to MakeBmpFromFile is the destination bits per pixel you want. It defaults to 0, which means "just take what's in the file". All colormapped formats will be decoded to 8 bpp in this case, and formats with 15 or more bpp will be decoded to 32 bpp. If you specify 32 for this parameter, the decoded bitmap is promoted to true-color if necessary. Specifying 8 causes the decoder to report an error if the file contains more than 8 bpp.
Once you've decoded the bitmaps, you'll want to do something with them. If you're coding for windows and using CWinBmp, you can do whatever DIBs are capable of. The class defines methods to draw the bitmap to a device context and to copy it to the clipboard. You can also load CWinBmps from resources. The class CDIBSection derives from CWinBmp and has the ability to return a GDI bitmap handle in addition to the features of CWinBmp. This means you can use GDI drawing functions to change the contents of a CDIBSection.
If you're not coding for windows or if you're interested in manipulating the data yourself, this is what "Do something with the bitmap" amounts to:
BYTE ** pLineArray; int x,y; BYTE * pLine; // Get the addresses of the bitmap lines pLineArray = pBmp->GetLineArray(); // Iterate through the lines for (y=0; y<pBmp->GetHeight(); y++) { pLine = pLineArray[y]; // Iterate through the pixels for (x=0; x<pBmp->GetWidth(); x++) { // Set the red intensity to maximum. // (replace this with what you really want to do...) // I'm assuming a 32 bpp bitmap here. pLine[x*4+RGBA_RED] = 0xFFh; } }
pBmp points to an object of a CBmp-derived class. pBmp->GetLineArray() returns an array of pointers to the bitmap lines. Once you have the array, you can iterate through the lines at maximum speed. If you've decoded the bitmap with paintlib, the lines are organized in either 1-byte or 4-byte pixels. The order of the components of each pixel in 32 bpp mode is defined by the constants RGBA_BLUE, RGBA_GREEN, RGBA_RED, and RGBA_ALPHA. In 8 bpp mode, the color of each pixel is determined by the palette of the bitmap.
If you defined _DEBUG when you built the library, it was compiled to contain trace statements and asserts to help you debugging. In addition, debug info is included and optimizations are disabled. Trace statements give diagnostic output to a suitable medium. For MSVC, output is sent either to the MSVC debug log or to a file. Other systems send output to stderr or a file. The amount of information output and the destination can be changed by calling CAnyPicDecoder::SetTraceConfig (Level, pszFName).
In addition to enabling trace output, defining _DEBUG also enables internal sanity checks and parameter validation via asserts. If an assertion fails, the program will stop execution and print out information about the file and line number causing the failure. There are comments at these places in the code to help you sort things out.
Errors which you can potentially recover from are handled by the C++ exception mechanism. Here is sample code including error-handling:
try { Decoder.MakeBmpFromFile ("foo.jpg", &Bmp); } catch (CTextException e) { fprintf (stderr, "Error %d decoding foo.jpg: %s", e.GetCode(), (const char *)e); }
If no error occurs, this code just amounts to one call to MakeBmpFromFile(). If something goes wrong, execution jumps to the catch block. In this block, you have a variable of type CTextException available which provides you with an error code and a descriptive error string. The error codes are explained in the reference section. (IMHO, exceptions are a very powerful C++ feature. If you don't know how they work, you can either work off the code above or learn how to use them effectively. I recommend the latter.)
Under windows, loading a picture (in any format) from a resource is possible. Just place a resource of type RCDATA into the .rc file of the program and load the resource as a picture by calling
MakeBmpFromResource(IDR_PICTURE, &Bmp)The line in the .rc file should look like this:
IDR_PICTURE RCDATA DISCARDABLE "picture.jpg"You will also need to define IDR_PICTURE in resource.h (or wherever resource IDs are defined in your project). Under MSVC, adding a user-defined resource to a project is a bit weird. What you need to do is:
For a real-life example of all this, see the sample programs. Be warned, however, that the sample code is messy in some places.