Back to index

plt-scheme  4.2.1
wx_gam.cc
Go to the documentation of this file.
00001 /* 
00002  * xvgam.c - Gamma Correction box handling functions
00003  *
00004  * callable functions:
00005  *
00006  *   CreateGam(geom)        -  creates the ctrlW window.  Doesn't map it.
00007  *   GamBox(vis)            -  random processing based on value of 'vis'
00008  *                             maps/unmaps window, etc.
00009  *   RedrawGam(x,y,w,h)     -  called by 'expose' events
00010  *   RedrawGraph(x,y,w,h)   -  called by 'expose' events
00011  *   ClickGam(x,y)          -  called when B1 clicked in gamW 
00012  *   TrackGraph(x,y)        -  called when B1 clicked in graphW
00013  *   GenerateGamma()        -  called to generate/error-check 'ghand'
00014  *   GenerateFSGamma()      -  called to generate floyd steinberg correction
00015  *   GammifyColors()        -  does gamma correction of r[],g[],b[] arrays
00016  *   SetGPreset()           -  sets preset #n to supplied values
00017  */
00018 
00019 /*
00020  * Copyright 1989, 1990 by the University of Pennsylvania
00021  *
00022  * Permission to use, copy, and distribute for non-commercial purposes,
00023  * is hereby granted without fee, providing that the above copyright
00024  * notice appear in all copies and that both the copyright notice and this
00025  * permission notice appear in supporting documentation.
00026  *
00027  * The software may be modified for your own purposes, but modified versions
00028  * may not be distributed.
00029  *
00030  * This software is provided "as is" without any express or implied warranty.
00031  */
00032 
00033 
00034 #include <stdlib.h>
00035 #include "wx_image.h"
00036 
00037 #define BUTTW   80
00038 #define BUTTW2 100
00039 #define BUTTH   19
00040 
00041 #define LINESTR "Lines"
00042 #define CURVSTR "Spline"
00043 #define HSVSTR  "HSV Mode"
00044 #define RGBSTR  "RGB Mode"
00045 
00046 byte           gamcr[256];   /* gamma correction curve */
00047 byte           fsgamcr[256]; /* gamma correction curve (for FS dither) */
00048 
00049 #define NUMHANDS 4
00050 XPoint        ghand[NUMHANDS];
00051 
00052 XPoint defgam[NUMHANDS];
00053 static int firsttime=1;
00054 
00055 
00056 // #if (defined(__STDC__) || hpux)
00057 static float splint(int xa[],int ya[],float y2a[],int n, float x);
00058 static void spline(int *, int *, int, float *);
00059 // #else
00060 // static void spline();
00061 // static float splint();
00062 // #endif
00063 
00064 /*********************/
00065 void wxImage::GenerateGamma()
00066 {
00067   /* this function generates a gamma correction curve (gamcr)
00068 
00069      This function generates a 4 point spline curve to be used as a 
00070      non-linear grey 'colormap'.  Two of the points are nailed down at 0,0
00071      and 255,255, and can't be changed.  You specify the other two.  If
00072      you specify points on the line (0,0 - 255,255), you'll get the normal
00073      linear reponse curve.  If you specify points of 50,0 and 200,255, you'll
00074      get grey values of 0-50 to map to black (0), and grey values of 200-255
00075      to map to white (255) (roughly).  Values between 50 and 200 will cover
00076      the output range 0-255.  The reponse curve will be slightly 's' shaped. */
00077 
00078   int i,j;
00079   static int x[NUMHANDS], y[NUMHANDS];
00080   float yf[NUMHANDS];
00081 
00082   /* do some idiot-proofing (x-coords must be monotonically increasing)  */
00083 
00084   for (i=0; i<4; i++) { 
00085     RANGE(ghand[i].x, 0, 255); 
00086     RANGE(ghand[i].y, 0, 255);
00087   }
00088 
00089   ghand[0].x = 0;  ghand[3].x = 255;
00090   if (ghand[1].x < 1)  ghand[1].x = 1;
00091   if (ghand[1].x >253) ghand[1].x = 253;
00092   if (ghand[2].x < ghand[1].x) ghand[2].x = ghand[1].x + 1;
00093   if (ghand[2].x >254) ghand[2].x = 254;
00094 
00095   if (firsttime) {   /* if this is the first 'generate' save as 'default' */
00096     memcpy(defgam, ghand, sizeof(ghand));
00097     firsttime=0;
00098   }
00099 
00100   for (i=0; i<NUMHANDS; i++) { x[i] = ghand[i].x;  y[i] = ghand[i].y; }
00101   spline(x, y, NUMHANDS, yf);
00102   
00103   for (i=0; i<256; i++) {
00104     j = (int) splint(x, y, yf, NUMHANDS, (float) i);
00105     if (j<0) j=0;
00106     else if (j>255) j=255;
00107     gamcr[i] = j;
00108   }
00109 }
00110 
00111 
00112 /*********************/
00113 void wxImage::GenerateFSGamma()
00114 {
00115   /* this function generates the Floyd-Steinberg gamma curve (fsgamcr)
00116 
00117      This function generates a 4 point spline curve to be used as a 
00118      non-linear grey 'colormap'.  Two of the points are nailed down at 0,0
00119      and 255,255, and can't be changed.  You specify the other two.  If
00120      you specify points on the line (0,0 - 255,255), you'll get the normal
00121      linear reponse curve.  If you specify points of 50,0 and 200,255, you'll
00122      get grey values of 0-50 to map to black (0), and grey values of 200-255
00123      to map to white (255) (roughly).  Values between 50 and 200 will cover
00124      the output range 0-255.  The reponse curve will be slightly 's' shaped. */
00125 
00126   int i,j;
00127   static int x[4] = {0,32,224,255};
00128   static int y[4] = {0, 0,255,255};
00129   float yf[4];
00130 
00131   spline(x, y, 4, yf);
00132   
00133   for (i=0; i<256; i++) {
00134     j = (int) splint(x, y, yf, 4, (float) i);
00135     if (j<0) j=0;
00136     else if (j>255) j=255;
00137     fsgamcr[i] = j;
00138   }
00139 }
00140 
00141 
00142 /*********************/
00143 static void spline(int *x,int *y,int n,float *y2)
00144 {
00145   /* given arrays of data points x[0..n-1] and y[0..n-1], computes the
00146      values of the second derivative at each of the data points
00147      y2[0..n-1] for use in the splint function */
00148 
00149   int i,k;
00150   float p,qn,sig,un,u[NUMHANDS];
00151 
00152   y2[0] = u[0] = 0.0;
00153 
00154   for (i=1; i<n-1; i++) {
00155     sig = ((float) x[i]-x[i-1]) / ((float) x[i+1] - x[i-1]);
00156     p = sig * y2[i-1] + 2.0;
00157     y2[i] = (sig-1.0) / p;
00158     u[i] = (((float) y[i+1]-y[i]) / (x[i+1]-x[i])) - 
00159            (((float) y[i]-y[i-1]) / (x[i]-x[i-1]));
00160     u[i] = (6.0 * u[i]/(x[i+1]-x[i-1]) - sig*u[i-1]) / p;
00161   }
00162   qn = un = 0.0;
00163 
00164   y2[n-1] = (un-qn*u[n-2]) / (qn*y2[n-2]+1.0);
00165   for (k=n-2; k>=0; k--) {
00166     y2[k] = y2[k]*y2[k+1]+u[k];
00167   }
00168 }
00169 
00170 
00171 
00172 /*********************/
00173 static float splint(int xa[],int ya[],float y2a[],int n, float x)
00174 {
00175   int klo,khi,k;
00176   float h,b,a;
00177 
00178   klo = 0;
00179   khi = n-1;
00180   while (khi-klo > 1) {
00181     k = (khi+klo) >> 1;
00182     if (xa[k] > x) khi = k;
00183     else klo = k;
00184   }
00185   h = xa[khi] - xa[klo];
00186   if (h==0.0) fprintf(stderr, "bad xvalues in splint\n");
00187   a = (xa[khi]-x)/h;
00188   b = (x-xa[klo])/h;
00189   return (a*ya[klo] + b*ya[khi] + ((a*a*a-a)*y2a[klo] +(b*b*b-b)*y2a[khi]) 
00190          * (h*h) / 6.0);
00191 }
00192     
00193 /*********************/
00194 void wxImage::GammifyColors()
00195 {
00196    HSVgamma();
00197 }
00198 
00199 
00200 #define NOHUE -1
00201 
00202 /*********************/
00203 void wxImage::HSVgamma()
00204 {
00205   int    i, vi, j;
00206   double rd, gd, bd, h, s, v, max, min, del, rc, agc, bc;
00207   double f, p, q, t;
00208 
00209   for (i=0; i<numcols; i++) {
00210     /* convert RGB to HSV */
00211     rd = r[i] / 255.0;            /* rd,gd,bd range 0-1 instead of 0-255 */
00212     gd = g[i] / 255.0;
00213     bd = b[i] / 255.0;
00214 
00215     /* compute maximum of rd,gd,bd */
00216     if (rd>=gd) { if (rd>=bd) max = rd;  else max = bd; }
00217            else { if (gd>=bd) max = gd;  else max = bd; }
00218 
00219     /* compute minimum of rd,gd,bd */
00220     if (rd<=gd) { if (rd<=bd) min = rd;  else min = bd; }
00221            else { if (gd<=bd) min = gd;  else min = bd; }
00222 
00223     del = max - min;
00224     v = max;
00225     if (max != 0.0) s = (del) / max;
00226                else s = 0.0;
00227 
00228     h = NOHUE;
00229     if (s != 0.0) {
00230       rc = (max - rd) / del;
00231       agc = (max - gd) / del;
00232       bc = (max - bd) / del;
00233 
00234       if      (rd==max) h = bc - agc;
00235       else if (gd==max) h = 2 + rc - bc;
00236       else if (bd==max) h = 4 + agc - rc;
00237 
00238       h = h * 60;
00239       if (h<0) h += 360;
00240     }
00241 
00242     /* map near-black to black to avoid weird effects */
00243     if (v <= .0625) s = 0.0;
00244 
00245     /* apply gamcr[] function to 'v' (the intensity) */
00246     vi = (int) floor(v * 255);
00247     v = gamcr[vi] / 255.0;
00248 
00249     /* convert HSV back to RGB */
00250     if (s==0.0) { rd = v;  gd = v;  bd = v; }
00251     else {
00252       if (h==360.0) h = 0.0;
00253       h = h / 60.0;
00254       j = (int) floor(h);
00255       f = h - j;
00256       p = v * (1-s);
00257       q = v * (1 - (s*f));
00258       t = v * (1 - (s*(1 - f)));
00259 
00260       switch (j) {
00261       case 0:  rd = v;  gd = t;  bd = p;  break;
00262       case 1:  rd = q;  gd = v;  bd = p;  break;
00263       case 2:  rd = p;  gd = v;  bd = t;  break;
00264       case 3:  rd = p;  gd = q;  bd = v;  break;
00265       case 4:  rd = t;  gd = p;  bd = v;  break;
00266       case 5:  rd = v;  gd = p;  bd = q;  break;
00267       }
00268     }
00269 
00270     r[i] = (int) floor(rd * 255);
00271     g[i] = (int) floor(gd * 255);
00272     b[i] = (int) floor(bd * 255);
00273   }
00274 }
00275