alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (img_colors.c)

This example Java source code file (img_colors.c) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

bmat, cmapentry, debug, gmat, lscale, ltab, rmat, times, true, utab, vtab, weight_dist

The img_colors.c Java example source code

/*
 * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/* Iterative color palette generation */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#ifdef TIMES
#include <time.h>
#endif /* TIMES */

#ifndef MAKECUBE_EXE
#include "jvm.h"
#include "jni_util.h"

extern JavaVM *jvm;
#endif

#define jio_fprintf fprintf

#define TRUE 1
#define FALSE 0
static float monitor_gamma[3] = {2.6f, 2.6f, 2.4f}; /* r,g,b */
static float mat[3][3] = {
    {0.3811f, 0.2073f, 0.0213f},
    {0.3203f, 0.6805f, 0.1430f},
    {0.2483f, 0.1122f, 1.2417f}
};
static float whiteXYZ[3] = { 0.9497f, 1.0000f, 1.4060f };
#define whitex (0.9497f / (0.9497f + 1.0000f + 1.4060f))
#define whitey (1.0000f / (0.9497f + 1.0000f + 1.4060f))
static float uwht = 4*whitex/(-2*whitex + 12*whitey + 3);
static float vwht = 9*whitey/(-2*whitex + 12*whitey + 3);

static float Rmat[3][256];
static float Gmat[3][256];
static float Bmat[3][256];
static float Ltab[256], Utab[256], Vtab[256];

typedef struct {
    unsigned char red;
    unsigned char green;
    unsigned char blue;
    unsigned char bestidx;
    int nextidx;
    float L, U, V;
    float dist;
    float dE;
    float dL;
} CmapEntry;

static int num_virt_cmap_entries;
static CmapEntry *virt_cmap;
static int prevtest[256];
static int nexttest[256];

static float Lscale = 10.0f;
/* this is a multiplier--it should not be zero */
static float Weight = 250.0f;

#define WEIGHT_DIST(d,l)   (Weight*(d)/(Weight+(l)))
#define UNWEIGHT_DIST(d,l) ((Weight+(l))*(d)/Weight)

#if 0
#define WEIGHT_DIST(d,l) (d)
#define UNWEIGHT_DIST(d,l) (d)
#endif

static void
init_matrices()
{
    static int done = 0;
    int i;

    if (done) {
        return;
    }
    for (i = 0; i < 256; ++i)
    {
        float iG = (float) pow(i/255.0, monitor_gamma[0]);
        Rmat[0][i] = mat[0][0] * iG;
        Rmat[1][i] = mat[0][1] * iG;
        Rmat[2][i] = mat[0][2] * iG;

        iG = (float) pow(i/255.0, monitor_gamma[1]);
        Gmat[0][i] = mat[1][0] * iG;
        Gmat[1][i] = mat[1][1] * iG;
        Gmat[2][i] = mat[1][2] * iG;

        iG = (float) pow(i/255.0, monitor_gamma[2]);
        Bmat[0][i] = mat[2][0] * iG;
        Bmat[1][i] = mat[2][1] * iG;
        Bmat[2][i] = mat[2][2] * iG;
    }
    done = 1;
}

static void
LUV_convert(int red, int grn, int blu, float *L, float *u, float *v)
{
    float X = Rmat[0][red] + Gmat[0][grn] + Bmat[0][blu];
    float Y = Rmat[1][red] + Gmat[1][grn] + Bmat[1][blu];
    float Z = Rmat[2][red] + Gmat[2][grn] + Bmat[2][blu];
    float sum = X+Y+Z;

    if (sum != 0.0f) {
        float x    = X/sum;
        float y    = Y/sum;
        float dnm  = -2*x + 12*y + 3;
        float ytmp = (float) pow(Y/whiteXYZ[1], 1.0/3.0);

        if (ytmp < .206893f) {
            *L = 903.3f*Y/whiteXYZ[1];
        } else {
            *L = 116*(ytmp) - 16;
        }
        if (dnm != 0.0f) {
            float uprm = 4*x/dnm;
            float vprm = 9*y/dnm;

            *u = 13*(*L)*(uprm-uwht);
            *v = 13*(*L)*(vprm-vwht);
        } else {
            *u = 0.0f;
            *v = 0.0f;
        }
    } else {
        *L = 0.0f;
        *u = 0.0f;
        *v = 0.0f;
    }
}

static int cmapmax;
static int total;
static unsigned char cmap_r[256], cmap_g[256], cmap_b[256];

#define DIST_THRESHOLD 7
static int
no_close_color(float l, float u, float v, int c_tot, int exact) {
    int i;
    for (i = 0; i < c_tot; ++i) {
        float t, dist = 0.0f;
        t = Ltab[i] - l; dist += t*t*Lscale;
        t = Utab[i] - u; dist += t*t;
        t = Vtab[i] - v; dist += t*t;

        if (dist < (exact ? 0.1 : DIST_THRESHOLD))
            return 0;
    }

    return 1;
}

static int
add_color(int r, int g, int b, int f) {
    if (total >= cmapmax)
        return 0;
    cmap_r[total] = r;
    cmap_g[total] = g;
    cmap_b[total] = b;
    LUV_convert(cmap_r[total],cmap_g[total],cmap_b[total],
                Ltab + total, Utab + total, Vtab + total);
    if (no_close_color(Ltab[total], Utab[total], Vtab[total], total-1, f)) {
        ++total;
        return 1;
    } else {
        return 0;
    }
}

static void
init_primaries() {
    int r, g, b;

    for (r = 0; r < 256; r += (r?128:127)) {
        for (g = 0; g < 256; g += (g?128:127)) {
            for (b = 0; b < 256; b += (b?128:127)) {
                if ((r == g) && (g == b)) continue; /* black or white */
                add_color(r, g, b, TRUE);
            }
        }
    }
}

static void
init_pastels() {
    int i;
    /* very light colors */
    for (i = 6; i >= 0; --i)
        add_color((i&4) ? 0xff : 0xf0,
                  (i&2) ? 0xff : 0xf0,
                  (i&1) ? 0xff : 0xf0, TRUE);
}

static void
init_grays() {
    int i;
    for (i = 15; i < 255; i += 16)
        add_color(i, i, i, TRUE);
}

static void
init_mac_palette() {
    add_color(255, 255, 204, TRUE);
    add_color(255, 255, 0,   TRUE);
    add_color(255, 204, 153, TRUE);
    add_color(255, 102, 204, TRUE);
    add_color(255, 102, 51,  TRUE);
    add_color(221, 0, 0,     TRUE);
    add_color(204, 204, 255, TRUE);
    add_color(204, 153, 102, TRUE);
    add_color(153, 255, 255, TRUE);
    add_color(153, 153, 255, TRUE);
    add_color(153, 102, 153, TRUE);
    add_color(153, 0, 102,   TRUE);
    add_color(102, 102, 204, TRUE);
    add_color(51, 255, 153,  TRUE);
    add_color(51, 153, 102,  TRUE);
    add_color(51, 102, 102,  TRUE);
    add_color(51, 51, 102,   TRUE);
    add_color(51, 0, 153,    TRUE);
    add_color(0, 187, 0,     TRUE);
    add_color(0, 153, 255,   TRUE);
    add_color(0, 0, 221,     TRUE);
}

static void
init_virt_cmap(int tablesize, int testsize)
{
    int r, g, b;
    int gray = -1;
    CmapEntry *pCmap;
    unsigned int dotest[256];

    if (virt_cmap) {
        free(virt_cmap);
        virt_cmap = 0;
    }

    num_virt_cmap_entries = tablesize * tablesize * tablesize;
    virt_cmap = malloc(sizeof(CmapEntry) * num_virt_cmap_entries);
    /*
     * Fix for bug 4070647 malloc return value not check in img_colors.c
     * We have to handle the malloc failure differently under
     * Win32 and Solaris since under Solaris this file is linked with
     * libawt.so and under Win32 it's a separate awt_makecube.exe
     * application.
     */
    if (virt_cmap == NULL) {
#ifndef MAKECUBE_EXE
        JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
        JNU_ThrowOutOfMemoryError(env, "init_virt_cmap: OutOfMemoryError");
        return;
#else
        fprintf(stderr,"init_virt_cmap: OutOfMemoryError\n");
        exit(-1);
#endif
    }
    pCmap = virt_cmap;
    for (r = 0; r < total; r++) {
        if (cmap_r[r] == cmap_g[r] && cmap_g[r] == cmap_b[r]) {
            if (gray < 0 || cmap_r[gray] < cmap_r[r]) {
                gray = r;
            }
        }
    }
    if (gray < 0) {
#ifdef DEBUG
        jio_fprintf(stderr, "Didn't find any grays in color table!\n");
#endif /* DEBUG */
        gray = 0;
    }
    g = 0;
    b = 0;
    for (r = 0; r < tablesize - 1; ++r) {
        if (g >= 0) {
            b = r;
            dotest[r] = 1;
            g -= tablesize;
        } else {
            dotest[r] = 0;
        }
        prevtest[r] = b;
        g += testsize;
    }
    b = r;
    prevtest[r] = b;
    dotest[r] = 1;
    for (r = tablesize - 1; r >= 0; --r) {
        if (prevtest[r] == r) {
            b = r;
        }
        nexttest[r] = b;
    }
#ifdef DEBUG
    for (r = 0; r < tablesize; ++r) {
        if (dotest[r]) {
            if (prevtest[r] != r || nexttest[r] != r) {
                jio_fprintf(stderr, "prev/next != r!\n");
            }
        }
    }
#endif /* DEBUG */
    for (r = 0; r < tablesize; ++r)
    {
        int red = (int)(floor(r*255.0/(tablesize - 1)));
        for (g = 0; g < tablesize; ++g)
        {
            int green = (int)(floor(g*255.0/(tablesize - 1)));
            for (b = 0; b < tablesize; ++b)
            {
                int blue = (int)(floor(b*255.0/(tablesize - 1)));
                float t, d;
                if (pCmap >= virt_cmap + num_virt_cmap_entries) {
#ifdef DEBUG
                    jio_fprintf(stderr, "OUT OF pCmap CONVERSION SPACE!\n");
#endif /* DEBUG */
                    continue;           /* Shouldn't happen */
                }
                pCmap->red = red;
                pCmap->green = green;
                pCmap->blue = blue;
                LUV_convert(red, green, blue, &pCmap->L, &pCmap->U, &pCmap->V);
                if ((red != green || green != blue) &&
                    (!dotest[r] || !dotest[g] || !dotest[b]))
                {
                    pCmap->nextidx = -1;
                    pCmap++;
                    continue;
                }
                pCmap->bestidx = gray;
                pCmap->nextidx = 0;
                t = Ltab[gray] - pCmap->L;
                d = t * t;
                if (red == green && green == blue) {
                    pCmap->dist = d;
                    d *= Lscale;
                } else {
                    d *= Lscale;
                    t = Utab[gray] - pCmap->U;
                    d += t * t;
                    t = Vtab[gray] - pCmap->V;
                    d += t * t;
                    pCmap->dist = d;
                }
                pCmap->dE = WEIGHT_DIST(d, pCmap->L);
                pCmap++;
            }
        }
    }
#ifdef DEBUG
    if (pCmap < virt_cmap + num_virt_cmap_entries) {
        jio_fprintf(stderr, "Didn't fill pCmap conversion table!\n");
    }
#endif /* DEBUG */
}

static int
find_nearest(CmapEntry *pCmap) {
    int red = pCmap->red;
    int grn = pCmap->green;
    int blu = pCmap->blue;
    float L = pCmap->L;
    float dist;
    int i;

    if ((red == grn) && (grn == blu)) {
        dist = pCmap->dist;

        for (i = pCmap->nextidx; i < total; ++i) {
            float dL;

            if (cmap_r[i] != cmap_g[i] || cmap_g[i] != cmap_b[i]) {
                continue;
            }

            dL = Ltab[i] - L; dL *= dL;

            if (dL < dist) {
                dist = dL;
                pCmap->dist = dist;
                pCmap->dL = dist;
                pCmap->dE = WEIGHT_DIST(dist*Lscale,L);
                pCmap->bestidx = i;
            }
        }
        pCmap->nextidx = total;
    } else {
        float U = pCmap->U;
        float V = pCmap->V;
        dist = pCmap->dist;

        for (i = pCmap->nextidx; i < total; ++i) {
            float dL, dU, dV, dE;
            dL = Ltab[i] - L; dL *= (dL*Lscale);
            dU = Utab[i] - U; dU *= dU;
            dV = Vtab[i] - V; dV *= dV;

            dE = dL + dU + dV;
            if (dE < dist)
            {
                dist = dE;
                /* *delta = (dL/4) + dU + dV; */
                /* *delta = dist */
                /* *delta = dL + 100*(dU+dV)/(100+L); */
                pCmap->dist = dist;
                pCmap->dE = WEIGHT_DIST(dE, L);
                pCmap->dL = dL/Lscale;
                pCmap->bestidx = i;
            }
        }
        pCmap->nextidx = total;
    }

    return pCmap->bestidx;
}

#define MAX_OFFENDERS 32
static CmapEntry *offenders[MAX_OFFENDERS + 1];
static int num_offenders;

static void
insert_in_list(CmapEntry *pCmap)
{
    int i;
    float dE = pCmap->dE;

    for (i = num_offenders; i > 0; --i) {
        if (dE < offenders[i-1]->dE) break;
        offenders[i] = offenders[i-1];
    }

    offenders[i] = pCmap;
    if (num_offenders < MAX_OFFENDERS) ++num_offenders;
}

static void
handle_biggest_offenders(int testtblsize, int maxcolors) {
    int i, j;
    float dEthresh = 0;
    CmapEntry *pCmap;

    num_offenders = 0;

    for (pCmap = virt_cmap, i = 0; i < num_virt_cmap_entries; i++, pCmap++) {
        if (pCmap->nextidx < 0) {
            continue;
        }
        if (num_offenders == MAX_OFFENDERS
            && pCmap->dE < offenders[MAX_OFFENDERS-1]->dE)
        {
            continue;
        }
        find_nearest(pCmap);
        insert_in_list(pCmap);
    }

    if (num_offenders > 0) {
        dEthresh = offenders[num_offenders-1]->dE;
    }

    for (i = 0; (total < maxcolors) && (i < num_offenders); ++i) {
        pCmap = offenders[i];

        if (!pCmap) continue;

        j = add_color(pCmap->red, pCmap->green, pCmap->blue, FALSE);

        if (j) {
            for (j = i+1; j < num_offenders; ++j) {
                float dE;

                pCmap = offenders[j];
                if (!pCmap) {
                    continue;
                }

                find_nearest(pCmap);

                dE = pCmap->dE;
                if (dE < dEthresh) {
                    offenders[j] = 0;
                } else {
                    if (offenders[i+1] == 0 || dE > offenders[i+1]->dE) {
                        offenders[j] = offenders[i+1];
                        offenders[i+1] = pCmap;
                    }
                }
            }
        }
    }
}

void
img_makePalette(int cmapsize, int tablesize, int lookupsize,
                float lscale, float weight,
                int prevclrs, int doMac,
                unsigned char *reds,
                unsigned char *greens,
                unsigned char *blues,
                unsigned char *lookup)
{
    CmapEntry *pCmap;
    int i, ix;
#ifdef STATS
    double ave_dL, ave_dE;
    double max_dL, max_dE;
#endif /* STATS */
#ifdef TIMES
    clock_t start, mid, tbl, end;

    start = clock();
#endif /* TIMES */

    init_matrices();
    Lscale = lscale;
    Weight = weight;

    cmapmax = cmapsize;
    total = 0;
    for (i = 0; i < prevclrs; i++) {
        add_color(reds[i], greens[i], blues[i], TRUE);
    }

    add_color(0, 0, 0, TRUE);
    add_color(255,255,255, TRUE);

    /* do grays next; otherwise find_nearest may break! */
    init_grays();
    if (doMac) {
        init_mac_palette();
    }
    init_pastels();

    init_primaries();

    /* special case some blues */
    add_color(0,0,192,TRUE);
    add_color(0x30,0x20,0x80,TRUE);
    add_color(0x20,0x60,0xc0,TRUE);

    init_virt_cmap(lookupsize, tablesize);

    while (total < cmapsize) {
        handle_biggest_offenders(tablesize, cmapsize);
    }

    memcpy(reds, cmap_r, cmapsize);
    memcpy(greens, cmap_g, cmapsize);
    memcpy(blues, cmap_b, cmapsize);

#ifdef TIMES
    mid = clock();
#endif /* TIMES */

    pCmap = virt_cmap;
    for (i = 0; i < num_virt_cmap_entries; i++, pCmap++) {
        if (pCmap->nextidx < 0) {
            continue;
        }
        if (pCmap->nextidx < total) {
            ix = find_nearest(pCmap);
        }
    }

#ifdef TIMES
    tbl = clock();
#endif /* TIMES */

    pCmap = virt_cmap;
    if (tablesize != lookupsize) {
        int r, g, b;
        for (r = 0; r < lookupsize; ++r)
        {
            for (g = 0; g < lookupsize; ++g)
            {
                for (b = 0; b < lookupsize; ++b, pCmap++)
                {
                    float L, U, V;
                    float bestd = 0;
                    CmapEntry *pTest;

                    if (pCmap->nextidx >= 0) {
                        continue;
                    }
#ifdef DEBUG
                    if (r == g && g == b) {
                        jio_fprintf(stderr, "GRAY VALUE!?\n");
                    }
#endif /* DEBUG */
                    L = pCmap->L;
                    U = pCmap->U;
                    V = pCmap->V;
                    for (i = 0; i < 8; i++) {
                        int ri, gi, bi;
                        float d, t;
                        ri = (i & 1) ? prevtest[r] : nexttest[r];
                        gi = (i & 2) ? prevtest[g] : nexttest[g];
                        bi = (i & 4) ? prevtest[b] : nexttest[b];
                        pTest = &virt_cmap[((ri * lookupsize)
                                            + gi) * lookupsize
                                           + bi];
#ifdef DEBUG
                        if (pTest->nextidx < 0) {
                            jio_fprintf(stderr, "OOPS!\n");
                        }
#endif /* DEBUG */
                        ix = pTest->bestidx;
                        t = Ltab[ix] - L; d  = t * t * Lscale;
                        if (i != 0 && d > bestd) continue;
                        t = Utab[ix] - U; d += t * t;
                        if (i != 0 && d > bestd) continue;
                        t = Vtab[ix] - V; d += t * t;
                        if (i != 0 && d > bestd) continue;
                        bestd = d;
                        pCmap->bestidx = ix;
                    }
                }
            }
        }
    }
    pCmap = virt_cmap;
    for (i = 0; i < num_virt_cmap_entries; i++) {
        *lookup++ = (pCmap++)->bestidx;
    }

#ifdef TIMES
    end = clock();
#endif /* TIMES */

#ifdef STATS
    max_dL = 0.0;
    max_dE = 0.0;
    ave_dL = 0.0;
    ave_dE = 0.0;

    pCmap = virt_cmap;
    for (i = 0; i < num_virt_cmap_entries; i++, pCmap++) {
        double t, dL, dU, dV, dE;
        if (pCmap->nextidx < 0) {
            int ix = pCmap->bestidx;
            dL = pCmap->L - Ltab[ix]; dL *= dL;
            dU = pCmap->U - Utab[ix]; dU *= dU;
            dV = pCmap->V - Vtab[ix]; dV *= dV;
            dE = dL * Lscale + dU + dV;
            dE = WEIGHT_DIST(dE, pCmap->L);
        } else {
            dL = pCmap->dL;
            dE = pCmap->dE;
        }

        if (dL > max_dL) max_dL = dL;
        t = UNWEIGHT_DIST(dE,dL) - dL*(Lscale-1);
        if (t > max_dE) max_dE = t;

        ave_dL += (dL > 0) ? sqrt(dL) : 0.0;
        ave_dE += (t > 0) ? sqrt(t) : 0.0;
    }

    jio_fprintf(stderr, "colors=%d, tablesize=%d, cubesize=%d, ",
            cmapsize, tablesize, lookupsize);
    jio_fprintf(stderr, "Lscale=%5.3f, Weight=%5.3f mac=%s\n",
            (double)lscale, (double)weight, doMac ? "true" : "false");
    jio_fprintf(stderr, "Worst case error dL = %5.3f, dE = %5.3f\n",
            sqrt(max_dL), sqrt(max_dE));
    jio_fprintf(stderr, "Average error dL = %5.3f, dE = %5.3f\n",
            ave_dL / num_virt_cmap_entries,  ave_dE / num_virt_cmap_entries);
#endif /* STATS */
#ifdef TIMES
    jio_fprintf(stderr, "%f seconds to find colors\n",
            (double)(mid - start) / CLOCKS_PER_SEC);
    jio_fprintf(stderr, "%f seconds to finish nearest colors\n",
            (double)(tbl - mid) / CLOCKS_PER_SEC);
    jio_fprintf(stderr, "%f seconds to make lookup table\n",
            (double)(end - tbl) / CLOCKS_PER_SEC);
    jio_fprintf(stderr, "%f seconds total\n",
            (double)(end - start) / CLOCKS_PER_SEC);
#endif /* TIMES */

    free(virt_cmap);
    virt_cmap = 0;
}

Other Java examples (source code examples)

Here is a short list of links related to this Java img_colors.c source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.