/**************************************************************************
 *{@C
 *      Copyright:      1988-2024 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         FileFormats
 *      Filename:       FF_ImageUtil.c
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    Miscellaneous utility functions to scale, 
 *                      gamma correct and color correct pixel images.
 *
 *      Additional documentation:
 *                      None.
 *
 *      Exported functions:
 *                      FF_ImgGenScaleTable
 *                      FF_ImgGenGammaTable
 *                      FF_ImgApplyGammaUByte
 *                      FF_ImgApplyGammaFloat
 *                      FF_ImgGenColorMatrix
 *                      FF_ImgApplyColorCorrect
 *
 **************************************************************************/

#include <stdio.h>

#include "UT_Compat.h"
#include "UT_Macros.h"
#include "UT_Error.h"
#include "UT_Memory.h"

#include "FF_Image.h"
#include "FF_ImagePrivate.h"

#if defined (CC_IS_VC6)
    /* Optimizer bug in VC++ 5.0 and 6.0. 
       Switch off global optimization for this function only. 
    */
    #pragma optimize("g", off)
#endif

/***************************************************************************
 *[@e
 *      Name:           FF_ImgGenScaleTable
 *
 *      Usage:          Create the lookup table for scaling an image
 *                      read from a pixel file.
 *
 *      Synopsis:       UT_Bool FF_ImgGenScaleTable
 *                              (FF_ImgFileDesc *px_f, FF_ImgDesc *img)
 *
 *      Description:    Initializes the scaling lookup table in the
 *                      "pixprivate" part of pixel file "px_f", so that
 *                      the contents of the file can be scaled to the
 *                      dimensions of image "img", on the fly, while
 *                      the file is read.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool FF_ImgGenScaleTable (FF_ImgFileDesc *px_f, FF_ImgDesc *img)
{
    pixfile *pf;
    scaletab *st;
    Int32 i, j, k, umax, xmax;
    Float32 mx, my, u1, u2;

    pf = px_f->pixprivate;
    umax = px_f->desc.width - 1;
    xmax = img->desc.width - 1;
    mx = (Float32) px_f->desc.width / (Float32) img->desc.width;
    my = (Float32) px_f->desc.height / (Float32) img->desc.height;

    /* Determine the size of the lookup table. */

    pf->xtabsize = 0;
    for (i = 0; i <= xmax; ++i) {
        u1 = i * mx;
        u2 = (i + 1) * mx;
        for (j = (Int32) u1; j <= (Int32) u2; ++j)
            ++pf->xtabsize;
    }

    /* Allocate memory for the table. */

    if (!(pf->xtable = UT_MemPermArray (pf->xtabsize, scaletab))) {
        return UT_False;
    }

    /* Initialize the table. */

    k = 0;
    for (i = 0; i <= xmax; ++i) {
        u1 = i * mx;
        u2 = (i + 1) * mx;
        for (j = (Int32) u1; j <= (Int32) u2; ++j) {
            st = pf->xtable + k;
            st->src = UT_MAX (0, UT_MIN (j, umax));
            st->dest = i;
            st->weight = UT_MIN (u2, (Float32) (j + 1)) -
                         UT_MAX (u1, (Float32) j);
            ++k;
        }
    }
    pf->my = my;

    /* Compute the area of a single pixel. */

    pf->pxarea = 1.0 / (mx * my);
    return UT_True;
}

#if defined (CC_IS_VC6)
    /* Optimizer bug in VC++ 5.0 and 6.0. 
       Switch on global optimization again. 
    */
    #pragma optimize("g", on)
#endif

/***************************************************************************
 *[@e
 *      Name:           FF_ImgGenGammaTable
 *
 *      Usage:          Allocate and initialize a gamma correction table.
 *
 *      Synopsis:       UT_Bool FF_ImgGenGammaTable
 *                              (FF_ImgFileDesc *px_f, FF_ImgDesc *img)
 *
 *      Description:    A lookup table for gamma correcting image "img" on
 *                      the fly, while reading it from or writing it to
 *                      to pixel file "px_f", is allocated and initialized.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool FF_ImgGenGammaTable (FF_ImgFileDesc *px_f, FF_ImgDesc *img)
{
    pixfile *pf;
    Float32 factor;

    pf = px_f->pixprivate;
    pf->gamma = UT_True;
    if (!(pf->gammatable = UT_MemPermArray (256, Int16))) {
        return UT_False;
    }
    if (pf->readfile)
        factor = px_f->desc.gamma / img->desc.gamma;
    else
        factor = img->desc.gamma / px_f->desc.gamma;
    UT_ImgGammaTable (factor, 256, 32767, pf->gammatable);
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           FF_ImgApplyGammaUByte
 *
 *      Usage:          Gamma-correct a scanline in UByte format.
 *
 *      Synopsis:       void FF_ImgApplyGammaUByte
 *                              (FF_ImgFileDesc *px_f, UInt8 *data)
 *
 *      Description:    Gamma-correct a scanline of pixel data
 *                      in UInt8 format.
 *
 *      Return value:   None.
 *
 *      See also:
 *
 ***************************************************************************/

void FF_ImgApplyGammaUByte (FF_ImgFileDesc *px_f, UInt8 *data)
{
    pixfile *pf;
    Int16 *gammatable;
    UInt8 *stop;

    pf = px_f->pixprivate;
    gammatable = pf->gammatable;
    stop = data + px_f->desc.width;
    while (data < stop) {
        *data = gammatable[(UInt32) * data] >> 7;
        ++data;
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           FF_ImgApplyGammaFloat
 *
 *      Usage:          Gamma-correct a scanline in Float format.
 *
 *      Synopsis:       void FF_ImgApplyGammaFloat
 *                              (FF_ImgFileDesc *px_f, Float32 *data)
 *
 *      Description:    Gamma-correct a scanline of pixel data
 *                      in Float32 format.
 *
 *      Return value:   None.
 *
 *      See also:
 *
 ***************************************************************************/

void FF_ImgApplyGammaFloat (FF_ImgFileDesc *px_f, Float32 *data)
{
    pixfile *pf;
    Int16 *gammatable;
    Float32 *stop, s, t;
    Int32 i, j;

    pf = px_f->pixprivate;
    gammatable = pf->gammatable;
    stop = data + px_f->desc.width;
    while (data < stop) {
        if (*data < 0.0 || *data > 1.0) {
            *data *= 255.0;
            i = (Int32) * data;
            j = UT_MIN (i + 1, 255);
            s = *data - (Float32) i;
            t = 1.0 - s;
            *data = (t * gammatable[i] + s * gammatable[j]) / 32767.0;
        }
        ++data;
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           FF_ImgGenColorMatrix
 *
 *      Usage:          Initialize the matrix for color correction.
 *
 *      Synopsis:       UT_Bool FF_ImgGenColorMatrix
 *                              (FF_ImgFileDesc *px_f, FF_ImgDesc *img)
 *
 *      Description:    The matrix for color-correcting image "img" on the
 *                      fly, while reading it from or writing it to pixel file
 *                      "px_f", is initialized.
 *
 *                      Note: Color correction is not yet implemented,
 *                      the color correction matrix always describes the
 *                      identical transformation.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:
 *
 ***************************************************************************/

UT_Bool FF_ImgGenColorMatrix (FF_ImgFileDesc *px_f, FF_ImgDesc *img)
{
    pixfile *pf;

    pf = px_f->pixprivate;
    pf->cm[0][0] = 1.0;
    pf->cm[0][1] = 0.0;
    pf->cm[0][2] = 0.0;
    pf->cm[1][0] = 0.0;
    pf->cm[1][1] = 1.0;
    pf->cm[1][2] = 0.0;
    pf->cm[2][0] = 0.0;
    pf->cm[2][1] = 0.0;
    pf->cm[2][2] = 1.0;
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           FF_ImgApplyColorCorrect
 *
 *      Description:    Perform color correction on a scanline.
 *
 *      Synopsis:       void FF_ImgApplyColorCorrect (FF_ImgFileDesc *px_f)
 *
 *      Usage:          Perform color correction on the red, green and
 *                      blue channels of the scan line stored in the
 *                      pixel buffer in the private part of a pixel file.
 *
 *                      Note: Color correction is not yet implemented;
 *                      this function is only a dummy.
 *
 *      Return value:   None.
 *
 *      See also:
 *
 ***************************************************************************/

void FF_ImgApplyColorCorrect (FF_ImgFileDesc *px_f)
{
    (void)px_f;
    return;
}
