1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18
19#include "filters.h"
20
21void estmateWhite(unsigned char *src, int len, int *wr, int *wb, int *wg){
22
23    int STEP = 4;
24    int RANGE = 256;
25    int *histR = (int *) malloc(256*sizeof(int));
26    int *histG = (int *) malloc(256*sizeof(int));
27    int *histB = (int *) malloc(256*sizeof(int));
28    int i;
29    for (i = 0; i < 255; i++) {
30        histR[i] = histG[i] = histB[i] =0;
31    }
32
33    for (i = 0; i < len; i+=STEP) {
34        histR[(src[RED])]++;
35        histG[(src[GREEN])]++;
36        histB[(src[BLUE])]++;
37    }
38    int min_r = -1, min_g = -1,min_b = -1;
39    int max_r = 0, max_g = 0,max_b = 0;
40    int sum_r = 0,sum_g=0,sum_b=0;
41
42    for (i = 1; i < RANGE-1; i++) {
43        int r = histR[i];
44        int g = histG[i];
45        int b = histB[i];
46        sum_r += r;
47        sum_g += g;
48        sum_b += b;
49
50        if (r>0){
51            if (min_r < 0) min_r = i;
52            max_r = i;
53        }
54        if (g>0){
55            if (min_g < 0) min_g = i;
56            max_g = i;
57        }
58        if (b>0){
59            if (min_b < 0) min_b = i;
60            max_b = i;
61        }
62    }
63
64    int sum15r = 0,sum15g=0,sum15b=0;
65    int count15r = 0,count15g=0,count15b=0;
66    int tmp_r = 0,tmp_g=0,tmp_b=0;
67
68    for (i = RANGE-2; i >0; i--) {
69        int r = histR[i];
70        int g = histG[i];
71        int b = histB[i];
72        tmp_r += r;
73        tmp_g += g;
74        tmp_b += b;
75
76        if ((tmp_r > sum_r/20) && (tmp_r < sum_r/5)) {
77            sum15r += r*i;
78            count15r += r;
79        }
80        if ((tmp_g > sum_g/20) && (tmp_g < sum_g/5)) {
81            sum15g += g*i;
82            count15g += g;
83        }
84        if ((tmp_b > sum_b/20) && (tmp_b < sum_b/5)) {
85            sum15b += b*i;
86            count15b += b;
87        }
88
89    }
90    free(histR);
91    free(histG);
92    free(histB);
93
94    if ((count15r>0) && (count15g>0) && (count15b>0) ){
95        *wr = sum15r/count15r;
96        *wb = sum15g/count15g;
97        *wg = sum15b/count15b;
98    }else {
99        *wg  = *wb = *wr=255;
100    }
101}
102
103void estmateWhiteBox(unsigned char *src, int iw, int ih, int x,int y, int *wr, int *wb, int *wg){
104    int r = 0;
105    int g = 0;
106    int b = 0;
107    int sum = 0;
108    int xp,yp;
109    int bounds = 5;
110    if (x<0) x = bounds;
111    if (y<0) y = bounds;
112    if (x>=(iw-bounds)) x = (iw-bounds-1);
113    if (y>=(ih-bounds)) y = (ih-bounds-1);
114    int startx = x - bounds;
115    int starty = y - bounds;
116    int endx = x + bounds;
117    int endy = y + bounds;
118
119    for(yp= starty;yp<endy;yp++) {
120        for(xp= startx;xp<endx;xp++) {
121            int i = 4*(xp+yp*iw);
122            r += src[RED];
123            g += src[GREEN];
124            b += src[BLUE];
125            sum++;
126        }
127    }
128    *wr = r/sum;
129    *wg = g/sum;
130    *wb = b/sum;
131}
132
133void JNIFUNCF(ImageFilterWBalance, nativeApplyFilter, jobject bitmap, jint width, jint height, int locX,int locY)
134{
135    char* destination = 0;
136    AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
137    int i;
138    int len = width * height * 4;
139    unsigned char * rgb = (unsigned char * )destination;
140    int wr;
141    int wg;
142    int wb;
143
144    if (locX==-1)
145        estmateWhite(rgb,len,&wr,&wg,&wb);
146    else
147        estmateWhiteBox(rgb, width, height,locX,locY,&wr,&wg,&wb);
148
149    int min = MIN(wr, MIN(wg, wb));
150    int max = MAX(wr, MAX(wg, wb));
151    float avg = (min+max)/2.f;
152    float scaleR =  avg/wr;
153    float scaleG =  avg/wg;
154    float scaleB =  avg/wb;
155
156    for (i = 0; i < len; i+=4)
157    {
158        int r = rgb[RED];
159        int g = rgb[GREEN];
160        int b = rgb[BLUE];
161
162        float Rc =  r*scaleR;
163        float Gc =  g*scaleG;
164        float Bc =  b*scaleB;
165
166        rgb[RED]   = clamp(Rc);
167        rgb[GREEN] = clamp(Gc);
168        rgb[BLUE]  = clamp(Bc);
169    }
170    AndroidBitmap_unlockPixels(env, bitmap);
171}
172