/**************************************************************************
 *{@C
 *      Copyright:      1988-2023 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         Utilities
 *      Filename:       UT_Image.c
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    Basic functionality needed for image processing package.
 *
 *      Additional documentation:
 *                      None.
 *
 *      Exported functions:
 *                      UT_ImgDitherTable
 *                      UT_ImgGammaTable
 *                      UT_ImgMakeNoiseGen
 *                      UT_ImgNoise
 *                      UT_ImgRawWriteHeader
 *                      UT_ImgRawWriteUInt8Header
 *                      UT_ImgRawWriteUInt16Header
 *                      UT_ImgRawWriteFloat32Header
 *                      UT_ImgRawWriteUInt8Scan
 *                      UT_ImgRawWriteUInt16Scan
 *                      UT_ImgRawWriteFloat32Scan
 *                      UT_ImgRawWriteUInt8Chan
 *                      UT_ImgRawWriteUInt16Chan
 *                      UT_ImgRawWriteFloat32Chan
 *
 **************************************************************************/

#include <stdio.h>
#include <string.h>
#include <math.h>

#include "UT_Compat.h"
#include "UT_Const.h"
#include "UT_Macros.h"
#include "UT_Error.h"
#include "UT_Random.h"
#include "UT_Portable.h"
#include "UT_FileIO.h"

#include "UT_Image.h"

/***************************************************************************
 *[@e
 *      Name:           UT_ImgDitherTable
 *
 *      Usage:          Fill a matrix with an error pattern to dither images.
 *
 *      Synopsis:       void UT_ImgDitherTable (Int16 tbl[], Int32 sz, Int32 maxval)
 *
 *      Description:    "tbl" must be a pointer to a 1-dimensional vector
 *                      of (1 << sz) * (1 << sz) Int16's. The table will be
 *                      filled with numbers from 0 to "maxval". "maxval" should
 *                      be less than the number of elements in "tbl".
 *
 *                      For a detailed description, see
 *                              David F. Rogers
 *                              "Procedural elements for Computer Graphics"
 *                              McGraw-Hill, 1985
 *
 *      Return value:   None.
 *
 *      See also:
 *
 ***************************************************************************/

void UT_ImgDitherTable (Int16 tbl[], Int32 sz, Int32 maxval)
{
    Int32 i, j, k, size, t;

    /* Fill the table with numbers from 0 to (1 << (sz << 1) - 1. */
    size = 1 << sz;
    dtelement (tbl, sz, 0, 0) = 0;
    for (k = 1; k < size; k <<= 1) {
        for (i = 0; i < k; ++i) {
            for (j = 0; j < k; ++j) {
                t = (dtelement (tbl, sz, i, j) <<= 2);
                dtelement (tbl, sz, i+k, j+k) = 1+t;
                dtelement (tbl, sz, i+k, j) = 2+t;
                dtelement (tbl, sz, i, j+k) = 3+t;
            }
        }
    }

    /* Scale the numbers so that they go from 0 to maxval. */
    k = (1 << (sz << 1)) - 1;
    for (i = 0; i < size; ++i) {
        for (j = 0; j < size; ++j) {
            dtelement (tbl, sz, i, j) =
                    ((maxval+1) * dtelement (tbl, sz, i, j)) / (k+1);
        }
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgGammaTable
 *
 *      Usage:          Create a gamma-correction lookup table.
 *
 *      Synopsis:       void UT_ImgGammaTable
 *                              (Float32 gamma, Int32 n,
 *                               Int32 maxval, Int16 g[])
 *
 *      Description:    G must point to a table of n elements
 *                      which are set by UT_ImgGammaTable so that 
 *                      g[i] = maxval * pow (i / (n-1), gamma).
 *
 *                      For more information about gamma-correction, see
 *                              David F. Rogers
 *                              "Procedural Elements for Computer Graphics"
 *                              McGraw-Hill 1985
 *
 *      Return value:   None.
 *
 *      See also:
 *
 ***************************************************************************/

void UT_ImgGammaTable (Float32 gamma, Int32 n, Int32 maxval, Int16 g[])
{
    Int32 i;
    Float32 fn, fmaxval;

    fn = (Float32)(n - 1);
    fmaxval = (Float32)maxval;
    for (i = 0; i < n; ++i) {
        g[i] = (Int32)(fmaxval * pow ((Float32)i / fn, gamma));
    }
    return;
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgMakeNoiseGen
 *
 *      Usage:          Initialize a noise generator.
 *
 *      Synopsis:       void UT_ImgMakeNoiseGen (Int32 seed, UT_ImgNoiseGen *gen)
 *
 *      Description:    A pseudo-random number generator is loaded with seed
 *                      value "seed", and the sequence of numbers produced
 *                      by the random number generator is used to initialize
 *                      noise generator "gen".
 *
 *      Return value:   None.
 *
 *      See also:       UT_ImgNoise
 *
 ***************************************************************************/

void UT_ImgMakeNoiseGen (Int32 seed, UT_ImgNoiseGen *gen)
{
    Int32        i, j;
    UT_RandomGen rgen;

    rgen = UT_RandomNew (seed);
    for (i = 0; i < UT_ImgNoiseSize; ++i) {
        gen->hashtable[i] = i;
    }
    for (i = UT_ImgNoiseSize - 1; i > 0; --i) {
        j = UT_RandomGetInt32 (rgen, 0, MaxInt32) % i;
        UT_SWAP (gen->hashtable[i], gen->hashtable[j], Int16);
    }
    for (i = 0; i < UT_ImgNoiseSize + 3; ++i) {
        gen->randtable[i] = UT_RandomGetFloat32 (rgen, -1.0, 1.0);
    }
    UT_RandomDelete (rgen);
    return;
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgNoise
 *
 *      Usage:          Get a noise sample from a noise generator.
 *
 *      Synopsis:       Float32 UT_ImgNoise
 *                              (const UT_ImgNoiseGen *gen,
 *                              Int32 p, Float32 x, Float32 y, Float32 z)
 *
 *      Description:    The routines in this file compute stochastic "noise
 *                      functions" which map three-dimensional points into
 *                      pseudorandom scalar values. These pseudo-random
 *                      values are narrowly limited within a band of spatial
 *                      frequencies.
 *
 *                      For a detailed description, see
 *
 *                      Alain Fournier,
 *                      "Random processes in Computer Graphics"
 *                      in
 *                      David F. Rogers, Rae A. Earnshaw (Editors),
 *                      "State of the Art in Computer Graphics:
 *                      Visualization and Modeling",
 *                      Springer Verlag, New York, 1991,
 *                      pp. 114-149
 *
 *      Return value:   The value of the noise function defined by
 *                      noise generator "gen" at position (x, y, z).
 *                      The noise function is periodic in x, y and z
 *                      direction, with a period length of (1 << p).
 *                      The period length must not be greater than
 *                      "UT_ImgNoiseSize".
 *
 *      See also:       UT_ImgMakeNoiseGen
 *
 ***************************************************************************/

Float32 UT_ImgNoise (const UT_ImgNoiseGen *gen, Int32 p, 
                     Float32 x, Float32 y, Float32 z)
{
    Int32   m, i, hash, ix, iy, iz, jx=0, jy=0, jz=0;
    Float64 tmp, sum, weight=0, sx, sy, sz, tx, ty, tz;

    m = (1 << p) - 1;
    ix = x >= 0.0? (Int32)x: -1 - (Int32)(-x);
    tmp = x - ix;
    sx = tmp * tmp * (3.0 - 2.0 * tmp);
    tx = 1.0 - sx;
    iy = y >= 0.0? (Int32)y: -1 - (Int32)(-y);
    tmp = y - iy;
    sy = tmp * tmp * (3.0 - 2.0 * tmp);
    ty = 1.0 - sy;
    iz = z >= 0.0? (Int32)z: -1 - (Int32)(-z);
    tmp = z - iz;
    sz = tmp * tmp * (3.0 - 2.0 * tmp);
    tz = 1.0 - sz;
    sum = 0.5;
    for (i = 0; i < 8; ++i) {
        switch (i) {
        case 0:
            weight = tx * ty * tz;
            jx = ix;
            jy = iy;
            jz = iz;
            break;
        case 1:
            weight = sx * ty * tz;
            jx = ix + 1;
            jy = iy;
            jz = iz;
            break;
        case 2:
            weight = tx * sy * tz;
            jx = ix;
            jy = iy + 1;
            jz = iz;
            break;
        case 3:
            weight = sx * sy * tz;
            jx = ix + 1;
            jy = iy + 1;
            jz = iz;
            break;
        case 4:
            weight = tx * ty * sz;
            jx = ix;
            jy = iy;
            jz = iz + 1;
            break;
        case 5:
            weight = sx * ty * sz;
            jx = ix + 1;
            jy = iy;
            jz = iz + 1;
            break;
        case 6:
            weight = tx * sy * sz;
            jx = ix;
            jy = iy + 1;
            jz = iz + 1;
            break;
        case 7:
            weight = sx * sy * sz;
            jx = ix + 1;
            jy = iy + 1;
            jz = iz + 1;
            break;
        }

        hash = gen->hashtable
            [gen->hashtable[gen->hashtable[jx & m] ^ (jy & m)] ^ (jz & m)];

        sum += weight * (gen->randtable[hash] * 0.5 +
                         gen->randtable[hash + 1] * (x - jx) +
                         gen->randtable[hash + 2] * (y - jy) +
                         gen->randtable[hash + 3] * (z - jz));
    }
    return UT_MAX (0.0, UT_MIN (sum, 1.0));
}

/*
 * Structures and definitons needed for the RAW image format.
 */

/* Header fields. */
#define strMagic     "Magic=%s"
#define strWidth     "Width=%d"
#define strHeight    "Height=%d"
#define strNumChan   "NumChan=%d"
#define strByteOrder "ByteOrder=%s"
#define strScanOrder "ScanOrder=%s"
#define strPixelType "PixelType=%s"

/* Header fields possible values. */
#define strIntel    "Intel"
#define strMotorola "Motorola"
#define strTopDown  "TopDown"
#define strBottomUp "BottomUp"

#define strUnknown  "Unknown"

#define BOTTOM_UP   0
#define TOP_DOWN    1
#define INTEL       0
#define MOTOROLA    1
#define TYPE_FLOAT  0
#define TYPE_USHORT 1
#define TYPE_UBYTE  2
#define HEADLEN     20
#define MAXSIZE    100

static UT_Bool readError (FILE *fp)
{
    if (feof (fp)) {
        UT_ErrSetNum (UT_ErrUnexpEof, "UT_ImgRawRead");
    } else {
        UT_ErrSetNum (UT_ErrFromOs (), "UT_ImageRawRead");
    }
    return UT_False;
}

static UT_Bool writeError (FILE *fp)
{
    (void) fp;
    UT_ErrSetNum (UT_ErrFromOs (), "UT_ImageRawWrite");
    return UT_False;
}

static UT_Bool checkMagic (const char *magic)
{
    if (strncmp (magic, "RAW", 3) != 0) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Invalid value for header field Magic: \"%s\"."
                                "Must be \"RAW\"", magic);
        return UT_False;
    }
    return UT_True;
}

static UT_Bool checkPixelType (const char *pixelType)
{
    if (!(strncmp (pixelType, UT_ImgRawTypeFloat, strlen (UT_ImgRawTypeFloat)) == 0) &&
         (strncmp (pixelType, UT_ImgRawTypeShort, strlen (UT_ImgRawTypeShort)) == 0) &&
         (strncmp (pixelType, UT_ImgRawTypeByte,  strlen (UT_ImgRawTypeByte))  == 0)) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Invalid value for header field PixelType: \"%s\"."
                      "Must be \"%s\", \"%s\" or \"%s\"",
                      pixelType, UT_ImgRawTypeFloat, 
                      UT_ImgRawTypeShort, UT_ImgRawTypeByte);
        return UT_False;
    }
    return UT_True;
}

static UT_Bool checkNumChans (UInt32 nChans)
{
    if (nChans != 1 && nChans != 3) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Invalid value for header field NumChan: %d."
                                "Must be 1 or 3", nChans);
        return UT_False;
    }
    return UT_True;
}

static UT_Bool checkHeight (UInt32 height)
{
    if (height < 1) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Invalid value for header field Height: %d."
                                "Must be greater than zero", height);
        return UT_False;
    }
    return UT_True;
}

static UT_Bool checkWidth (UInt32 width)
{
    if (width < 1) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Invalid value for header field Width: %d."
                                "Must be greater than zero", width);
        return UT_False;
    }
    return UT_True;
}

static UT_Bool readHeaderLine (FILE *fp, char *buf)
{
    int c;
    char *bufPtr, *bufEndPtr;
    UT_Bool success = UT_False;
 
    bufPtr    = buf;
    bufEndPtr = buf + MAXSIZE;

    #if defined (DEBUG_LOCAL)
        printf ("readHeaderLine\n"); fflush (stdout);
    #endif

    while ((c = fgetc (fp) != EOF) && bufPtr < bufEndPtr) {
        if (c == '\n') {
            success = UT_True;
            break;
        }
        *bufPtr = c;
        bufPtr++;
    }
    *bufPtr = '\0';
    return success;
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgRawReadHeader
 *
 *      Usage:          Read the header of an image in RAW format.
 *
 *      Synopsis:       UT_Bool UT_ImgRawReadHeader 
 *                              (FILE *fp, UInt32 &width, UInt32 &height,
 *                              UInt32 &nChans, UT_Bool &isIntel, 
 *                              UT_Bool &isTopDown, char pixelType[UT_ImgRawTypeLen])
 *
 *      Description:    Read the header of an image in RAW format.
 *
 *      Return value:   UT_True, if the header information could be read
 *                      successfully, else UT_False.
 *
 *      See also:       UT_ImgRawReadUInt8Chan
 *                      UT_ImgRawReadUInt16Chan
 *                      UT_ImgRawReadFloat32Chan
 *
 ***************************************************************************/

UT_Bool UT_ImgRawReadHeader (FILE *fp, UInt32 *width, UInt32 *height,
                             UInt32 *nChans, UT_Bool *isIntel, 
                             UT_Bool *isTopDown, char pixelType[UT_ImgRawTypeLen])
{
    char buf[MAXSIZE];
    char tmpStr[MAXSIZE];

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strMagic, tmpStr))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field Magic");
        return UT_False;
    }
    if (!checkMagic (tmpStr)) {
        return UT_False;
    }

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strWidth, width))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field Width");
        return UT_False;
    }
    if (!checkWidth (*width)) {
        return UT_False;
    }

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strHeight, height))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field Height");
        return UT_False;
    }
    if (!checkHeight (*height)) {
        return UT_False;
    }

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strNumChan, nChans))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field NumChan");
        return UT_False;
    }
    if (!checkNumChans (*nChans)) {
        return UT_False;
    }

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strByteOrder, tmpStr))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field ByteOrder");
        return UT_False;
    }
    *isIntel = UT_False;
    if (strcmp (tmpStr, strIntel) == 0) {
        *isIntel = UT_True;
    }

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strScanOrder, tmpStr))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field ScanOrder");
        return UT_False;
    }
    *isTopDown = UT_False;
    if (strcmp (tmpStr, strTopDown) == 0) {
        *isTopDown = UT_True;
    }

    if (!readHeaderLine (fp, buf) ||
        (1 != sscanf (buf, strPixelType, pixelType))) {
        UT_ErrSetNum (UT_ErrUnexpEof, "Unable to parse header field PixelType");
        return UT_False;
    }
    if (!checkPixelType (pixelType)) {
        return UT_False;
    }
    return UT_True;
}

static UT_Bool readFloat32Row (FILE *fp, Float32 *pixels, UInt32 nFloats,
                               UInt8 *buf, UT_Bool swapBytes)
{
    UInt32  i;
    Float32 *mPtr = pixels;
    UInt8   *bufPtr = buf;

    #if defined (DEBUG_LOCAL)
        printf ("Reading %d floats\n", nFloats);
    #endif
    if (4 * nFloats != fread (buf, 4, nFloats, fp)) {
        return readError (fp);
    }
             
    if (swapBytes) {
        for (i=0; i<nFloats; i++) {
            ((UInt8 *)mPtr)[0] = bufPtr[3];
            ((UInt8 *)mPtr)[1] = bufPtr[2];
            ((UInt8 *)mPtr)[2] = bufPtr[1];
            ((UInt8 *)mPtr)[3] = bufPtr[0];
            mPtr++;
            bufPtr += 4;
        }
    } else {
        for (i=0; i<nFloats; i++) {
            ((UInt8 *)mPtr)[0] = bufPtr[0];
            ((UInt8 *)mPtr)[1] = bufPtr[1];
            ((UInt8 *)mPtr)[2] = bufPtr[2];
            ((UInt8 *)mPtr)[3] = bufPtr[3];
            mPtr++;
            bufPtr += 4;
        }
    }
    return UT_True;
}

static UT_Bool readUInt16Row (FILE *fp, UInt16 *pixels, UInt32 nShorts,
                              UInt8 *buf, UT_Bool swapBytes)
{
    UInt32 i;
    UInt16 *mPtr = pixels;
    UInt8  *bufPtr = buf;

    #if defined (DEBUG_LOCAL)
        printf ("Reading %d UInt16s\n", nShorts);
    #endif
    if (2 * nShorts != fread (buf, 2, nShorts, fp)) {
        return readError (fp);
    }
             
    if (swapBytes) {
        for (i=0; i<nShorts; i++) {
            ((UInt8 *)mPtr)[0] = bufPtr[1];
            ((UInt8 *)mPtr)[1] = bufPtr[0];
            mPtr++;
            bufPtr += 2;
        }
    } else {
        for (i=0; i<nShorts; i++) {
            ((UInt8 *)mPtr)[0] = bufPtr[0];
            ((UInt8 *)mPtr)[1] = bufPtr[1];
            mPtr++;
            bufPtr += 2;
        }
    }
    return UT_True;
}

static UT_Bool readUInt8Row (FILE *fp, UInt8 *pixels, UInt32 nBytes,
                             UInt8 *buf, UT_Bool swapBytes)
{
    UInt32 i;
    UInt8  *mPtr = pixels;
    UInt8  *bufPtr = buf;

    #if defined (DEBUG_LOCAL)
        printf ("Reading %d UBytes\n", nBytes);
    #endif
    if (nBytes != fread (buf, 1, nBytes, fp)) {
        return readError (fp);
    }
             
    for (i=0; i<nBytes; i++) {
        mPtr[0] = bufPtr[0];
        mPtr++;
        bufPtr += 1;
    }
    return UT_True;
}

static void writeInt (FILE *fp, const char *fmt, Int32 val)
{
    char str[HEADLEN+1];

    sprintf (str, fmt, val);
    while (strlen (str) < HEADLEN -1) {
        strcat (str, " ");
    }
    strcat (str, "\n");
    fprintf (fp, "%s", str);
}

static void writeString (FILE *fp, const char *fmt, const char *val)
{
    char str[HEADLEN+1];

    sprintf (str, fmt, val);
    while (strlen (str) < HEADLEN -1) {
        strcat (str, " ");
    }
    strcat (str, "\n");
    fprintf (fp, "%s", str);
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgRawWriteHeader
 *
 *      Usage:          Write the header for an image in RAW format.
 *
 *      Synopsis:       UT_Bool UT_ImgRawWriteHeader 
 *                              (FILE *fp, UInt32 width, UInt32 height,
 *                              UInt32 nChans, UT_Bool isIntel, 
 *                              UT_Bool isTopDown, const char *pixelType)
 *
 *      Description:    Write the header for an image in RAW format.
 *
 *      Return value:   UT_True, if the header information could be written
 *                      successfully, else UT_False.
 *
 *      See also:       UT_ImgRawWriteUInt8Chan
 *                      UT_ImgRawWriteUInt16Chan
 *                      UT_ImgRawWriteFloat32Chan
 *
 ***************************************************************************/

UT_Bool UT_ImgRawWriteHeader (FILE *fp, UInt32 width, UInt32 height,
                              UInt32 nChans, UT_Bool isIntel, 
                              UT_Bool isTopDown, const char *pixelType)
{
    if (!checkWidth (width) ||
        !checkHeight (height) ||
        !checkNumChans (nChans) ||
        !checkPixelType (pixelType)) {
        return UT_False;
    }
    writeString (fp, strMagic,     "RAW");
    writeInt    (fp, strWidth,     width);
    writeInt    (fp, strHeight,    height);
    writeInt    (fp, strNumChan,   nChans);
    writeString (fp, strByteOrder, isIntel?   strIntel:   strMotorola);
    writeString (fp, strScanOrder, isTopDown? strTopDown: strBottomUp);
    writeString (fp, strPixelType, pixelType);
    return UT_True;
}

UT_Bool UT_ImgRawWriteUInt8Header (FILE *fp, UInt32 width, UInt32 height,
                                   UInt32 nChans, UT_Bool isTopDown)
{
    return UT_ImgRawWriteHeader (fp, width, height, nChans,
                                 UT_PortIsIntel(), isTopDown, UT_ImgRawTypeByte);
}

UT_Bool UT_ImgRawWriteUInt16Header (FILE *fp, UInt32 width, UInt32 height,
                                   UInt32 nChans, UT_Bool isTopDown)
{
    return UT_ImgRawWriteHeader (fp, width, height, nChans,
                                 UT_PortIsIntel(), isTopDown, UT_ImgRawTypeShort);
}

UT_Bool UT_ImgRawWriteFloat32Header (FILE *fp, UInt32 width, UInt32 height,
                                     UInt32 nChans, UT_Bool isTopDown)
{
    return UT_ImgRawWriteHeader (fp, width, height, nChans,
                                 UT_PortIsIntel(), isTopDown, UT_ImgRawTypeFloat);
}

UT_Bool UT_ImgRawWriteUInt8Scan (FILE *fp, const UInt8 *pixBuf, UInt32 width)
{
    if (width != fwrite (pixBuf, sizeof (UInt8), width, fp)) {
        return writeError (fp);
    }
    return UT_True;
}

UT_Bool UT_ImgRawWriteUInt16Scan (FILE *fp, const UInt16 *pixBuf, UInt32 width)
{
    if (width != fwrite (pixBuf, sizeof (UInt16), width, fp)) {
        return writeError (fp);
    }
    return UT_True;
}

UT_Bool UT_ImgRawWriteFloat32Scan (FILE *fp, const Float32 *pixBuf, UInt32 width)
{
    if (width != fwrite (pixBuf, sizeof (Float32), width, fp)) {
        return writeError (fp);
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgRawWriteUInt8Chan
 *
 *      Usage:          Write an image channel in UInt8 format into a RAW file.
 *
 *      Synopsis:       UT_Bool UT_ImgRawWriteUInt8Chan 
 *                              (const char *fileName, const UInt8 *pixBuf,
 *                              UInt32 width, UInt32 height, 
 *                              UT_Bool topDown, UT_Bool withHeader)
 *
 *      Description:    Write an image channel in UInt8 format into a RAW file.
 *                      TODO DOC
 *
 *      Return value:   UT_True, if the image channel could be written
 *                      successfully, else UT_False.
 *
 *      See also:       UT_ImgRawWriteHeader
 *                      UT_ImgRawWriteUInt16Chan
 *                      UT_ImgRawWriteFloat32Chan
 *
 ***************************************************************************/

UT_Bool UT_ImgRawWriteUInt8Chan (const char *fileName, const UInt8 *pixBuf,
                                 UInt32 width, UInt32 height, 
                                 UT_Bool topDown, UT_Bool withHeader)
{
    FILE *fp;
    const UInt8 *pixBufPtr;
    UInt32 y;

    if (!(fp = UT_FileOpen (fileName, "wb"))) {
        return UT_False;
    }

    if (withHeader) {
        if (!UT_ImgRawWriteHeader (fp, width, height, 1, 
                                   UT_PortIsIntel(), topDown, UT_ImgRawTypeByte)) {
            UT_FileClose (fp);
            return UT_False;
        }
    }

    pixBufPtr = pixBuf;
    for (y = 0; y < height; y++) {
        if (!UT_ImgRawWriteUInt8Scan (fp, pixBufPtr, width)) {
            UT_FileClose (fp);
            return UT_False;
        }
        pixBufPtr += width;
    }
    return UT_FileClose (fp);
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgRawWriteUInt16Chan
 *
 *      Usage:          Write an image channel in UInt16 format into a RAW file.
 *
 *      Synopsis:       UT_Bool UT_ImgRawWriteUInt16Chan 
 *                              (const char *fileName, const UInt16 *pixBuf,
 *                              UInt32 width, UInt32 height,
 *                              UT_Bool topDown, UT_Bool withHeader)
 *
 *      Description:    Write an image channel in UInt16 format into a RAW file.
 *                      TODO DOC
 *
 *      Return value:   UT_True, if the image channel could be written
 *                      successfully, else UT_False.
 *
 *      See also:       UT_ImgRawWriteHeader
 *                      UT_ImgRawWriteUInt8Chan
 *                      UT_ImgRawWriteFloat32Chan
 *
 ***************************************************************************/

UT_Bool UT_ImgRawWriteUInt16Chan (const char *fileName, const UInt16 *pixBuf,
                                  UInt32 width, UInt32 height, 
                                  UT_Bool topDown, UT_Bool withHeader)
{
    FILE *fp;
    const UInt16 *pixBufPtr;
    UInt32 y;

    if (!(fp = UT_FileOpen (fileName, "wb"))) {
        return UT_False;
    }

    if (withHeader) {
        if (!UT_ImgRawWriteHeader (fp, width, height, 1, 
                                   UT_PortIsIntel(), topDown, UT_ImgRawTypeShort)) {
            UT_FileClose (fp);
            return UT_False;
        }
    }

    pixBufPtr = pixBuf;
    for (y = 0; y < height; y++) {
        if (!UT_ImgRawWriteUInt16Scan (fp, pixBufPtr, width)) {
            UT_FileClose (fp);
            return UT_False;
        }
        pixBufPtr += width;
    }
    return UT_FileClose (fp);
}

/***************************************************************************
 *[@e
 *      Name:           UT_ImgRawWriteFloat32Chan
 *
 *      Usage:          Write an image channel in Float32 format into a RAW file.
 *
 *      Synopsis:       UT_Bool UT_ImgRawWriteFloat32Chan 
 *                              (const char *fileName, const Float32 *pixBuf,
 *                              UInt32 width, UInt32 height, 
 *                              UT_Bool topDown, UT_Bool withHeader)
 *
 *      Description:    Write an image channel in Float32 format into a RAW file.
 *                      TODO DOC
 *
 *      Return value:   UT_True, if the image channel could be written
 *                      successfully, else UT_False.
 *
 *      See also:       UT_ImgRawWriteHeader
 *                      UT_ImgRawWriteUInt8Chan
 *                      UT_ImgRawWriteUInt16Chan
 *
 ***************************************************************************/

UT_Bool UT_ImgRawWriteFloat32Chan (const char *fileName, const Float32 *pixBuf,
                                   UInt32 width, UInt32 height, 
                                   UT_Bool topDown, UT_Bool withHeader)
{
    FILE *fp;
    const Float32 *pixBufPtr;
    UInt32 y;

    if (!(fp = UT_FileOpen (fileName, "wb"))) {
        return UT_False;
    }

    if (withHeader) {
        if (!UT_ImgRawWriteHeader (fp, width, height, 1, 
                                   UT_PortIsIntel(), topDown, UT_ImgRawTypeFloat)) {
            UT_FileClose (fp);
            return UT_False;
        }
    }

    pixBufPtr = pixBuf;
    for (y = 0; y < height; y++) {
        if (!UT_ImgRawWriteFloat32Scan (fp, pixBufPtr, width)) {
            UT_FileClose (fp);
            return UT_False;
        }
        pixBufPtr += width;
    }
    return UT_FileClose (fp);
}

/*
        Vector font containing all printable ASCII characters (i.e. all
        characters in the range from SPC to DEL).
        The following vector of character strings defines the shape of all
        printable ASCII characters as polygonal lines, i.e. "move" and "draw"
        commands.  Every line segment is encoded in a single byte: Bits 0 to 3
        contain the y coordinate of a point (0 to 15), bits 4 to 6 contain
        its x coordinate (0 to 7). If bit 7 (the highest valued bit) is 0, the
        point has to be made the "current point" without drawing, if bit 7
        is 1, a straight line has to be drawn from the current point to the
        point encoded in bits 0 to 6; that point then becomes the current
        point.
        The coordinates are relative to the upper left corner of each
        character, positive x pointing to the right and positive y pointing
        downwards.
        The end of a string encoding the shape of a character is indicated
        by a '\0' byte (this implies that a shape description cannot contain
        a "move (0, 0)" command.
        To draw a character c, do the following:

                char    *p;
                Int     x, y;

                p = vecf_string (c);
                while (*p)
                        {x = vecf_x (p);
                        y = vecf_y (p);
                        if (vecf_draw (p))
                                draw (x, y);
                        else
                                move (x, y);
                        ++p;}

<*/

const char *vecf_font[256] = {
    /* 00 */    "",
    /* 01 */    "",
    /* 02 */    "",
    /* 03 */    "",
    /* 04 */    "",
    /* 05 */    "",
    /* 06 */    "",
    /* 07 */    "",
    /* 08 */    "",
    /* 09 */    "",
    /* 0A */    "",
    /* 0B */    "",
    /* 0C */    "",
    /* 0D */    "",
    /* 0E */    "",
    /* 0F */    "",
    /* 10 */    "",
    /* 11 */    "",
    /* 12 */    "",
    /* 13 */    "",
    /* 14 */    "",
    /* 15 */    "",
    /* 16 */    "",
    /* 17 */    "",
    /* 18 */    "",
    /* 19 */    "",
    /* 1A */    "",
    /* 1B */    "",
    /* 1C */    "",
    /* 1D */    "",
    /* 1E */    "",
    /* 1F */    "",
    /* SPC */   "",
    /* ! */     "\x30\xB7\x38\xB9",
    /* " */     "\x30\xB2\x40\xC2",
    /* # */     "\x20\xA9\x06\xE6\x63\x83\x40\xC9",
    /* $ */     "\x30\xBA\x07\xA9\xC9\xE7\xC5\xA5\x83\xA1\xC1\xE3",
    /* % */     "\x31\xA0\x90\x81\x82\x93\xA3\xB2\xB1\xE0\x89\x38"
                "\xC9\xD9\xE8\xE7\xD6\xC6\xB7\xB8",
    /* & */     "\x69\x93\x91\xA0\xC0\xD1\xD3\xC4\xA4\x86\x87\xA9\xC9"
                "\xD8\xE6",
    /* ' */     "\x41\xB1\xB0\xC0\xC1\xB3",
    /* ( */     "\x40\xA3\xA6\xC9",
    /* ) */     "\x20\xC3\xC6\xA9",
    /* * */     "\x30\x96\xE2\x82\xD6\xB0",
    /* + */     "\x33\xB9\x06\xE6",
    /* , */     "\x49\xB9\xB8\xC8\xC9\xBB",
    /* - */     "\x06\xE6",
    /* . */     "\x39\xB8\xC8\xC9\xB9",
    /* / */     "\x09\xE0",
    /* 0 */     "\x07\xE2\xE7\xC9\xA9\x87\x82\xA0\xC0\xE2",
    /* 1 */     "\x03\xB0\xB9\x09\xE9",
    /* 2 */     "\x02\xA0\xC0\xE2\xE4\x89\xE9",
    /* 3 */     "\x02\xa0\xc0\xE2\xC4\x24\xC4\xE6\xE7\xC9\xA9\x87",
    /* 4 */     "\x49\xC0\x86\xE6",
    /* 5 */     "\x60\x80\x84\xA3\xC3\xE5\xE7\xC9\xA9\x87",
    /* 6 */     "\x50\xA0\x82\x87\xA9\xC9\xE7\xE5\xC3\xA3\x85",
    /* 7 */     "\x19\x96\xE0\x80",
    /* 8 */     "\x24\x82\xA0\xC0\xE2\xC4\xA4\x86\x87\xA9\xC9\xE7"
                "\xE6\xC4",
    /* 9 */     "\x19\xC9\xE7\xE2\xC0\xA0\x82\x84\xA6\xC6\xE4",
    /* : */     "\x44\xC3\xB3\xB4\xC4\x38\xB9\xC9\xC8\xB8",
    /* ; */     "\x44\xC3\xB3\xB4\xC4\x49\xB9\xB8\xC8\xC9\xBB",
    /* < */     "\x63\x86\xE9",
    /* = */     "\x05\xE5\x67\x87",
    /* > */     "\x03\xE6\x89",
    /* ? */     "\x02\xA0\xC0\xE2\xE4\xB6\xB7\x38\xB9",
    /* @ */     "\x64\xC2\xA4\xA6\xC8\xE6\xE2\xC0\xA0\x82\x87\xA9\xC9",
    /* A */     "\x09\xB0\xE9\x16\xD6",
    /* B */     "\x09\xC9\xE7\xE6\xC4\x14\xC4\xE2\xC0\x80\x10\x99",
    /* C */     "\x62\xC0\xA0\x82\x87\xA9\xC9\xE7",
    /* D */     "\x10\x99\x09\xC9\xE7\xE2\xC0\x80",
    /* E */     "\x60\x80\x89\xE9\x44\x84",
    /* F */     "\x60\x80\x89\x04\xC4",
    /* G */     "\x62\xC0\xA0\x82\x87\xA9\xC9\xE7\xE4\xB4",
    /* H */     "\x09\x80\x04\xE4\x60\xE9",
    /* I */     "\x60\x80\x30\xB9\x09\xE9",
    /* J */     "\x07\xA9\xC9\xE7\xE0\x80",
    /* K */     "\x09\x80\x06\xE0\x24\xE9",
    /* L */     "\x69\x89\x80",
    /* M */     "\x09\x80\xb4\xE0\xE9",
    /* N */     "\x09\x80\xE9\xE0",
    /* O */     "\x20\xC0\xE2\xE7\xC9\xA9\x87\x82\xA0",
    /* P */     "\x10\x99\x15\xC5\xE3\xE2\xC0\x80",
    /* Q */     "\x20\x82\x87\xA9\xC9\xE7\xE2\xC0\xA0\x25\xE9",
    /* R */     "\x10\x99\x69\xA5\x15\xC5\xE3\xE2\xC0\x80",
    /* S */     "\x07\xA9\xC9\xE7\xE5\xC4\xA4\x82\xA0\xC0\xE2",
    /* T */     "\x60\x80\x30\xB9",
    /* U */     "\x60\xE7\xC9\xA9\x87\x80",
    /* V */     "\x60\xB9\x80",
    /* W */     "\x60\xE9\xB5\x89\x80",
    /* X */     "\x60\x89\x69\x80",
    /* Y */     "\x60\xB4\x80\x34\xB9",
    /* Z */     "\x69\x89\xE0\x80",
    /* [ */     "\x50\xA0\xA9\xD9",
    /* \ */     "\x69\x80",
    /* ] */     "\x10\xC0\xC9\x99",
    /* ^ */     "\x06\xB0\xE6",
    /* _ */     "\x0A\xEA",
    /* ` */     "\x31\xC1\xC0\xB0\xB1\xC3",
    /* a */     "\x14\xA3\xC3\xD4\xD8\xC9\x99\x88\x87\xA5\xD5\x58\xE9",
    /* b */     "\x09\x80\x05\xA3\xC3\xE5\xE7\xC9\x99\x88",
    /* c */     "\x64\xC3\xA3\x85\x87\xA9\xC9\xE8",
    /* d */     "\x60\xE9\x68\xD9\xA9\x87\x85\xA3\xC3\xE5",
    /* e */     "\x07\xE5\xC3\xA3\x85\x87\xA9\xC9\xE7",
    /* f */     "\x52\xB0\x92\x99\x14\xC4",
    /* g */     "\x0A\xAC\xCC\xEA\xE3\x64\xD3\xA3\x85\x87\xA9\xC9\xE7",
    /* h */     "\x09\x80\x05\xA3\xC3\xE5\xE9",
    /* i */     "\x30\xB1\x13\xB3\xB9\x19\xD9",
    /* j */     "\x30\xB1\x23\xC3\xCA\xAC",
    /* k */     "\x63\x89\x80\x36\xE9",
    /* l */     "\x19\xD9\x39\xB0\x90",
    /* m */     "\x09\x84\x93\xA3\xB4\xB9\x34\xC3\xD3\xE4\xE9",
    /* n */     "\x09\x83\x05\xA3\xC3\xE5\xE9",
    /* o */     "\x23\x85\x87\xA9\xC9\xE7\xE5\xC3\xA3",
    /* p */     "\x0C\x83\x04\x93\xC3\xE5\xE7\xC9\xA9\x87",
    /* q */     "\x64\xD3\xA3\x85\x87\xA9\xC9\xE7\x63\xEC",
    /* r */     "\x13\x99\x15\xB3\xD3",
    /* s */     "\x08\xA9\xC9\xE8\xE7\xC6\xA6\x85\x84\xA3\xC3\xE4",
    /* t */     "\x20\xA8\xB9\xC8\x23\xC3",
    /* u */     "\x03\x87\xA9\xC9\xE7\x63\xE9",
    /* v */     "\x03\xB9\xE3",
    /* w */     "\x03\x89\xB6\xE9\xE3",
    /* x */     "\x03\xE9\x09\xE3",
    /* y */     "\x03\x87\xA9\xC9\xE7\x63\xEA\xCC\x9C",
    /* z */     "\x03\xE3\x89\xE9",
    /* { */     "\x41\xB2\xB4\xA5\xB6\xB8\xC9",
    /* | */     "\x30\xB9",
    /* } */     "\x21\xB2\xB4\xC5\xB6\xB8\xA9",
    /* ~ */     "\x02\x81\x90\xA0\xC2\xD2\xE1\xE0",
    /* DEL */   "\x02\xA0\x04\xC0\x06\xE0\x08\xE2\x0A\xE4\x0C\xE6"
                "\x2C\xE8\x4C\xEA",
    /* 80 */    "",
    /* 81 */    "",
    /* 82 */    "",
    /* 83 */    "",
    /* 84 */    "",
    /* 85 */    "",
    /* 86 */    "",
    /* 87 */    "",
    /* 88 */    "",
    /* 89 */    "",
    /* 8A */    "",
    /* 8B */    "",
    /* 8C */    "",
    /* 8D */    "",
    /* 8E */    "",
    /* 8F */    "",
    /* 90 */    "",
    /* 91 */    "",
    /* 92 */    "",
    /* 93 */    "",
    /* 94 */    "",
    /* 95 */    "",
    /* 96 */    "",
    /* 97 */    "",
    /* 98 */    "",
    /* 99 */    "",
    /* 9A */    "",
    /* 9B */    "",
    /* 9C */    "",
    /* 9D */    "",
    /* 9E */    "",
    /* 9F */    "",
    /* A0 */    "",
    /* A1 */    "",
    /* A2 */    "",
    /* A3 */    "",
    /* A4 */    "",
    /* A5 */    "",
    /* A6 */    "",
    /* section */ "\x51\xC0\xA0\x82\xA4\xC4\xE6\xC8\x24\x86\xA8\xC8"
                "\xEA\xCC\xAC\x9B",
    /* A8 */    "",
    /* A9 */    "",
    /* AA */    "",
    /* AB */    "",
    /* AC */    "",
    /* AD */    "",
    /* AE */    "",
    /* AF */    "",
    /* B0 */    "",
    /* B1 */    "",
    /* B2 */    "",
    /* B3 */    "",
    /* B4 */    "",
    /* B5 */    "",
    /* B6 */    "",
    /* B7 */    "",
    /* B8 */    "",
    /* B9 */    "",
    /* BA */    "",
    /* BB */    "",
    /* BC */    "",
    /* BD */    "",
    /* BE */    "",
    /* BF */    "",
    /* C0 */    "",
    /* C1 */    "",
    /* C2 */    "",
    /* C3 */    "",
    /* A umlaut */      "\x09\xB0\xE9\x16\xD6\x01\x80\x60\xE1",
    /* C5 */    "",
    /* C6 */    "",
    /* C7 */    "",
    /* C8 */    "",
    /* C9 */    "",
    /* CA */    "",
    /* CB */    "",
    /* CC */    "",
    /* CD */    "",
    /* CE */    "",
    /* CF */    "",
    /* D0 */    "",
    /* D1 */    "",
    /* D2 */    "",
    /* D3 */    "",
    /* D4 */    "",
    /* D5 */    "",
    /* O umlaut */      "\x03\x87\xA9\xC9\xE7\xE3\xC1\xA1\x83\x01\x80\x60\xE1",
    /* D7 */    "",
    /* D8 */    "",
    /* D9 */    "",
    /* DA */    "",
    /* DB */    "",
    /* U umlaut */      "\x60\xE7\xC9\xA9\x87\x80\x20\xA1\x40\xC1",
    /* DD */    "",
    /* DE */    "",
    /* sharp s */       "\x09\x82\xA0\xB0\xD2\xD3\xC4\xA4\x44\xE6\xE7\xC9\xA9",
    /* E0 */    "",
    /* E1 */    "",
    /* E2 */    "",
    /* E3 */    "",
    /* a umlaut */      "\x14\xA3\xC3\xD4\xD8\xC9\x99\x88\x87\xA5\xD5\x58\xE9"
                    "\x20\xA1\x40\xC1",
    /* E5 */    "",
    /* E6 */    "",
    /* E7 */    "",
    /* E8 */    "",
    /* E9 */    "",
    /* EA */    "",
    /* EB */    "",
    /* EC */    "",
    /* ED */    "",
    /* EE */    "",
    /* EF */    "",
    /* F0 */    "",
    /* F1 */    "",
    /* F2 */    "",
    /* F3 */    "",
    /* F4 */    "",
    /* F5 */    "",
    /* o umlaut */      "\x23\x85\x87\xA9\xC9\xE7\xE5\xC3\xA3\x20\xA1\x40\xC1",
    /* F7 */    "",
    /* F8 */    "",
    /* F9 */    "",
    /* FA */    "",
    /* FB */    "",
    /* u umlaut */      "\x03\x87\xA9\xC9\xE7\x63\xE9\x20\xA1\x40\xC1",
    /* FD */    "",
    /* FE */    "",
    /* FF */    "",
};
