1 #include "common.h"
2 
3 #include "blend.h"
4 #include "colormod.h"
5 #include "filter.h"
6 #include "image.h"
7 
8 /*\ Create and return an empty filter struct \*/
9 ImlibFilter        *
__imlib_CreateFilter(int size)10 __imlib_CreateFilter(int size)
11 {
12    ImlibFilter        *fil;
13 
14    fil = malloc(sizeof(ImlibFilter));
15    if (size > 0)
16      {
17         fil->alpha.pixels = malloc(size * sizeof(ImlibFilterPixel));
18         fil->red.pixels = malloc(size * sizeof(ImlibFilterPixel));
19         fil->green.pixels = malloc(size * sizeof(ImlibFilterPixel));
20         fil->blue.pixels = malloc(size * sizeof(ImlibFilterPixel));
21         fil->alpha.size = size;
22         fil->red.size = size;
23         fil->green.size = size;
24         fil->blue.size = size;
25      }
26    else
27      {
28         fil->alpha.pixels = 0;
29         fil->red.pixels = 0;
30         fil->green.pixels = 0;
31         fil->blue.pixels = 0;
32         fil->alpha.size = 0;
33         fil->red.size = 0;
34         fil->green.size = 0;
35         fil->blue.size = 0;
36      }
37    fil->alpha.entries = 0;
38    fil->red.entries = 0;
39    fil->green.entries = 0;
40    fil->blue.entries = 0;
41    fil->alpha.div = 0;
42    fil->red.div = 0;
43    fil->green.div = 0;
44    fil->blue.div = 0;
45    fil->alpha.cons = 0;
46    fil->red.cons = 0;
47    fil->green.cons = 0;
48    fil->blue.cons = 0;
49    return fil;
50 }
51 
52 /*\ Free a filter struct \*/
53 void
__imlib_FreeFilter(ImlibFilter * fil)54 __imlib_FreeFilter(ImlibFilter * fil)
55 {
56    free(fil->alpha.pixels);
57    free(fil->red.pixels);
58    free(fil->green.pixels);
59    free(fil->blue.pixels);
60    free(fil);
61 }
62 
63 void
__imlib_FilterSetColor(ImlibFilterColor * fil,int x,int y,int a,int r,int g,int b)64 __imlib_FilterSetColor(ImlibFilterColor * fil, int x, int y,
65                        int a, int r, int g, int b)
66 {
67    int                 i;
68    ImlibFilterPixel   *pix = fil->pixels;
69 
70    /*\ Look for an entry matching (x, y) \ */
71    for (i = fil->entries; --i >= 0;)
72      {
73         if ((pix[i].xoff == x) && (pix[i].yoff == y))
74            break;
75      }
76    /*\ If all zero, remove the found entry \ */
77    if (!(a | r | g | b))
78      {
79         if (i >= 0)
80           {
81              while (i < fil->entries)
82                {
83                   pix[i] = pix[i + 1];
84                }
85              fil->entries--;
86           }
87         return;
88      }
89    /*\ No match, then make a new entry \ */
90    if (i < 0)
91       i = fil->entries;
92    if (i >= fil->size)
93      {
94         fil->size += 4;
95         pix = realloc(pix, (fil->size * sizeof(ImlibFilterPixel)));
96         if (!pix)
97            return;
98         fil->pixels = pix;
99      }
100    if (i >= fil->entries)
101       fil->entries = i + 1;
102    pix[i].xoff = x;
103    pix[i].yoff = y;
104    pix[i].a = a;
105    pix[i].r = r;
106    pix[i].g = g;
107    pix[i].b = b;
108 }
109 
110 /*\ Set the divisors manually \*/
111 void
__imlib_FilterDivisors(ImlibFilter * fil,int a,int r,int g,int b)112 __imlib_FilterDivisors(ImlibFilter * fil, int a, int r, int g, int b)
113 {
114    fil->alpha.div = a;
115    fil->red.div = r;
116    fil->green.div = g;
117    fil->blue.div = b;
118 }
119 
120 /*\ Set the constants \*/
121 void
__imlib_FilterConstants(ImlibFilter * fil,int a,int r,int g,int b)122 __imlib_FilterConstants(ImlibFilter * fil, int a, int r, int g, int b)
123 {
124    fil->alpha.cons = a;
125    fil->red.cons = r;
126    fil->green.cons = g;
127    fil->blue.cons = b;
128 }
129 
130 static int
__imlib_FilterCalcDiv(ImlibFilterColor * fil)131 __imlib_FilterCalcDiv(ImlibFilterColor * fil)
132 {
133    int                 i, ret;
134    ImlibFilterPixel   *pix;
135 
136    if (fil->div)
137       return fil->div;
138    ret = 0;
139    pix = fil->pixels;
140    for (i = fil->entries; --i >= 0;)
141      {
142         ret += pix->a + pix->r + pix->g + pix->b;
143         pix++;
144      }
145    return ret;
146 }
147 
148 static int
__imlib_FilterGet(ImlibFilterColor * fil,DATA32 * data,int w,int h,int x,int y)149 __imlib_FilterGet(ImlibFilterColor * fil, DATA32 * data,
150                   int w, int h, int x, int y)
151 {
152    int                 i, off, ret;
153    ImlibFilterPixel   *pix;
154    DATA32             *p;
155 
156    ret = fil->cons;
157    pix = fil->pixels;
158    for (i = fil->entries; --i >= 0;)
159      {
160         off = x + pix->xoff;
161         if (off < 0)
162            off = 0;
163         if (off >= w)
164            off = w - 1;
165         p = data + off;
166         off = y + pix->yoff;
167         if (off < 0)
168            off = 0;
169         if (off >= h)
170            off = h - 1;
171         p += off * w;
172         ret += A_VAL(p) * pix->a + R_VAL(p) * pix->r +
173            G_VAL(p) * pix->g + B_VAL(p) * pix->b;
174         pix++;
175      }
176    return ret;
177 }
178 
179 /*\ Correct saturation from [-32768, 32767] to [0, 255] \*/
180 #define SATURATE(x) ((((x) | (!((x) >> 8) - 1)) & (~((x) >> 31))) & 0xff)
181 
182 /*\ Filter an image with the a, r, g, b filters in fil
183 |*|  NB: This is currently not very optimal, and could probably be improved
184 \*/
185 void
__imlib_FilterImage(ImlibImage * im,ImlibFilter * fil)186 __imlib_FilterImage(ImlibImage * im, ImlibFilter * fil)
187 {
188    int                 x, y, a, r, g, b, ad, rd, gd, bd;
189    DATA32             *data, *p1, *p2;
190 
191    data = malloc(im->w * im->h * sizeof(DATA32));
192    if (!data)
193       return;
194 
195    ad = __imlib_FilterCalcDiv(&fil->alpha);
196    rd = __imlib_FilterCalcDiv(&fil->red);
197    gd = __imlib_FilterCalcDiv(&fil->green);
198    bd = __imlib_FilterCalcDiv(&fil->blue);
199 
200    p1 = im->data;
201    p2 = data;
202 
203    for (y = 0; y < im->h; y++)
204      {
205         for (x = 0; x < im->w; x++)
206           {
207              *p2 = *p1;
208              if (ad)
209                {
210                   a = __imlib_FilterGet(&fil->alpha, im->data, im->w, im->h, x,
211                                         y);
212                   a /= ad;
213                   A_VAL(p2) = SATURATE(a);
214                }
215              if (rd)
216                {
217                   r = __imlib_FilterGet(&fil->red, im->data, im->w, im->h, x,
218                                         y);
219                   r /= rd;
220                   R_VAL(p2) = SATURATE(r);
221                }
222              if (gd)
223                {
224                   g = __imlib_FilterGet(&fil->green, im->data, im->w, im->h, x,
225                                         y);
226                   g /= gd;
227                   G_VAL(p2) = SATURATE(g);
228                }
229              if (bd)
230                {
231                   b = __imlib_FilterGet(&fil->blue, im->data, im->w, im->h, x,
232                                         y);
233                   b /= bd;
234                   B_VAL(p2) = SATURATE(b);
235                }
236              p1++;
237              p2++;
238           }
239      }
240    __imlib_ReplaceData(im, data);
241 }
242