Blob Blame History Raw
/* See LICENSE file for licensing information.
*/

#include "pm_c_util.h"
#include "mallocvar.h"
#include "pnm.h"
#include "palm.h"

#include "palmcolormap.h"



static pixval
scaleSample(pixval const arg,
            pixval const oldMaxval,
            pixval const newMaxval) {

    return (arg * newMaxval + oldMaxval/2) / oldMaxval;
}



ColormapEntry
palmcolor_mapEntryColorFmPixel(pixel  const color,
                               pixval const maxval,
                               pixval const newMaxval) {


    return
        0
        | (scaleSample(PPM_GETR(color), maxval, newMaxval) << 16) 
        | (scaleSample(PPM_GETG(color), maxval, newMaxval) <<  8)
        | (scaleSample(PPM_GETB(color), maxval, newMaxval) <<  0);
}



int
palmcolor_compare_indices(const void * const p1,
                          const void * const p2) {
/*----------------------------------------------------------------------------
   This is a 'qsort' collation function.
-----------------------------------------------------------------------------*/
    if ((*((ColormapEntry *) p1) & 0xFF000000) < (*((ColormapEntry *) p2) & 0xFF000000))
        return -1;
    else if ((*((ColormapEntry *) p1) & 0xFF000000) > (*((ColormapEntry *) p2) & 0xFF000000))
        return 1;
    else
        return 0;
}



int
palmcolor_compare_colors(const void * const p1,
                         const void * const p2) {
/*----------------------------------------------------------------------------
   This is a 'qsort' collation function.
-----------------------------------------------------------------------------*/
    unsigned long const val1 = *((const unsigned long *) p1) & 0xFFFFFF;
    unsigned long const val2 = *((const unsigned long *) p2) & 0xFFFFFF;

    if (val1 < val2)
        return -1;
    else if (val1 > val2)
        return 1;
    else
        return 0;
}

/***********************************************************************
 ***********************************************************************
 ***********************************************************************
 ******* colortables from pilrc-2.6/bitmap.c ***************************
 ***********************************************************************
 ***********************************************************************
 ***********************************************************************/

#if 0

/*
 * The 1bit-2 color system palette for Palm Computing Devices.
 */
static int PalmPalette1bpp[2][3] = 
{
  { 255, 255, 255}, {   0,   0,   0 }
};

/*
 * The 2bit-4 color system palette for Palm Computing Devices.
 */
static int PalmPalette2bpp[4][3] = 
{
  { 255, 255, 255}, { 192, 192, 192}, { 128, 128, 128 }, {   0,   0,   0 }
};

/*
 * The 4bit-16 color system palette for Palm Computing Devices.
 */
static int PalmPalette4bpp[16][3] = 
{
  { 255, 255, 255}, { 238, 238, 238 }, { 221, 221, 221 }, { 204, 204, 204 },
  { 187, 187, 187}, { 170, 170, 170 }, { 153, 153, 153 }, { 136, 136, 136 },
  { 119, 119, 119}, { 102, 102, 102 }, {  85,  85,  85 }, {  68,  68,  68 },
  {  51,  51,  51}, {  34,  34,  34 }, {  17,  17,  17 }, {   0,   0,   0 }
};

/*
 * The 4bit-16 color system palette for Palm Computing Devices.
 */
static int PalmPalette4bppColor[16][3] = 
{
  { 255, 255, 255}, { 128, 128, 128 }, { 128,   0,   0 }, { 128, 128,   0 },
  {   0, 128,   0}, {   0, 128, 128 }, {   0,   0, 128 }, { 128,   0, 128 },
  { 255,   0, 255}, { 192, 192, 192 }, { 255,   0,   0 }, { 255, 255,   0 },
  {   0, 255,   0}, {   0, 255, 255 }, {   0,   0, 255 }, {   0,   0,   0 }
};

#endif  /* 0 */

/*
 * The 8bit-256 color system palette for Palm Computing Devices.
 *
 * NOTE:  only the first 231, plus the last one, are valid.
 */
static int PalmPalette8bpp[256][3] = 
{
  { 255, 255, 255 }, { 255, 204, 255 }, { 255, 153, 255 }, { 255, 102, 255 }, 
  { 255,  51, 255 }, { 255,   0, 255 }, { 255, 255, 204 }, { 255, 204, 204 }, 
  { 255, 153, 204 }, { 255, 102, 204 }, { 255,  51, 204 }, { 255,   0, 204 }, 
  { 255, 255, 153 }, { 255, 204, 153 }, { 255, 153, 153 }, { 255, 102, 153 }, 
  { 255,  51, 153 }, { 255,   0, 153 }, { 204, 255, 255 }, { 204, 204, 255 },
  { 204, 153, 255 }, { 204, 102, 255 }, { 204,  51, 255 }, { 204,   0, 255 },
  { 204, 255, 204 }, { 204, 204, 204 }, { 204, 153, 204 }, { 204, 102, 204 },
  { 204,  51, 204 }, { 204,   0, 204 }, { 204, 255, 153 }, { 204, 204, 153 },
  { 204, 153, 153 }, { 204, 102, 153 }, { 204,  51, 153 }, { 204,   0, 153 },
  { 153, 255, 255 }, { 153, 204, 255 }, { 153, 153, 255 }, { 153, 102, 255 },
  { 153,  51, 255 }, { 153,   0, 255 }, { 153, 255, 204 }, { 153, 204, 204 },
  { 153, 153, 204 }, { 153, 102, 204 }, { 153,  51, 204 }, { 153,   0, 204 },
  { 153, 255, 153 }, { 153, 204, 153 }, { 153, 153, 153 }, { 153, 102, 153 },
  { 153,  51, 153 }, { 153,   0, 153 }, { 102, 255, 255 }, { 102, 204, 255 },
  { 102, 153, 255 }, { 102, 102, 255 }, { 102,  51, 255 }, { 102,   0, 255 },
  { 102, 255, 204 }, { 102, 204, 204 }, { 102, 153, 204 }, { 102, 102, 204 },
  { 102,  51, 204 }, { 102,   0, 204 }, { 102, 255, 153 }, { 102, 204, 153 },
  { 102, 153, 153 }, { 102, 102, 153 }, { 102,  51, 153 }, { 102,   0, 153 },
  {  51, 255, 255 }, {  51, 204, 255 }, {  51, 153, 255 }, {  51, 102, 255 },
  {  51,  51, 255 }, {  51,   0, 255 }, {  51, 255, 204 }, {  51, 204, 204 },
  {  51, 153, 204 }, {  51, 102, 204 }, {  51,  51, 204 }, {  51,   0, 204 },
  {  51, 255, 153 }, {  51, 204, 153 }, {  51, 153, 153 }, {  51, 102, 153 },
  {  51,  51, 153 }, {  51,   0, 153 }, {   0, 255, 255 }, {   0, 204, 255 },
  {   0, 153, 255 }, {   0, 102, 255 }, {   0,  51, 255 }, {   0,   0, 255 },
  {   0, 255, 204 }, {   0, 204, 204 }, {   0, 153, 204 }, {   0, 102, 204 },
  {   0,  51, 204 }, {   0,   0, 204 }, {   0, 255, 153 }, {   0, 204, 153 },
  {   0, 153, 153 }, {   0, 102, 153 }, {   0,  51, 153 }, {   0,   0, 153 },
  { 255, 255, 102 }, { 255, 204, 102 }, { 255, 153, 102 }, { 255, 102, 102 },
  { 255,  51, 102 }, { 255,   0, 102 }, { 255, 255,  51 }, { 255, 204,  51 },
  { 255, 153,  51 }, { 255, 102,  51 }, { 255,  51,  51 }, { 255,   0,  51 },
  { 255, 255,   0 }, { 255, 204,   0 }, { 255, 153,   0 }, { 255, 102,   0 },
  { 255,  51,   0 }, { 255,   0,   0 }, { 204, 255, 102 }, { 204, 204, 102 },
  { 204, 153, 102 }, { 204, 102, 102 }, { 204,  51, 102 }, { 204,   0, 102 },
  { 204, 255,  51 }, { 204, 204,  51 }, { 204, 153,  51 }, { 204, 102,  51 },
  { 204,  51,  51 }, { 204,   0,  51 }, { 204, 255,   0 }, { 204, 204,   0 },
  { 204, 153,   0 }, { 204, 102,   0 }, { 204,  51,   0 }, { 204,   0,   0 },
  { 153, 255, 102 }, { 153, 204, 102 }, { 153, 153, 102 }, { 153, 102, 102 },
  { 153,  51, 102 }, { 153,   0, 102 }, { 153, 255,  51 }, { 153, 204,  51 },
  { 153, 153,  51 }, { 153, 102,  51 }, { 153,  51,  51 }, { 153,   0,  51 },
  { 153, 255,   0 }, { 153, 204,   0 }, { 153, 153,   0 }, { 153, 102,   0 },
  { 153,  51,   0 }, { 153,   0,   0 }, { 102, 255, 102 }, { 102, 204, 102 },
  { 102, 153, 102 }, { 102, 102, 102 }, { 102,  51, 102 }, { 102,   0, 102 },
  { 102, 255,  51 }, { 102, 204,  51 }, { 102, 153,  51 }, { 102, 102,  51 },
  { 102,  51,  51 }, { 102,   0,  51 }, { 102, 255,   0 }, { 102, 204,   0 },
  { 102, 153,   0 }, { 102, 102,   0 }, { 102,  51,   0 }, { 102,   0,   0 },
  {  51, 255, 102 }, {  51, 204, 102 }, {  51, 153, 102 }, {  51, 102, 102 },
  {  51,  51, 102 }, {  51,   0, 102 }, {  51, 255,  51 }, {  51, 204,  51 },
  {  51, 153,  51 }, {  51, 102,  51 }, {  51,  51,  51 }, {  51,   0,  51 },
  {  51, 255,   0 }, {  51, 204,   0 }, {  51, 153,   0 }, {  51, 102,   0 },
  {  51,  51,   0 }, {  51,   0,   0 }, {   0, 255, 102 }, {   0, 204, 102 },
  {   0, 153, 102 }, {   0, 102, 102 }, {   0,  51, 102 }, {   0,   0, 102 },
  {   0, 255,  51 }, {   0, 204,  51 }, {   0, 153,  51 }, {   0, 102,  51 },
  {   0,  51,  51 }, {   0,   0,  51 }, {   0, 255,   0 }, {   0, 204,   0 },
  {   0, 153,   0 }, {   0, 102,   0 }, {   0,  51,   0 }, {  17,  17,  17 },
  {  34,  34,  34 }, {  68,  68,  68 }, {  85,  85,  85 }, { 119, 119, 119 },
  { 136, 136, 136 }, { 170, 170, 170 }, { 187, 187, 187 }, { 221, 221, 221 },
  { 238, 238, 238 }, { 192, 192, 192 }, { 128,   0,   0 }, { 128,   0, 128 },
  {   0, 128,   0 }, {   0, 128, 128 }, {   0,   0,   0 }, {   0,   0,   0 },
  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 },
  {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }, {   0,   0,   0 }
};



Colormap *
palmcolor_build_default_8bit_colormap(void) {

    unsigned int i;

    Colormap * cmP;

    MALLOCVAR_NOFAIL(cmP);
    cmP->nentries = 232;
    MALLOCARRAY_NOFAIL(cmP->color_entries, cmP->nentries);

    /* Fill in the colors */
    for (i = 0; i < 231; ++i) {
        cmP->color_entries[i] = ((i << 24) |
                                (PalmPalette8bpp[i][0] << 16) |
                                (PalmPalette8bpp[i][1] << 8) |
                                (PalmPalette8bpp[i][2]));
    }
    cmP->color_entries[231] = 0xFF000000;
    cmP->ncolors = 232;

    /* now sort the table */
    qsort(cmP->color_entries, cmP->ncolors, sizeof(ColormapEntry), 
          palmcolor_compare_colors);
    return cmP;
}



Colormap *
palmcolor_build_custom_8bit_colormap(pixel **     const pixels,
                                     unsigned int const rows,
                                     unsigned int const cols,
                                     pixval       const maxval) {

    unsigned int row;
    Colormap * colormapP;

    MALLOCVAR_NOFAIL(colormapP);
    colormapP->nentries = 256;
    MALLOCARRAY_NOFAIL(colormapP->color_entries, colormapP->nentries);
    colormapP->ncolors = 0;  /* initial value */
    
    for (row = 0; row < rows; ++row) {
        unsigned int col;
        for (col = 0; col < cols; ++col) {
            ColormapEntry * foundEntryP;
            ColormapEntry const searchTarget =
                palmcolor_mapEntryColorFmPixel(pixels[row][col], maxval, 255);

            foundEntryP =
                bsearch(&searchTarget,
                        colormapP->color_entries, colormapP->ncolors,
                        sizeof(ColormapEntry), palmcolor_compare_colors);
            if (!foundEntryP) {
                if (colormapP->ncolors >= colormapP->nentries)
                    pm_error("Too many colors for custom colormap "
                             "(max %u).  "
                             "Try using pnmquant to reduce the number "
                             "of colors.", colormapP->nentries);
                else {
                    /* add the new color, and re-sort */
                    unsigned int const colorIndex = colormapP->ncolors++;
                    ColormapEntry const newEntry =
                        searchTarget | (colorIndex << 24);
                    colormapP->color_entries[colorIndex] = newEntry;
                    qsort(colormapP->color_entries, colormapP->ncolors, 
                          sizeof(ColormapEntry), palmcolor_compare_colors);
                }
            }
        }
    }
    return colormapP;
}



Colormap *
palmcolor_read_colormap (FILE * const ifP) {

    unsigned short ncolors;
    Colormap * retval;
    int rc;
    
    rc = pm_readbigshort(ifP, (short *) &ncolors);
    if (rc != 0)
        retval = NULL;
    else {
        long colorentry;
        Colormap * colormapP;
        unsigned int i;
        bool error;

        MALLOCVAR_NOFAIL(colormapP);
        colormapP->nentries = ncolors;
        MALLOCARRAY_NOFAIL(colormapP->color_entries, colormapP->nentries);
        
        for (i = 0, error = FALSE;  i < ncolors && !error;  ++i) {
            int rc;
            rc = pm_readbiglong(ifP, &colorentry);
            if (rc != 0)
                error = TRUE;
            else
                colormapP->color_entries[i] = (colorentry & 0xFFFFFFFF);
        }
        if (error) {
            free (colormapP->color_entries);
            free (colormapP);
            retval = NULL;
        } else {
            colormapP->ncolors = ncolors;
            retval = colormapP;
        }
    }
    return retval;
}