ilteris kaplan blog

Archive of blog posts since 2005

April 5, 2008

Wiki

Adjusting Brightness

#wiki

Adjusting Brightness

Step by Step

To adjust the brightness values of an image we have to do couple of things. First hand we need to import an image. We are using Quicktime library for this. Here is the function:


void ImportFile(GWorldPtr destWorld,int left,int top,int right, int bottom) {
/* this method imports a file and returns a picture handle .
  it uses Quicktime so it can
import almost any file format including JPG , Pict, 
Photoshop, EPS, BMP, GIF and many more.
 you must have the QuickTime.lib in your project to 
compile, and have Quicktime installed to run
*/
   Rect				recti;
   PicHandle			theNewPic;
   OSErr myError;
   ComponentInstance gi;
   FSSpec fsp;
   Point where;
   AEKeyword  myKeyword;
   DescType  myActualType;
   Size   myActualSize ;
   NavReplyRecord navreply;
  where.h=200; where.v=100;
/* where the  Standard File dialog window goes */
NavGetFile (NULL, &navreply,NULL,NULL,NULL,NULL,NULL,NULL);
    if (AEGetNthPtr(&(navreply.selection), 1, typeFSS, &myKeyword, 
&myActualType, &fsp, sizeof(fsp), &myActualSize)!= noErr) SysBeep(10);
       myError=GetGraphicsImporterForFile(&fsp,&gi);
       myError=GraphicsImportGetAsPicture (gi,&theNewPic);
       CloseComponent(gi); 
       SetRect(&recti,left,top,right,bottom);
       SetPort((GrafPtr)destWorld);
       DrawPicture(theNewPic,&recti);
       // drawing the imported picture onto the second buffer 
        KillPicture(theNewPic); 
}

I haven’t digged too much of this function and I am skipping it to concentrate more on the pixel manipulation functions. The important thing is, we are not drawing our image to the second buffer. Instead, we created another buffer (another offworld buffer) that is going to hold the original image for us. So in the header we have a line like this:


GWorldPtr	ourBuffer,ourImage; 

and ourImage is going to hold the image data. Next our whole manipulations functions are going to be in DrawToBuffer again. In DrawToBuffer funcion we are accessing the pixel information of our imagebuffer just like we access our GWorld buffer. First we are getting the PixMap of the buffer, then extracting the rowBytes to get the width of the pixels, and finally we are getting the base address.


imagePixmap=GetGWorldPixMap(ourImage);
imageRowBytes  = ((*(imagePixmap))->rowBytes) & 0x7fff;
imageBaseAddress   = GetPixBaseAddr(imagePixmap );

Next we need to extract those ARGB values of bits that we access. In order to do that, we are using a function called ourGetPixel, and here is the definition of this function:

 
void ourGetPixel(unsigned short horizontal,unsigned short vertical,
unsigned char* R,unsigned char* G,unsigned char* B,unsigned short rowbytes,
Ptr pixbase){
       Ptr AdressOfRed;
       AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1;
*R=*(AdressOfRed);
*G=*(AdressOfRed+1);
*B=*(AdressOfRed+2);
}

This function sets the R,G, B values for each pixel in our program to the ones in the image. Then we do our manipulation and eventually call oursetPixel function for our good old buffer. We draw our manipulated pixels on this buffer and then swap the buffers that show up on the screen and voila.

Our manipulation to change the brightness value of the pixel is straightforward, we are increasing or decreasing the RGB values of pixels simultaneously thus giving us the change in the brightness.


temp =  distance+R;
     if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
     R = temp;
     temp =  distance+G; // we make it.
      if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
      G = temp; 
      temp =  distance+B;
      if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
      B = temp;

DrawToBuffer

 
void DrawToBuffer(void) {
long x , y,temp,distance;
Point mousepoint;
unsigned short bufferRowBytes,imageRowBytes ;
Ptr bufferBaseAddress,imageBaseAddress;
PixMapHandle bufferPixmap, imagePixmap;
unsigned char R,G,B;
count++;
GetMouse(&mousepoint);
bufferPixmap=GetGWorldPixMap(ourBuffer);
// getting the pixel map of our buffer GWorld 
// so that we can access the pixels
bufferRowBytes  = ((*(bufferPixmap))->rowBytes) & 0x7fff;
// getting the number of bytes in each row 
// of the pixel map. This is then used to	

// calculate the location in memory of specific pixels
bufferBaseAddress   = GetPixBaseAddr(bufferPixmap );
// getting the base address in memory of the 
// begining of the pixel data

imagePixmap=GetGWorldPixMap(ourImage);
// getting the pixel map of our buffer GWorld
// so that we can access the pixels
imageRowBytes  = ((*(imagePixmap))->rowBytes) & 0x7fff;
// getting the number of bytes in each row of 
// the pixel map. This is then used to

// calculate the location in memory of specific pixels
imageBaseAddress   = GetPixBaseAddr(imagePixmap );

distance = (mousepoint.v-320);
// if you go up it makes it darker, down it makes it brighter.
for(x=0;x<640;x++){
      for(y=0;y<480;y++){
      ourGetPixel(x,y,&R,&G,&B,imageRowBytes,imageBaseAddress);	
          // geting the color value of a pixel in our image
          // buffer , note that we need to pass
          // the adress (!) of three unsigned chars to
          // hold the values
          // we are using the ampersand since we are 
          // getting the values. 
          temp =  distance+R;
          if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
          // adding the distance from the mouse to the R, 
	// G and B , this actually makes the pixel
	// brighter, We use a long called temp to do 
	// the addition so we don't run into problems
	// if the result is greater than 255, then we 
	// check to see that it is between 2- 255 , and 
	// if not 							
	// The values which are valid for RGB are 0-255! 
	// So we need to check 
	// if they are between 
             R = temp;
             temp =  distance+G; // we make it.
             if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
             G = temp;
             temp =  distance+B;
	    if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
             B = temp;
             ourSetPixel(x,y,R,G,B,bufferRowBytes,bufferBaseAddress);
               // calling our method that set individual pixels and 
               // expects : X coordinate of the pixel,
               // y coordinate of the pixel, R value, G value, B value,
               // the number of bytes in each row of the pixel map, the base
               // address in memory of the begining of the pixel data
              }
         }
} 

Source Code


/*****************************         Adjusting Brightness.c Mac   *************************/


void 	Initialize(void);											// function prototypes
void	DrawLine( void );
void	doEventLoop( void );
void 	DrawToBuffer(void);
void 	CopyToWindow (void);
int 	ourRandom(  int min,  int max );
void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase);
void ourGetPixel(unsigned short horizontal,unsigned short vertical,unsigned char* R,unsigned char* G,unsigned char* B,unsigned short rowbytes,Ptr pixbase);
void ImportFile(GWorldPtr destWorld,int left,int top,int right, int bottom);



														//globals
WindowPtr	ourWindow;
Rect		windRect;
GWorldPtr	ourBuffer,ourImage; 
// we added another buffer called ourimage 
//in order to hold hte image we import and we are not going to 
// manipulate that buffer. We don't want to fuck our image! 
int			count=0;

void DrawToBuffer(void) {
	long x , y,temp,distance;
	Point mousepoint;
	unsigned short bufferRowBytes,imageRowBytes ;
	Ptr bufferBaseAddress,imageBaseAddress;
	PixMapHandle bufferPixmap, imagePixmap;
	unsigned char R,G,B;
	count++;
	GetMouse(&mousepoint);			
	
	bufferPixmap=GetGWorldPixMap(ourBuffer);
	// getting the pixel map of our buffer GWorld so that we can access the pixels
	bufferRowBytes  = ((*(bufferPixmap))->rowBytes) & 0x7fff;
* getting the number of bytes in each row of the pixel map. This is then used to																			* calculate the location in memory of specific pixels
	bufferBaseAddress   = GetPixBaseAddr(bufferPixmap );
	// getting the base address in memory of the begining of the pixel data

	imagePixmap=GetGWorldPixMap(ourImage);
	// getting the pixel map of our buffer GWorld so that we can access the pixels
	imageRowBytes  = ((*(imagePixmap))->rowBytes) & 0x7fff;
* getting the number of bytes in each row of the pixel map. This is then used to																			* calculate the location in memory of specific pixels
	imageBaseAddress   = GetPixBaseAddr(imagePixmap );				
	distance = (mousepoint.v-320);
	// if you go up it makes it darker, down it makes it brighter.
	for(x=0;x<640;x++){														 
		for(y=0;y<480;y++){												
			ourGetPixel(x,y,&R,&G,&B,imageRowBytes,imageBaseAddress);			
			// geting the color value of a pixel in our image buffer , note that we need to pass 
			// the adress (!) of three unsigned chars to hold the values		
			// we are using the ampersand since we are getting the values. 
			temp =  distance+R;
			if (temp > 255) temp = 255; else if (temp < 0) temp = 0;			
			// adding the distance from the mouse to the R, G and B , this actually makes the pixel
			// brighter, We use a long called temp to do the addition so we don't run into problems
			// if the result is greater than 255, then we check to see that it is between 2- 255 , and if not 							
			// The values which are valid for RGB are 0-255! So we need to check 
			// if they are between!
			R = temp;															
																										
			temp =  distance+G; // we make it.
			if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
			G = temp;
			
			temp =  distance+B;
			if (temp > 255) temp = 255; else if (temp < 0) temp = 0;
			B = temp;
															
			ourSetPixel(x,y,R,G,B,bufferRowBytes,bufferBaseAddress);						
* calling our method that set individual pixels and expects : X coordinate of the pixel,																			* y coordinate of the pixel, R value, G value, B value, the number of bytes in each row of the pixel map, the base 
			// address in memory of the begining of the pixel data
		}																	
	}																																		
}




void CopyToWindow (void){													
	//  copy all our buffer to the window, completely replaceing 
	//  everything that was there
	Rect sourceRect,destRect;
	SetPortWindowPort(ourWindow);
	GetPortBounds( GetWindowPort(ourWindow), &destRect ); 
	GetPortBounds( ourBuffer, &sourceRect ); 
	 CopyBits( GetPortBitMapForCopyBits( ourBuffer ), GetPortBitMapForCopyBits(GetWindowPort(ourWindow)),
                &sourceRect, &destRect, srcCopy, NULL );
																
}
	
	
	
void	main( void )

{
	Initialize();
	doEventLoop();
	
}


void 	Initialize(void){

	OSErr		error;
		
	SetRect(&windRect,100,100,740,580);
	InitCursor();

	ourWindow = NewCWindow( 0L, &windRect,  "\pAdjust Brightness", true, noGrowDocProc,(WindowPtr)-1L, true, 0L ); 
	if ( ourWindow == nil )	ExitToShell();
	
	ShowWindow( ourWindow );
	SetPortWindowPort( ourWindow );
	SetRect(&windRect,0,0,640,480);
	error =NewGWorld(&ourBuffer, 32, &windRect, nil, nil,0 );					
	// creating our offscreen buffer
		if (error != noErr ) ExitToShell();
	error =NewGWorld(&ourImage, 32, &windRect, nil, nil,0 );	
		if (error != noErr ) ExitToShell();
	
	ImportFile(ourImage,0,0,640,480);	 
	// Calling our method that opens a picture file and returns a picture handle
	
	
}

/*************** The Event Loop ***************/
void doEventLoop()
{
	EventRecord anEvent;
	WindowPtr   evtWind;
	short       clickArea;
	Rect        screenRect;
	Point		thePoint;
	for (;;){
		if (WaitNextEvent( everyEvent, &anEvent, 0, nil )){
			if (anEvent.what == mouseDown){
				clickArea = FindWindow( anEvent.where, &evtWind );				
				if (clickArea == inDrag){
					GetRegionBounds( GetGrayRgn(), &screenRect );
					DragWindow( evtWind, anEvent.where, &screenRect );
				}
				else if (clickArea == inContent){
					if (evtWind != FrontWindow())
						SelectWindow( evtWind );
					else{
						thePoint = anEvent.where;
						GlobalToLocal( &thePoint );
					}
				}
				else if (clickArea == inGoAway)
					if (TrackGoAway( evtWind, anEvent.where ))
						return;
			}
		}
		DrawToBuffer();														
		// after checking for various events we call our drawing finctions
		CopyToWindow();
	}
}



int ourRandom(  int min,  int max ){										
	// method that returns a random number between min and max						
	return( (Random()+32768) /((32768*2/) (max-min)))+ min;

}


void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase){
	Ptr AdressOfRed;
	AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1;
*(AdressOfRed)=R;
*(AdressOfRed+1)=G;
*(AdressOfRed+2)=B;
}

void ourGetPixel(unsigned short horizontal,unsigned short vertical,unsigned char* R,unsigned char* G,unsigned char* B,unsigned short rowbytes,Ptr pixbase){
	Ptr AdressOfRed;
	AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1;
*R=*(AdressOfRed);
*G=*(AdressOfRed+1);
*B=*(AdressOfRed+2);
}



void ImportFile(GWorldPtr destWorld,int left,int top,int right, int bottom) {
	// this method imports a file and returns a picture handle . it uses Quicktime so it can
    //	import almost any file format including JPG , Pict, Photoshop, EPS, BMP, GIF and many more.
	// you must have the QuickTime.lib in your project to compile, and have Quicktime installed to run
	
	Rect				recti;
	PicHandle			theNewPic;
	OSErr myError;
	ComponentInstance gi;
	FSSpec fsp;
	Point where;
	AEKeyword  myKeyword;
	DescType  myActualType;
	Size   myActualSize ;
	NavReplyRecord navreply;
	where.h=200; where.v=100;    									 
	/* where the  Standard File dialog window goes */

	NavGetFile (NULL, &navreply,NULL,NULL,NULL,NULL,NULL,NULL);
	if (AEGetNthPtr(&(navreply.selection), 1, typeFSS, &myKeyword, &myActualType, &fsp, sizeof(fsp), &myActualSize)!= noErr) SysBeep(10);

	myError=GetGraphicsImporterForFile(&fsp,&gi);
	myError=GraphicsImportGetAsPicture (gi,&theNewPic);		
	CloseComponent(gi);	

	SetRect(&recti,left,top,right,bottom);
	SetPort((GrafPtr)destWorld);		
	DrawPicture(theNewPic,&recti);										
	// drawing the imported picture onto the second buffer 
	KillPicture(theNewPic); 
}

Continue Reading

Back to Archive