![]() Original |
![]() Gold |
This is a two-step process. The first step is to create the metallic sheen.

Start with a grayscale image and increase the number of transitions between white and black.
![]() Original |
![]() 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.
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.
![]()
The gradient is applied to an 8-bit image as a new palette or to a 24-bit image through lookup tables.
// 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);
}
Victor Image Processing Library homepage |
Victor Sample Code