/*
 * CDE - Common Desktop Environment
 *
 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
 *
 * These libraries and programs are free software; you can
 * redistribute them and/or modify them under the terms of the GNU
 * Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * These libraries and programs are distributed in the hope that
 * they will be useful, but WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with these libraries and programs; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301 USA
 */
/* $XConsortium: iltruegray.c /main/3 1995/10/23 16:02:03 rswiston $ */
/**---------------------------------------------------------------------
***	
***    (c)Copyright 1991 Hewlett-Packard Co.
***    
***                             RESTRICTED RIGHTS LEGEND
***    Use, duplication, or disclosure by the U.S. Government is subject to
***    restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
***    Technical Data and Computer Software clause in DFARS 252.227-7013.
***                             Hewlett-Packard Company
***                             3000 Hanover Street
***                             Palo Alto, CA 94304 U.S.A.
***    Rights for non-DOD U.S. Government Departments and Agencies are as set
***    forth in FAR 52.227-19(c)(1,2).
***
***-------------------------------------------------------------------*/

/* ======================================================================================
     /ilc/iltruegray.c : Image Library conversion routines fron RGB to grayscale
   =================================================================================== */


#include "ilint.h"
#include "ilpipelem.h"
#include "ilconvert.h"



typedef struct {
    unsigned long   R[256], G[256], B[256]; /* RGB->gray multiply lookup table */
    long            nPixels;                /* width of src/dst images */
    long            srcRowBytes;            /* bytes/row of src image */
    ilPtr           pSrcPixels;             /* ptr to start of src pixels */
    long            dstRowBytes;            /* bytes/row of dst image */
    ilPtr           pDstPixels;             /* ptr to start of dst pixels */
    } ilRGBToGrayRec, *ilRGBToGrayRecPtr;


/* =============================================================================================================================
             ilInitRGBToGray     -   Init() function.
        NOTE: also used for Gray to RGB conversion below !
   ============================================================================================================================= */


static ilError ilInitRGBGrayConversions (
    ilRGBToGrayRecPtr  pPriv,
    ilImageInfo        *pSrcImage,
    ilImageInfo        *pDstImage
    )
{

    pPriv->nPixels = pSrcImage->width;
    pPriv->srcRowBytes = pSrcImage->plane[0].nBytesPerRow;
    pPriv->pSrcPixels = pSrcImage->plane[0].pPixels;
    pPriv->dstRowBytes = pDstImage->plane[0].nBytesPerRow;
    pPriv->pDstPixels = pDstImage->plane[0].pPixels;

    return IL_OK;
}

/* =============================================================================================================================
             ilAddElementRGBGrayConversions - AddElement() function
        Called only for RGB->gray conversion: init RGB lookup/multiply tables in pPriv
   ============================================================================================================================= */

static ilError ilAddElementRGBGrayConversions (
    ilRGBToGrayRecPtr   pPriv,
    unsigned short     *pPalette,           /* not used */
    void               *pOptionData         /* not used */
    )
{
    int        i;

        /*  Init tables, index by R/G/B, which effectively multiply each component
            (0..255) by the NTSC conversion formula: 0.30 * R + 0.587 * G + 0.114 * B,
            except that each value is * 65536 for extra accuracy: the result is
            shifted right by 16 before storing.
            Note that "19660" would probably be more accurate at "19661", but the 
            old code used 19660 and for that little difference it is silly to 
            invalidate the old checksum tests.  Note also that if R/G/B are all = 255
            the result is still <= 255 after the shift right.
        */
    for (i = 0; i < 256; i++) {
        pPriv->R[i] = 19660 * i;
        pPriv->G[i] = 38469 * i;
        pPriv->B[i] = 7471 * i;
        }
    return IL_OK;
}


/* =============================================================================================================================
            ilExecuteRGBToGray    -    Execute() function: convert the given # of src lines.

         Converts RGB images to a grayscale with format byte per pixel.
            Input image:   uncompressed IL_DES_RGB, IL_FORMAT_3BYTE_PIXEL
            Output image:  uncompressed IL_GRAY, 255 levels, IL_FORMAT_BYTE.

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

static ilError ilExecuteRGBToGray  (
    ilExecuteData          *pData,
    long                    dstLine,
    long                   *pNLines
    )
{
ilRGBToGrayRecPtr  pPriv;
long                        srcnbytes, dstnbytes;
ilPtr              psrcline, pdstline;
ilPtr              psrc, pdst;
long               nLines, nPixels;
INT32		    i;



    pPriv = (ilRGBToGrayRecPtr)pData->pPrivate;
    srcnbytes = pPriv->srcRowBytes;
    psrcline = pPriv->pSrcPixels + pData->srcLine * srcnbytes;
    dstnbytes = pPriv->dstRowBytes;
    pdstline = pPriv->pDstPixels + dstLine * dstnbytes;

    if (pPriv->nPixels < 0)  return 0;

    nLines = *pNLines;
    if (nLines <= 0) return 0;

    while ( nLines--  > 0 ) {

          psrc = psrcline;
          pdst = pdstline;
          nPixels = pPriv->nPixels;

          /*  --    grayscale from:     Y  =   0.30red  + 0.587green + 0.114blue    */
          while ( nPixels--  >  0 ) {
                i = pPriv->R[*psrc++];
                i += pPriv->G[*psrc++];
                i += pPriv->B[*psrc++];
                *pdst++ = i >> 16;
                }

          psrcline += srcnbytes;
          pdstline += dstnbytes;
    }


    return IL_OK;
}


/* =============================================================================================================================
          ilRGBToGray          -    Table exported to ilConvert(), declared in /ilc/ilconvert.h 
   ============================================================================================================================= */

IL_PRIVATE ilConvertRec _ilRGBToGray = {
    IL_NPF,                                     /* CheckFormat() */
    IL_STD_FORMAT_3BYTE_PIXEL,                  /* srcFormatCode */
    ilAddElementRGBGrayConversions,             /* AddElement() */
    IL_DES_GRAY,                                /* pDstDes */
    IL_FORMAT_BYTE,                             /* pDstFormat */
    sizeof (ilRGBToGrayRec),                    /* nBytesPrivate */
    ilInitRGBGrayConversions,                   /* Init() */
    IL_NPF,                                     /* Cleanup() */
    IL_NPF,                                     /* Destroy() */
    ilExecuteRGBToGray                          /* Execute() */
    };


/* =====================================================================================
                                   GRAY TO RGB
        Convert byte/pixel gray to 3byte/pixel rgb.

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

static ilError ilExecuteGrayToRGB  (
    ilExecuteData          *pData,
    long                    dstLine,
    long                   *pNLines
    )
{
ilRGBToGrayRecPtr           pPriv;
long               nLinesM1, nPixelsM1;
long                        srcRowBytes, dstRowBytes, nPixelsM1Init;
ilPtr                       pSrcLine, pDstLine;
ilPtr              pSrc, pDst;
ilByte             byte;

    pPriv = (ilRGBToGrayRecPtr)pData->pPrivate;
    nPixelsM1Init = pPriv->nPixels - 1;
    nLinesM1 = *pNLines - 1;
    if ((nLinesM1 < 0) || (nPixelsM1Init < 0))
        return IL_OK;

    srcRowBytes = pPriv->srcRowBytes;
    pSrcLine = pPriv->pSrcPixels + pData->srcLine * srcRowBytes;
    dstRowBytes = pPriv->dstRowBytes;
    pDstLine = pPriv->pDstPixels + dstLine * dstRowBytes;

        /*  Simply replicate each gray byte 3 times to form RGB - tough, eh?
            However if black not zero must invert the gray byte.
        */
    if (pData->pSrcImage->pDes->blackIsZero) {
        do {
            pSrc = pSrcLine;
            pSrcLine += srcRowBytes;
            pDst = pDstLine;
            pDstLine += dstRowBytes;
            nPixelsM1 = nPixelsM1Init;
            do {
                byte = *pSrc++;
                *pDst++ = byte;
                *pDst++ = byte;
                *pDst++ = byte;
                } while (--nPixelsM1 >= 0);
            } while (--nLinesM1 >= 0);
        }
    else {
        do {
            pSrc = pSrcLine;
            pSrcLine += srcRowBytes;
            pDst = pDstLine;
            pDstLine += dstRowBytes;
            nPixelsM1 = nPixelsM1Init;
            do {
                byte = ~*pSrc++;
                *pDst++ = byte;
                *pDst++ = byte;
                *pDst++ = byte;
                } while (--nPixelsM1 >= 0);
            } while (--nLinesM1 >= 0);
        }

    return IL_OK;
}


/* =====================================================================================
          ilGrayToRGB  -    Table exported to ilConvert(), declared in /ilc/ilconvert.h 
   ==================================================================================== */

IL_PRIVATE ilConvertRec _ilGrayToRGB = {
    IL_NPF,                                     /* CheckFormat() */
    IL_STD_FORMAT_BYTE,                         /* srcFormatCode */
    IL_NPF,                                     /* AddElement() */
    IL_DES_RGB,                                 /* pDstDes */
    IL_FORMAT_3BYTE_PIXEL,                      /* pDstFormat */
    sizeof (ilRGBToGrayRec),                    /* nBytesPrivate */
    ilInitRGBGrayConversions,                   /* Init() */
    IL_NPF,                                     /* Cleanup() */
    IL_NPF,                                     /* Destroy() */
    ilExecuteGrayToRGB                          /* Execute() */
    };



