summaryrefslogtreecommitdiff
path: root/embiance.c
blob: 286b37383763489ebe70c808f3352ef05326ed55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "Embiance.h"

#define WARN(f, __VAR_ARGS__) fprintf(stderr, "WARN:" f "\n", __VAR_ARGS__)

static unsigned int _rotl(const unsigned int value, int shift) {
        if ((shift &= sizeof(value)*8 - 1) == 0)
                    return value;
            return (value << shift) | (value >> (sizeof(value)*8 - shift));
}

static unsigned int ARGBtoRGBA(unsigned int argb)
{
        return _rotl(argb, 8);
}

static void _argb_to_rgba(void *imgData, size_t n)
{
    unsigned int i = 0;
    /* convert ARGB to RGBA */
    for (i = 0; i < n; i++)
    {
        ((unsigned int*)imgData)[i] = ARGBtoRGBA(((unsigned int*)imgData)[i]);
    }
}

unsigned int evas_object_image_frequent_colors_get_median_cut(Evas_Object *obj, unsigned int ncolors, l_int32 **r, l_int32 **g, l_int32 **b)
{
    PIX     *pixs = NULL, *cut = NULL;
    PIXCMAP *cmap_cut = NULL;
    unsigned int ncolors_found = 0;
    Eina_Rectangle size;
    void *imgData;
    l_int32 *rr, *gg, *bb;

    evas_object_image_size_get(obj, &size.w, &size.h);

    pixs = pixCreateHeader(size.w, size.h, 32);
    imgData = malloc(size.w * size.h * sizeof(l_int32));
    memcpy(imgData, evas_object_image_data_get(obj, EINA_FALSE), (size.w * size.h * sizeof(l_int32)));
    _argb_to_rgba(imgData, (size.w * size.h));
    pixSetData(pixs, imgData);

    cut = pixMedianCutQuantGeneral(pixs, 0, 0, ncolors, 0, 0, 1);

    cmap_cut = pixGetColormap(cut);
    ncolors_found = pixcmapGetCount(cmap_cut);

    pixcmapToArrays(cmap_cut, r, g, b);

    rr = calloc(ncolors_found, sizeof(l_int32));
    gg = calloc(ncolors_found, sizeof(l_int32));
    bb = calloc(ncolors_found, sizeof(l_int32));

    memcpy(rr, *r, (ncolors_found * sizeof(l_int32)));
    memcpy(gg, *g, (ncolors_found * sizeof(l_int32)));
    memcpy(bb, *b, (ncolors_found * sizeof(l_int32)));

    *r = rr;
    *g = gg;
    *b = bb;

    pixDestroy(&cut);
    pixDestroy(&pixs);

    return ncolors_found;
}

unsigned int evas_object_image_frequent_colors_get_histo(Evas_Object *obj, unsigned int ncolors, unsigned int sigbits, l_int32 **rr, l_int32 **rg, l_int32 **rb)
{
    PIX     *pixs = NULL;
    Eina_Rectangle size;
    void *imgData;
    unsigned int i, j; 
    NUMA *na = NULL;
    l_int32 hvals[ncolors + 1];
    const unsigned int nchannel = 3;
    unsigned int word_width;
    l_int32 *r, *g, *b;
    l_int32 hval;
    unsigned int hr = 0, hg = 0, hb = 0;
    unsigned int segment, shifted_index_val;

    if (sigbits > 6)
        sigbits = 6;
    else if (sigbits < 1)
        sigbits = 1;
    word_width = (sigbits * nchannel);

    evas_object_image_size_get(obj, &size.w, &size.h);

    pixs = pixCreateHeader(size.w, size.h, 32);
    imgData = malloc(size.w * size.h * sizeof(l_int32));
    memcpy(imgData, evas_object_image_data_get(obj, EINA_FALSE), (size.w * size.h * sizeof(l_int32)));
    _argb_to_rgba(imgData, (size.w * size.h));
    pixSetData(pixs, imgData);

    r = calloc((ncolors + 1), sizeof(l_int32));
    g = calloc((ncolors + 1), sizeof(l_int32));
    b = calloc((ncolors + 1), sizeof(l_int32));

#define BIT(v, i) ((v >> ((word_width - 1) - i)) & 0x1)

    na = pixOctcubeHistogram(pixs, sigbits, NULL);
    memset(hvals, 0, ((ncolors + 1) * sizeof(l_int32)));
    for (i = 0; i < numaGetCount(na); i++)
    {
        numaGetIValue(na, i, &hval);
        if (hval == 0)
            continue;
        if (hval > hvals[ncolors - 1])
        {
            hr = hg = hb = 0;
            for (segment = 0, shifted_index_val = i; segment < sigbits; segment++, (shifted_index_val <<= nchannel))
            {
                hr = (hr << 1) | BIT(shifted_index_val, 0);
                hg = (hg << 1) | BIT(shifted_index_val, 1);
                hb = (hb << 1) | BIT(shifted_index_val, 2);
            }

            hr = (hr << (8 - sigbits));
            hg = (hg << (8 - sigbits));
            hb = (hb << (8 - sigbits));

            for (j = 0; j < ncolors; j++)
            {
                if (hval > hvals[j])
                {
                    if (hvals[j] != 0)
                    {
                        memmove(&r[j + 1], &r[j], ((ncolors - j) * sizeof(l_int32)));
                        memmove(&g[j + 1], &g[j], ((ncolors - j) * sizeof(l_int32)));
                        memmove(&b[j + 1], &b[j], ((ncolors - j) * sizeof(l_int32)));
                        memmove(&hvals[j + 1], &hvals[j], ((ncolors - j) * sizeof(l_int32)));
                    }
                    r[j] = hr;
                    g[j] = hg;
                    b[j] = hb;
                    hvals[j] = hval;
                    break;
                }
            }
        }
    }

    *rr = r;
    *rg = g;
    *rb = b;

    numaDestroy(&na);
    pixDestroy(&pixs);

    return ncolors;
}