Graphics Programming using Allegro

Processing Individual Pixels, Negate an Image

Published:  September 6, 2008
by Richard G. Baldwin

File:  Allegro00145


Preface

General

This lesson is part of a series (see Resources) designed to teach you how to use Allegro to do graphics programming in C++.  My purpose in writing the series is to provide lecture and lab material for a course titled Game Development Using C++ that I teach at Austin Community College in Austin, Texas.  However, if you have stumbled upon this series and you find it useful, you are welcome to study it.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

Listings

Supplemental material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

Preview

The purpose of this program is to show you:

This program assumes that the programmer knows the width and height dimensions of the image.

A PCX image file

A PCX image file with dimensions of 324x330 is loaded into a bitmap in memory.  An onscreen window is created that is of sufficient size to contain two copies of the image, one above the other.  The original image is copied into the upper half of the onscreen window as shown in Figure 1.  Then all of the pixels in the memory bitmap are negated and the resulting modified bitmap is copied into the onscreen window immediately below the original image as shown in Figure 1.

Pressing any key causes the program to terminate.

Figure 1. Screen output from program named ImageNegate01.

Discussion and sample code

Negating the pixels in an image is a good way to illustrate the code necessary to process individual pixels in an image because the negation algorithm is very simple.  In addition, pixel negation is much more than simply an exercise.  Many computer programs, including Microsoft Word and Microsoft FrontPage, use pixel negation to indicate that an image has been selectedThe negation process is computationally cheap and totally reversible.

For example, I am currently using Microsoft FrontPage to compose this document.  Figure 1 has a normal image of a starfish at the top and a negated image of the same starfish at the bottom.  If I select Figure 1, the top image becomes negated and the bottom image becomes normal.  De-selecting Figure 1 causes the images to return to the images that you see when you view this document.

Beginning of the program named ImageNegate01

I will explain this program by breaking it down into code fragments and explaining the fragments.  A complete listing of the program is provided in Listing 5 near the end of the lesson.

Listing 1 shows the beginning of the program, including the declaration and initialization of four local variables.  The purpose of each of the local variables is explained in the comments.

Listing 1. Beginning of the program named ImageNegate01.
#include 

int main(){
  int pixel = 0;//temporary storage for a pixel
  
  //Temporary storage for red, green, and blue values
  int red = 0;
  int green = 0;
  int blue = 0;

  //Typical Allegro setup.
  allegro_init();
  install_keyboard();
  set_color_depth(32);

  set_gfx_mode(GFX_AUTODETECT_WINDOWED,324,660,0,0);

You have seen code like this in numerous previous lessons and it shouldn't be necessary to explain the code here.  However, just as a reminder, a few comments are in order.

Comments

As you already know, the last statement in Listing 1 creates an onscreen window.  Also, as you learned in an earlier lesson, the window width must be a multiple of 4.  (At least that is true on my HP laptop computer running Windows Vista Home Premium.)

In addition, the width of the onscreen window should be greater than or equal to the width of the image.  The height of the window should be greater than or equal to twice the height of the image.  If these two conditions aren't met, the window won't be large enough to contain two copies of the image as shown in Figure 1.

Load and display the starfish image

The code in Listing 2 is essentially the same as code that I explained in an earlier lesson, so no explanation should be needed here.

Listing 2. Load and display the starfish image.
  //Declare a pointer variable capable of pointing to a
  // bitmap.
  BITMAP *picA = NULL;
  //Load an image file from the current directory.
  picA = load_bitmap("starfish.pcx", NULL);

  //Copy the image to the upper-left corner of the
  // onscreen window.
  blit(picA, screen, 0,0,0,0,324,330);

When the code in Listing 2 finishes executing, the normal image of the starfish has been displayed in the top of Figure 1.

 Cycle through the bitmap negating each pixel

As I mentioned earlier, the algorithm for negating a pixel is straightforward and totally reversibleAll that is necessary to negate a pixel is to subtract each of the red, green, and blue color values from 255.  All that is necessary to reverse the process and restore the pixel to its normal value is to subtract each of the negated red, green, and blue color values from 255.

A pair of nested for loops

Listing 3 uses a pair of nested for loops to implement the negation algorithm and to negate each pixel in the original memory bitmap.  (This negated bitmap will later be copied to the screen bitmap producing the negated image in the bottom of Figure 1.)

Listing 3. Cycle through the bitmap negating each pixel.
  for(int row = 0;row < 330;row++){
    for(int column = 0;column < 324;column++){
      pixel = getpixel(picA,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      putpixel(picA,column,row,makecol(
                             255-red,255-green,255-blue));
    }//end loop row
  }//end loop on column

Get each pixel value

Listing 3 calls the getpixel function inside the inner loop to gain access to each individual pixel.  A pixel value returned by the getpixel function is simply a numeric value of type int composed of red, green, and blue color values (and possibly a transparency value, commonly known as alpha as well).

Get the red, green, and blue color values

Once you have the pixel value, you can call the getr, getg, and getb functions to get the red, green, and blue color values respectively.  (You can also call the geta function to get the alpha value.)

The color values will all range from 0 to 255.  A value of 0 indicates the total absence of that color component and a color value of 255 indicates the presence of the maximum intensity of that color component.  Values in between the extremes indicate a proportional amount of the color component.  (I will discuss the alpha value in a future lesson.)

Modify the original memory bitmap

After gaining access to an individual pixel value, Listing 3 replaces the original pixel value in the bitmap with the negated value.  This is accomplished by calling the putpixel function and negating each color value in the call to the makecol function inside the parameter list of the putpixel function.

When the code in Listing 3 finishes executing, every pixel in the original memory bitmap has been replaced by its negated value.

Copy the negated bitmap to the onscreen window

Listing 4 begins by copying the negated bitmap to the bottom of the onscreen window as shown in Figure 1.

Listing 4. Copy the negated bitmap to the onscreen window.
  //Copy the modified bitmap to the onscreen window
  // immediately below the original image.
  blit(picA, screen, 0,0,0,330,324,330);

  //Block and wait until the user presses a key.
  readkey();
  
  //Destroy bitmaps to avoid memory leaks.
  destroy_bitmap(picA);

  return 0;//Return 0 to indicate a successful run.
}//end main function
END_OF_MAIN()

Then Listing 4 blocks and waits for the user to press a key, at which time it destroys the memory bitmap and terminates the program.

Summary

I showed you:

The program that I explained in this lesson assumes that the programmer knows the width and height dimensions of the image in advance.  That is somewhat restrictive, so I will deal with that issue in a future lesson.

Complete program listing

A complete listing of the program discussed in this lesson is shown in Listing 5.

Listing 5. Source code for program named ImageNegate01.
//34567890123456789012345678901234567890123456789012345678
/*Project ImageNegate01

This program assumes that the programmer knows the width
and height dimensions of the image.

The purpose of this program is to show how to load an
image file into memory, how to create a negative of the
image, and how to display both the original and the
negated image in an onscreen window.

A PCX image file with dimensions of 324x330 is loaded into
a bitmap in memory.

An onscreen window is created that is of sufficient size
to contain two copies of the image, one above the other.

The original image is copied into the upper half of the
onscreen window.

Then all of the pixels in the bitmap are negated and the
resulting modified bitmap is copied into the onscreen
window immediately below the original image.

Pressing any key causes the program to terminate.
*/
#include <allegro.h>

int main(){
  int pixel = 0;//temporary storage for a pixel
  int red = 0;//temporary storage for red, green, and blue
  int green = 0;
  int blue = 0;

  //Typical Allegro setup.
  allegro_init();
  install_keyboard();
  set_color_depth(32);
  //Create an onscreen window. The window width must be a
  // multiple of 4 and should be greater than or equal to
  // the width of the image. The height of the window
  // should be equal to or greater than twice the height
  // of the image. If the latter two conditions aren't
  // met, the window won't be large enough to contain two
  //copies of the image.
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,324,660,0,0);

  //Declare a pointer variable capable of pointing to a
  // bitmap.
  BITMAP *picA = NULL;
  //Load an image file from the current directory.
  picA = load_bitmap("starfish.pcx", NULL);

  //Copy the image to the upper-left corner of the
  // onscreen window.
  blit(picA, screen, 0,0,0,0,324,330);


  //Cycle through the bitmap negating each pixel.
  for(int row = 0;row < 330;row++){
    for(int column = 0;column < 324;column++){
      pixel = getpixel(picA,column,row);
      red = getr(pixel);
      green = getg(pixel);
      blue = getb(pixel);
      putpixel(picA,column,row,makecol(
                             255-red,255-green,255-blue));
    }//end loop row
  }//end loop on column

  //Copy the modified bitmap to the onscreen window
  // immediately below the original image.
  blit(picA, screen, 0,0,0,330,324,330);

  //Block and wait until the user presses a key.
  readkey();
  
  //Destroy bitmaps to avoid memory leaks.
  destroy_bitmap(picA);

  return 0;//Return 0 to indicate a successful run.
}//end main function
END_OF_MAIN()

 

Resources


Copyright

Copyright 2008, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-