/*******************************************************************************
 *
 * Copyright (c) 1998, Tortuga Technologies Pty Ltd. All rights reserved.
 * 
 * This is unpublished proprietary source code of Tortuga Technologies.
 * The copyright notice above does not evidence any actual or intended
 * publication of such source code.
 * 
 *******************************************************************************
 * 
 * Filename:    $Id: cfa2bmp.html,v 1.1 2002/04/22 10:03:47 jill Exp $
 * 
 * Description: Converts a 96x72x4 bit Bayer Pattern CFA to a 96x72 bitmap
 * 
 * History:
 * --------
 * $Log: cfa2bmp.html,v $
 * Revision 1.1  2002/04/22 10:03:47  jill
 * Initial import
 *
 * Revision 1.2  1998/05/07 10:59:15  graham
 * Made common header for functions & increased buffer size to BUFSIZ*15
 *
 * Revision 1.1  1998/04/28 12:17:22  graham
 * Initial version
 *
 *
 ******************************************************************************/

/* system includes */

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>


/* local includes */

#include "cfa2.h"


/* local definitions */

#define WIDTH    96
#define HEIGHT   72


/******************************************************************************/
/*                                                                            */
/* Unit:        cfa2bmp()                                                     */
/*                                                                            */
/* Description: Converts a 96x72x4bit Bayer Pattern CFA into a 96x72 rgb      */
/*              bitmap.                                                       */
/*                                                                            */
/*              The CFA is first pixel replicated into three colour arrays.   */
/*              Missing pixels are then re-created through interpolating the  */
/*              pixels that are present.  The data is then fed through a      */
/*              1.7 gamma factor array which lightens the image.              */
/*                                                                            */
/* Notes:       This routine was developed upon previous work carried out by  */
/*              "Stephane Charette" <charette@writeme.com>                    */
/*              "Ed Hamrick"        http://www.hamrick.com/                   */
/*                                                                            */
/* Parameters:  cfa  -  address of buffer containing the raw cfa data         */
/*              bmp  -  address of buffer in which to place the converted     */
/*                      bitmap                                                */
/*                                                                            */
/* Globals:     None.                                                         */
/*                                                                            */
/* Returns:     None.                                                         */
/*                                                                            */
/******************************************************************************/
void cfa2bmp( unsigned char *cfa, unsigned char *bmp )
{
    unsigned char buf[96][72];  /* full sized buffer to work with  */

    unsigned char red[96][72];  /* rgb buffers to interpolate into */
    unsigned char blu[96][72];
    unsigned char gre[96][72];

    unsigned char ch;           /* local useful variables          */
    register int i, x, y;


    /* hardcoded ".bmp" header 96x72, 24 bits */

    static unsigned char bmphead[] = {
        0x42, 0x4D, 0x36, 0x24, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
        0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x48, 0x00,
        0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };


    /* gamma correction table for gamma = 1.7 used */
    /* to lighten the finished thumbnail image     */

    static unsigned char gamma[] = {
        0, 10, 15, 19, 22, 25, 28, 31, 33, 36, 38, 40, 42, 44, 46, 48,
        50, 52, 54, 55, 57, 59, 60, 62, 64, 65, 67, 68, 70, 71, 72, 74,
        75, 77, 78, 79, 81, 82, 83, 84, 86, 87, 88, 89, 91, 92, 93, 94,
        95, 97, 98, 99,100,101,102,103,105,106,107,108,109,110,111,112,
        113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
        129,130,131,132,133,134,135,135,136,137,138,139,140,141,142,143,
        144,144,145,146,147,148,149,150,150,151,152,153,154,155,156,156,
        157,158,159,160,160,161,162,163,164,164,165,166,167,168,168,169,
        170,171,172,172,173,174,175,175,176,177,178,178,179,180,181,181,
        182,183,184,184,185,186,187,187,188,189,190,190,191,192,192,193,
        194,195,195,196,197,197,198,199,199,200,201,202,202,203,204,204,
        205,206,206,207,208,208,209,210,210,211,212,212,213,214,214,215,
        216,216,217,218,218,219,220,220,221,222,222,223,224,224,225,226,
        226,227,227,228,229,229,230,231,231,232,233,233,234,234,235,236,
        236,237,238,238,239,239,240,241,241,242,242,243,244,244,245,245,
        246,247,247,248,248,249,250,250,251,251,252,253,253,254,254,255
    };


    /* split each byte into two in a local buffer */

    for( i = 0, y = 0; y < HEIGHT; y++ )
    {
        for( x = 0; x < WIDTH; x+=2 )
        {
            buf[x  ][y] = cfa[i  ] >> 4;
            buf[x+1][y] = cfa[i++] & 0x0F;
        }
    }


    /* replicate pixels from the initial buffer into */
    /* red, blue and green matrices...               */

    for( y = 0; y < HEIGHT; y += 2 )
    {
        for( x = 0; x < WIDTH; x += 2 )
        {
            /* grGRgrGR  :=  ggGGggGG  rrRRrrRR  bbBBbbBB */
            /* bgBGbgBG  :=  ggGGggGG  rrRRrrRR  bbBBbbBB */
            /* GRGRGRGR  :=  ...                          */

            gre[x  ][y  ] = buf[x  ][y  ];
            gre[x+1][y  ] = buf[x  ][y  ];
            gre[x  ][y+1] = buf[x+1][y+1];
            gre[x+1][y+1] = buf[x+1][y+1];

            red[x  ][y  ] = buf[x+1][y  ];
            red[x+1][y  ] = buf[x+1][y  ];
            red[x  ][y+1] = buf[x+1][y  ];
            red[x+1][y+1] = buf[x+1][y  ];

            blu[x  ][y  ] = buf[x  ][y+1];
            blu[x+1][y  ] = buf[x  ][y+1];
            blu[x  ][y+1] = buf[x  ][y+1];
            blu[x+1][y+1] = buf[x  ][y+1];
        }
    }


    /* bailing out here and printing the bitmap produces     */
    /* a fine but grainy image which becomes blocky on       */
    /* enlargement, I guess it depends on the requirements   */


    /* next we interpolate the data trying to recreate the   */
    /* pixels that are missing adding this to the replicated */
    /* data                                                  */


    /* compute the interpolated red data */

    for ( y = 2; y < HEIGHT-2; y += 2 )
    {
        for ( x = 3; x < WIDTH-2; x += 2 )
        {
            /* get the left, bottom, corner red pixels */

            unsigned char r, rl, rb, rc;

            r  = buf[x  ][y  ];
            rl = buf[x-2][y  ];
            rb = buf[x  ][y+2];
            rc = buf[x-2][y+2];

            red[x-1][y  ] = (r + rl          ) / 2;
            red[x  ][y+1] = (r      + rb     ) / 2;
            red[x-1][y+1] = (r + rl + rb + rc) / 4;
        }
    }


    /* compute the interpolated green data */

    for ( y = 2; y < HEIGHT-2; y += 2 )
    {
        for ( x = 3; x < WIDTH-2; x += 2 )
        {
            /* get the left, right, top, bottom green pixels */

            unsigned char gl, gr, gt, gb;

            gl = buf[x-1][y  ];
            gr = buf[x+1][y  ];
            gt = buf[x  ][y-1];
            gb = buf[x  ][y+1];

            gre[x][y] = (gl + gr + gt + gb) / 4;
        }
    }

    for ( y = 3; y < HEIGHT-2; y += 2 )
    {
        for ( x = 2; x < WIDTH-2; x += 2 )
        {
            /* get the left, right, top, bottom green pixels */

            unsigned char gl, gr, gt, gb;

            gl = buf[x-1][y  ];
            gr = buf[x+1][y  ];
            gt = buf[x  ][y-1];
            gb = buf[x  ][y+1];
      
            gre[x][y] = (gl + gr + gt + gb) / 4;
        }
    }


    /* compute the interpolated blue data */

    for ( y = 3; y < HEIGHT-2; y += 2 )
    {
        for ( x = 2; x < WIDTH-2; x += 2 )
        {
            /* get the right, top, corner blue pixels */

            unsigned char b, br, bt, bc;

            b  = buf[x  ][y  ];
            br = buf[x+2][y  ];
            bt = buf[x  ][y-2];
            bc = buf[x+2][y-2];

            blu[x+1][y  ] = (b + br          ) / 2;
            blu[x  ][y-1] = (b      + bt     ) / 2;
            blu[x+1][y-1] = (b + br + bt + bc) / 4;
        }
    }


    /* bailing out here and printing the bitmap produces a */
    /* much smoother image, perhaps even a little blurry,  */
    /* I guess this shows the quality of the interpolation */
    /* algorithm, if I get time I'd work more on this ...  */


    /* copy the header to the user supplied buffer */

    (void) memcpy( bmp, bmphead, sizeof(bmphead) );


    /* now copy out our rgb pixels using a handy dandy */
    /* gamma array which lightens and lifts the        */
    /* thumbnail image                                 */

    i = sizeof(bmphead);

    for( y = HEIGHT-1; y >= 0; y-- )
    {
        for( x = 0; x < WIDTH; x++ )
        {
            ch = blu[x][y];
            bmp[i++] = gamma[ (ch * 16) + ch ];

            ch = gre[x][y];
            bmp[i++] = gamma[ (ch * 16) + ch ];

            ch = red[x][y];
            bmp[i++] = gamma[ (ch * 16) + ch ];
        }
    }


    return;
}


#ifdef _TOOL
/******************************************************************************/
/*                                                                            */
/* Unit:        main()                                                        */
/*                                                                            */
/* Description: ifdef'd main() to test the cfa2bmp function above             */
/*                                                                            */
/* Notes:       This was a real pig to develop                                */
/*                                                                            */
/* Parameters:  argv[1]  -  filename of raw bayer pattern cfa data            */
/*              argv[2]  -  filename in which to place the bitmap             */
/*                                                                            */
/* Globals:     None                                                          */
/*                                                                            */
/* Returns:    -1  -  Bad argument                                            */
/*              0  -  All converted                                           */
/*                                                                            */
/******************************************************************************/
int main( int argc, char *argv[] )
{
    int fd;

    unsigned char buffer[3456];
    unsigned char bitmap[20790];


    /* check the args */

    if ( (argv[1] == NULL) || (argv[2] == NULL) )
    {
        (void) printf( "Usage: %s filename.cfa filename.bmp\n", argv[0] );
        exit( -1 );
    }


    /* read in the thumbnail data */

    fd = open( argv[1], O_RDONLY );

    if ( fd == -1 )
    {
        (void) printf( "%s: failed to open \"%s\"", argv[0], argv[1] );
        exit( -1 );
    }
    (void) read( fd, buffer, 3456 );
    (void) close( fd );


    /* convert the sucker */

    cfa2bmp( buffer, bitmap );


    /* and write it out */

    fd = open( argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666 );

    if ( fd == -1 )
    {
        (void) printf( "%s: failed to open \"%s\"", argv[0], argv[2] );
        exit( -1 );
    }
    (void) write( fd, bitmap, 20790 );
    (void) close( fd );


    /* phew ! that was hard yakka */

    exit( 0 );
}
#endif