Complete program listing

A complete listing of the program is shown in Listing 7.

Listing 7. Source code for program named ImageNegate03.
/*Project ImageNegate03

This program is similar to ImageNegate01. However, this
version assumes that the programmer does not know the
width and height of the image.

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

A PCX image file of an unknown size is loaded into memory
and displayed in the top half of a graphics window on the
screen. A negated version of the image is displayed in the
bottom half of the window.

The width and height of the image and the width and height
of the window respectively are displayed in the upper-left
corner of the window. For a particular file named
starfish.pcx, the following output is superimposed on the
original image:
321
327
324
654

I have determined experimentally that the width of the
window MUST be a multiple of 4. I have also determined
experimentally that the width must be at least 108 pixels.
This second requirement seems to be a characteristic of
Windows Vista because it is not possible to manually
resize a window to make it narrower than approximately
108 pixels. If these two conditions aren't met, the
program hangs up my Windows Vista Home Premium edition OS
requiring me to log out and then log back in order to
continue programming in Dev-C++.

I have also determined experimentally that for PCX or BMP
files with a color depth of 16, 24, or 32, you MUST create
the onscreen window before you call load_bitmap to load
the image file. Otherwise, the colors may not be correct.
This makes it difficult to set the size of the window
based solely on the dimensions of the clip rectangle of
the image. The clip rectangle can't be obtained until
after the image file is loaded.

There may be a better solution to this problem than mine,
but if so, I haven't discovered it yet.  While my
solution is not elegant, it works. My solution in this
program is to perform the following sequence of
operations:

Load the image file into a bitmap.
Get the height and width of the bitmap.
Destroy the bitmap.
Create the window of the correct size.
Load the image file again into a second bitmap.
Display the image in the top of the window.
Negate the image in the bitmap.
Display the negated image in the bottom of the window.

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

int main(){
  int pixel = 0;//temporary storage for a pixel

  //Temporary storage for red, green, and blue
  int red = 0;
  int green = 0;
  int blue = 0;
  
  int width = 0;//image width
  int height = 0;//image height
  int windowWidth = 0;//must be a multiple of 4 && >= 108
  int windowHeight = 0;
  
  //The addresses of the following variables are passed
  // in the call to get_clip_rect, where they are
  // populated with the coordinates of the diagonal
  // corners of the rectangular image.
  int upperLeftX = 0;
  int upperLeftY = 0;
  int lowerRightX = 0;
  int lowerRightY = 0;

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

  //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);
  
  //Get the current clip rectangle for the image. This is
  // (one less than) the size of the image in both
  // dimensions.
  get_clip_rect(picA,
                &upperLeftX,
                &upperLeftY,
                &lowerRightX,
                &lowerRightY);

  //Compute the width and the height from the coordinates
  // of the diagonal corners of the clip rectangle.
  width = lowerRightX  + 1;
  height = lowerRightY + 1;
  
  //Compute the window dimensions based on the width
  // and height of the bitmap. Guarantee that the width
  // is a multiple of 4 large enough to contain the
  // image and is not less than 108 pixels.
  if(width % 4 == 0){
    windowWidth = width;
  }else{
    windowWidth = (width/4)*4 + 4;
  }//end else
  
  if(windowWidth < 108){
    windowWidth = 108;
  }//end if
  
  //Make the height sufficient to contain two copies of
  // the image, one above the other.
  windowHeight = 2 * height;
  
  //Destroy the bitmap, create the display window, and
  // reload the bitmap.
  destroy_bitmap(picA);
  set_gfx_mode(GFX_AUTODETECT_WINDOWED,
               windowWidth,
               windowHeight,
               0,
               0);
  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,width,height);

  //Display the width and height of the bitmap and the
  // window in the upper-left corner of the window.
  char charArray[20];
  sprintf(charArray, "%d", width);
  textout_ex(screen,font,charArray,10,10,
                                 makecol(255,255,255),-1);
  sprintf(charArray, "%d", height);
  textout_ex(screen,font,charArray,10,20,
                                 makecol(255,255,255),-1);
  sprintf(charArray, "%d", windowWidth);
  textout_ex(screen,font,charArray,10,30,
                                 makecol(255,255,255),-1);
  sprintf(charArray, "%d", windowHeight);
  textout_ex(screen,font,charArray,10,40,
                                 makecol(255,255,255),-1);

  //Cycle through the bitmap negating each pixel.
  for(int row = 0;row < height;row++){
    for(int column = 0;column < width;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,height,width,height);

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

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