Gray scale conversion

Source code

/*========================================================

  Color To Gray scale conversion 
  (c) QUAGLIOZZI ERIC - 2007

  Version 2.0
  -----------

  Convert color bitmap to gray bitmap
  Formule de conversion utilisée: Y = 0.3R + 0.59G + 0.11B
  Les calculs sont réalisés en virgule fixe 20:12, 32 bits.

  ========================================================

   Usable for low res (72 dpi) and double res (144 dpi)
   bitmap using 8 & 16 bits Colors.
 ---------------------------------------------------------
 | Do not use with other resolutions, may system crash ! |
 ---------------------------------------------------------
*/





//---------------- Macros and constants ------------------

#if defined(_MSC_VER)     // If compiling with VC++...

    #define private        static __inline
    #define longint        __int64
    
#elif defined(__GNUC__)  // If compiling with GCC...

    #define private        static inline
    #define longint        long long int
    
#else

    #error "Unknown Compiler!"
    
#endif

#define chRed   0x0004
#define chGreen 0x0002
#define chBlue  0x0001

//----------------- Types --------------------------------


typedef unsigned long Call68KFuncType(const void * emulStateP,
                                 unsigned long trapOrFunction,
                                 const void * argsOnStackP,
                                 unsigned long argsSizeAndwantA0);

typedef unsigned long NativeFuncType(const void * emulStateP,
                                     void * userData68KP,
                                     Call68KFuncType * call68KFuncP);



typedef struct {
    unsigned char RGB4[1024];
} PalmOSPalette;    


typedef struct {
    unsigned char Index[216];
} PalmOSInverse;    



typedef struct {
    char hb_object_header[14];
    short         Channels;           // Color channels used (R,G,B)
    short          w;                 // Largeur réelle bitmap source
    short         h;                  // Hauteur réelle bitmap source
    short         bitdepth;           // Source: 1 = 8 bits, 2 = 16 bits
    short         density;            // Source: 1 = LowRes, 2 = DoubleRes
    unsigned char * pSData;           // pointeur byte des pixels source
    PalmOSPalette * pPalmOSPalette;   // Pointeur palette palm os
    PalmOSInverse * pPalmOSInverse;   // Pointeur inverse palette palm os
    unsigned long Rc;                 // 0.3  au format 20:12, 32 bits
    unsigned long Gc;                 // 0.59 au format 20:12, 32 bits
    unsigned long Bc;                 // 0.11 au format 20:12, 32 bits
    long          Lum;                // Luminosité au format 20:12, 32 bits, if <0 no light!
} ColorToGrayHB;    




typedef struct _ParamsType
  {
    ColorToGrayHB  * pColorToGrayHB;  // Access to GrayIndex HB++ object
    }
    ParamsType;

#define FixedPoint    12              // We use 20:12 fixed point computation


//----------------- ColorToGray Effect Function ----------


unsigned long ColorToGray(const void * emulStateP, void * userData68KP,
                                         Call68KFuncType * call68KFuncP)
{
  ParamsType    * p;          //pointer to params structure
  ColorToGrayHB * CtG;        //and local copy...just to be easy to write
  PalmOSPalette * PPal;
  PalmOSInverse * InvPal;

  unsigned char * Psource;    //scanline pointer
  short           i, j;       //Loops and index
  short           is;         //Loops and index
  unsigned short  id;
  long            h,w,wl;         
  long   R,G,B;               //Colors
  long   Rp,Gp,Bp;            //coefficients
  long   RGB;
  long   Gray, lm, CIndex;
  short  chan;


  // Do local copy of params

  p=(ParamsType *) userData68KP;
  CtG = p->pColorToGrayHB;
  PPal  = CtG->pPalmOSPalette;
  InvPal = CtG->pPalmOSInverse;
 
  // Perform initialization
  w = CtG->w * CtG->density;
  h = CtG->h * CtG->density;
  wl = w * CtG->bitdepth; if((wl & 0x00000001)!=0) wl++;  
  Psource = CtG->pSData;
  lm = CtG->Lum;
  chan = CtG->Channels;
  
  //Gray scale Index transformation

  for (j=0; j<h; j++)
  {
    // init index source
    is = 0;
    for (i=0; i<w; i++)
    {
      //Get source color
      if (CtG->bitdepth==1)
      {
        //Mode 256 couleurs
        id = (Psource[i] & 0xFF)<<2;
        R=PPal->RGB4[id+1] & 0xFF;
        G=PPal->RGB4[id+2] & 0xFF;
        B=PPal->RGB4[id+3] & 0xFF;
      }
      else
      {
        // true colors
        RGB = ( ((long)(Psource[is]) & 0xFF)<< 8) | (Psource[is+1] & 0xFF);
        R = (RGB >> 8) & 0x00F8;
        G = (RGB >> 3) & 0x00FC;
        B = (RGB << 3) & 0x00F8;
      }
      // Gray = 0.3R + 0.59G + 0.11B
      Gray  = (R * CtG->Rc)>> FixedPoint;
      Gray += (G * CtG->Gc)>> FixedPoint;
      Gray += (B * CtG->Bc)>> FixedPoint;
      if(lm>=0) { Gray=(Gray*lm)>>FixedPoint; }
      if (Gray>255) Gray=255;

      //Set source color
      if (CtG->bitdepth==1)
      { //256 colors
        //Retrouve la couleur indexée la plus proche        
        Gray=((Gray+26)*5)>>8;           // (x*5)>>8 est ~ x/51 pour retrouver index
        CIndex = 0;
        if(chan & chRed) CIndex += (Gray<<5)+(Gray<<2);
        if(chan & chGreen) CIndex += (Gray<<2)+(Gray<<1);
        if(chan & chBlue)  CIndex += Gray;
        Psource[i]= InvPal->Index[CIndex];  // copy new color
      }
      else
      { //65536 colors
        if(chan & chRed) R=Gray>>3; else R=0;
        if(chan & chGreen) G=Gray>>2; else G=0;
        if(chan & chBlue) B=Gray>>3; else B=0;
        Psource[is] = (R<<3)|(G>>3);
        Psource[is+1]= (G<<5)|(B);
      }
      // pixel suivant
      is += CtG->bitdepth;
    }
    // Ligne suivante
    Psource += wl;
  }
  return 0;
}

//========================================================================