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