Victor Image Processing Library How-to Tips

Making Metallic

An image appears to have a metallic sheen when normal shading from dark to light is replaced with multiple transitions between light and dark. This gives the appearance of reflective highlights characteristic of shiny metal. To make it appear gold, bronze, or other color construct a color gradient and apply it to the image.
grayscale leaf
Original
gold metallic leaf
Gold

This is a two-step process. The first step is to create the metallic sheen.

metallic leaf
Metallic

Start with a grayscale image and increase the number of transitions between white and black.

single transition
Original
six transitions
Metallic

This effect requires a smooth gradation of brightness values in the image. A sharpened image, or one with a lot of noise will not develop the metallic sheen. In the sample code below, we replace the normal range of black (0) to white (255) with six transitions between light and dark. We construct a lookup table for replacing the pixel values.

The important thing to remember when striving for the metallic sheen is that the source image must have a gradation of brightness values. Also, as you experiment with this technique you will learn that each image is unique and a table that works well for one image may produce garish effects on another.

Metallic - the Source Code

This function works best for grayscale images. Color images may yield unpredictable results. Requires Victor Image Processing Library v 4.1x or higher.
int metallic(imgdes *srcimg, imgdes *resimg)
{
   int rcode, buffsize=256, j, k=0;
   static UCHAR *redlut;
   redlut = (UCHAR far*)malloc(buffsize);
   for(j=0; j<255;) {
      for(k=0; k<256; k+=6) {
         redlut[j++] = (UCHAR)k;
         }
      for(k=255; k>0; k-=6) {
         redlut[j++] = (UCHAR)k;
         }
      }
   redlut[255]=255;
   
   rcode = usetable(redlut, redlut, redlut, srcimg, resimg);
   free(redlut);
   return(rcode);
}

After developing the metallic sheen, a color gradient is applied to the image. The gradient used for the gold leaf above starts at black, changes to red, moves through orange, and ends at white.

black-red-orange-white gradient

The gradient is applied to an 8-bit image as a new palette or to a 24-bit image through lookup tables.

Gold Leaf - the Source Code

Requires Victor Image Processing Library v 4.1x or higher.
// New data type to define the start and end of a color ramp
typedef struct {
   int lo, hi, lored, logrn, loblu, hired, higrn, hiblu;
   } COLORAMP;
// Prototypes for the helper functions, defined below
void ramplut(int low, int high, UCHAR *lut);
void ramppalette(int low, int high, RGBQUAD *paltab);
int rampcolors(COLORAMP *ramp, imgdes *srcimg, imgdes *resimg);
int goldcolor(imgdes *srcimg, imgdes *resimg)
{ // Create a gradient: black - red - orange - white
   int rcode ;
   COLORAMP ramp;
   ramp.lo = 0; // Black  
   ramp.lored= 0; 
   ramp.logrn= 0; 
   ramp.loblu= 0; 
   ramp.hi = 55;  // Red
   ramp.hired= 190; 
   ramp.higrn= 55; 
   ramp.hiblu= 0; 
   rcode = rampcolors(&ramp, srcimg, resimg);
   ramp.lo = 55; // Red
   ramp.lored= 190; 
   ramp.logrn= 55; 
   ramp.loblu= 0; 
   ramp.hi = 155;  // Orange
   ramp.hired= 255; 
   ramp.higrn= 190; 
   ramp.hiblu= 50; 
   rcode = rampcolors(&ramp, srcimg, resimg);
   
   ramp.lo = 155; // Orange
   ramp.lored= 255; 
   ramp.logrn= 190; 
   ramp.loblu= 50; 
   ramp.hi = 255;  // White
   ramp.hired= 255; 
   ramp.higrn= 255; 
   ramp.hiblu= 255; 
   rcode = rampcolors(&ramp, srcimg, resimg);
   
   return(rcode);
}
void ramplut(int low, int high, UCHAR *lut)
/* low, high -- color numbers to ramp (0-255) */
{
	int loval, hival;
	int j, deltaval, deltalut;
	float m, b; // slope and intercept, as in y = mx + b 
	float temp;
	if(low == high)
		return;
	loval = lut[low];
	hival = lut[high];
	deltalut = high - low;
	deltaval = hival - loval;
	m = (float)deltaval/deltalut;
	b = (float)loval - (low * m);
	for(j = low; j<high; j++) {
		temp = (float)j * m + (float)b;
		lut[j] = (UCHAR) temp;
		}
}
void ramppalette(int low, int high, RGBQUAD *paltab)
/* low, high -- color numbers to ramp (0-255) */
{
	int lowr, lowg, lowb, highr, highg, highb;
	int j, deltared, deltagrn, deltablu, deltapal;
	float mr, mg, mb, br, bg, bb; /* slope and intercepts */
	float temp;
	if(low == high)
		return;
	lowr = paltab[low].rgbRed;
	lowg = paltab[low].rgbGreen;
	lowb = paltab[low].rgbBlue;
	highr = paltab[high].rgbRed;   
	highg = paltab[high].rgbGreen; 
	highb = paltab[high].rgbBlue;   
	deltapal = high - low;
	deltared = highr - lowr;
	deltagrn = highg - lowg;
	deltablu = highb - lowb;
	mr = (float)deltared/deltapal;
	mg = (float)deltagrn/deltapal;
	mb = (float)deltablu/deltapal;
	br = (float)lowr - (low * mr);
	bg = (float)lowg - (low * mg);
	bb = (float)lowb - (low * mb);
	for(j = low; j<high; j++) {
		temp = (float)j * mr + (float)br;
		paltab[j].rgbRed = (UCHAR) temp;
		temp = (float)j * mg + (float)bg;
		paltab[j].rgbGreen = (UCHAR) temp;
		temp = (float)j * mb + (float)bb;
		paltab[j].rgbBlue = (UCHAR) temp;
		}
}
/* Ramp colors to form a gradient between two specificed colors. 
   For 8-bit images set up to ramp the palette, for 24-bit
   images ramp three lookup tables
*/
int rampcolors(COLORAMP *ramp, imgdes *srcimg, imgdes *resimg)
{
   int rcode, buffsize=256, j;
   static UCHAR *redlut, *grnlut, *blulut;
   copyimage(srcimg, resimg);
   switch(srcimg->bmh->biBitCount){
   case (8):
      resimg->palette[ramp->lo].rgbRed = ramp->lored;
      resimg->palette[ramp->lo].rgbGreen = ramp->logrn;
      resimg->palette[ramp->lo].rgbBlue = ramp->loblu;
      resimg->palette[ramp->hi].rgbRed = ramp->hired;
      resimg->palette[ramp->hi].rgbGreen = ramp->higrn;
      resimg->palette[ramp->hi].rgbBlue  = ramp->hiblu;
      ramppalette(ramp->lo,ramp-> hi, resimg->palette);
      resimg->imgtype = 0;  // Make sure it's not considered grayscale
      rcode = updatebitmapcolortable(resimg);
      break;
   case (24):
      redlut = (UCHAR far*)malloc(buffsize);
      grnlut = (UCHAR far*)malloc(buffsize);
      blulut = (UCHAR far*)malloc(buffsize);
      for(j=0; j<256; j++) {
         redlut[j] = grnlut[j] = blulut[j] = j;
         }
      redlut[ramp->lo] = ramp->lored; 
      grnlut[ramp->lo] = ramp->logrn; 
      blulut[ramp->lo] = ramp->loblu;
      redlut[ramp->hi] = ramp->hired;
      grnlut[ramp->hi] = ramp->higrn;
      blulut[ramp->hi] = ramp->hiblu;
      ramplut(ramp->lo, ramp->hi, redlut);
      ramplut(ramp->lo, ramp->hi, grnlut);
      ramplut(ramp->lo, ramp->hi, blulut);
      rcode = usetable(redlut, grnlut, blulut, resimg, resimg);
      free(blulut);
      free(grnlut);
      free(redlut);
      break;
   case (1):
      rcode = BAD_BPP;
   }
   return(rcode);
}


Copyright © 1997 Catenary Systems Inc. All rights reserved. Victor Image Processing Library is a trademark of Catenary Systems.


Victor Image Processing Library homepage | Victor Sample Code