Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 384 lines (303 sloc) 7.733 kb
d3a51f7 @fsphil Updated URLs and email address to new domain.
authored
1 /* fswebcam - FireStorm.cx's webcam generator */
2 /*============================================================*/
e9e2f15 @fsphil Update for 20110717 release
authored
3 /* Copyright (C)2005-2011 Philip Heron <phil@sanslogic.co.uk> */
d3a51f7 @fsphil Updated URLs and email address to new domain.
authored
4 /* */
5 /* This program is distributed under the terms of the GNU */
6 /* General Public License, version 2. You may use, modify, */
7 /* and redistribute it under the terms of this license. A */
8 /* copy should be included with this source. */
b94f24a @fsphil initial check-in
authored
9
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
14 #include <stdint.h>
15 #include <stdlib.h>
97911c8 @fsphil Add option to swap colour channels
authored
16 #include <string.h>
227f990 @fsphil Fix compiler warnings
authored
17 #include <ctype.h>
b94f24a @fsphil initial check-in
authored
18 #include <gd.h>
19 #include "parse.h"
20 #include "log.h"
21
22 /* These helper macros should maybe be moved elsewhere. */
23
24 #define RGB(r, g, b) ((r << 16) + (g << 8) + b)
25
26 #define R(c) ((c & 0xFF0000) >> 16)
27 #define G(c) ((c & 0xFF00) >> 8)
28 #define B(c) (c & 0xFF)
29
30 #define GREY(c) ((R(c) + G(c) + B(c)) / 3)
31 #define MIX(a, b, c) (a + (((b - a) * c) / 0xFF))
32
33 #define RGBMIX(c1, c2, d) \
34 (RGB(MIX(R(c1), R(c2), d), MIX(G(c1), G(c2), d), MIX(B(c1), G(c2), d)))
35
36 gdImage *fx_flip(gdImage *src, char *options)
37 {
38 int i;
39 char d[32];
40
41 i = 0;
42 while(!argncpy(d, 32, options, ", \t", i++, 0))
43 {
44 if(*d == 'v')
45 {
46 int y, h;
47 gdImage *line;
48
49 MSG("Flipping image vertically.");
50
51 line = gdImageCreateTrueColor(gdImageSX(src), 1);
52 h = gdImageSY(src) / 2;
53
54 for(y = 0; y < h; y++)
55 {
56 /* Copy bottom line into buffer. */
57 gdImageCopy(line, src,
58 0, 0,
59 0, gdImageSY(src) - y - 1,
60 gdImageSX(src), 1);
61
62 /* Copy the top line onto the bottom. */
63 gdImageCopy(src, src,
64 0, gdImageSY(src) - y - 1,
65 0, y,
66 gdImageSX(src), 1);
67
68 /* Copy the buffer into the top. */
69 gdImageCopy(src, line,
70 0, y,
71 0, 0,
72 gdImageSX(src), 1);
73 }
74
75 gdImageDestroy(line);
76 }
77 else if(*d == 'h')
78 {
79 int x, w;
80 gdImage *line;
81
82 MSG("Flipping image horizontally.");
83
84 line = gdImageCreateTrueColor(1, gdImageSY(src));
85 w = gdImageSX(src) / 2;
86
87 for(x = 0; x < w; x++)
88 {
89 /* Copy right line into buffer. */
90 gdImageCopy(line, src,
91 0, 0,
92 gdImageSX(src) - x - 1, 0,
93 1, gdImageSY(src));
94
95 /* Copy the left line onto the right. */
96 gdImageCopy(src, src,
97 gdImageSX(src) - x - 1, 0,
98 x, 0,
99 1, gdImageSY(src));
100
101 /* Copy the buffer into the left. */
102 gdImageCopy(src, line,
103 x, 0,
104 0, 0,
105 1, gdImageSY(src));
106 }
107
108 gdImageDestroy(line);
109 }
110 else WARN("Unknown flip direction: %s", d);
111 }
112
113 return(src);
114 }
115
116 gdImage *fx_crop(gdImage *src, char *options)
117 {
118 char arg[32];
119 int w, h, x, y;
120 gdImage *im;
121
122 if(argncpy(arg, 32, options, ", \t", 0, 0))
123 {
124 WARN("Invalid area to crop: %s", arg);
125 return(src);
126 }
127
128 w = argtol(arg, "x ", 0, 0, 10);
129 h = argtol(arg, "x ", 1, 0, 10);
130
131 if(w < 0 || h < 0)
132 {
133 WARN("Invalid area to crop: %s", arg);
134 return(src);
135 }
136
137 /* Make sure crop area resolution is smaller than the source image. */
138 if(w > gdImageSX(src) ||
139 h > gdImageSY(src))
140 {
141 WARN("Crop area is larger than the image!");
142 return(src);
143 }
144
145 /* Get the offset. */
146 x = -1;
147 y = -1;
148
149 if(!argncpy(arg, 32, options, ", \t", 1, 0))
150 {
151 x = argtol(arg, "x ", 0, 0, 10);
152 y = argtol(arg, "x ", 1, 0, 10);
153 }
154
155 if(x < 0 || y < 0)
156 {
157 /* By default crop the center of the image. */
158 x = (gdImageSX(src) - w) / 2;
159 y = (gdImageSY(src) - h) / 2;
160 }
161
162 MSG("Cropping image from %ix%i [offset: %ix%i] -> %ix%i.",
163 gdImageSX(src), gdImageSY(src), x, y, w, h);
164
165 im = gdImageCreateTrueColor(w, h);
166 if(!im)
167 {
168 WARN("Out of memory.");
169 return(src);
170 }
171
172 gdImageCopy(im, src, 0, 0, x, y, w, h);
173
174 gdImageDestroy(src);
175
176 return(im);
177 }
178
179 gdImage *fx_scale(gdImage *src, char *options)
180 {
181 int w, h;
182 gdImage *im;
183
184 w = argtol(options, "x ", 0, 0, 10);
185 h = argtol(options, "x ", 1, 0, 10);
186
187 if(w < 0 || h < 0)
188 {
189 WARN("Invalid resolution: %s", options);
190 return(src);
191 }
192
193 MSG("Scaling image from %ix%i -> %ix%i.",
194 gdImageSX(src), gdImageSY(src), w, h);
195
196 im = gdImageCreateTrueColor(w, h);
197 if(!im)
198 {
199 WARN("Out of memory.");
200 return(src);
201 }
202
203 gdImageCopyResampled(im, src, 0, 0, 0, 0,
204 w, h, gdImageSX(src), gdImageSY(src));
205
206 gdImageDestroy(src);
207
208 return(im);
209 }
210
211 gdImage *fx_rotate(gdImage *src, char *options)
212 {
213 int x, y;
214 gdImage *im;
215 int angle = atoi(options);
216
217 /* Restrict angle to 0-360 range. */
218 if((angle %= 360) < 0) angle += 360;
219
220 /* Round to nearest right angle. */
221 x = (angle + 45) % 360;
222 angle = x - (x % 90);
223
224 /* Not rotating 0 degrees. */
225 if(angle == 0)
226 {
227 MSG("Not rotating 0 degrees.");
228 return(src);
229 }
230
231 /* 180 can be done with two flips. */
232 if(angle == 180)
233 {
234 fx_flip(src, "h,v");
235 return(src);
236 }
237
238 MSG("Rotating image %i degrees. %ix%i -> %ix%i.", angle,
239 gdImageSX(src), gdImageSY(src),
240 gdImageSY(src), gdImageSX(src));
241
242 /* Create rotated image. */
243 im = gdImageCreateTrueColor(gdImageSY(src), gdImageSX(src));
244 if(!im)
245 {
246 WARN("Out of memory.");
247 return(src);
248 }
249
250 for(y = 0; y < gdImageSY(src); y++)
251 for(x = 0; x < gdImageSX(src); x++)
252 {
253 int c = gdImageGetPixel(src, x, y);
254
255 if(angle == 90)
256 {
257 gdImageSetPixel(im, gdImageSX(im) - y - 1, x, c);
258 }
259 else
260 {
261 gdImageSetPixel(im, y, gdImageSY(im) - x - 1, c);
262 }
263 }
264
265 gdImageDestroy(src);
266
267 return(im);
268 }
269
270 /*
271 * This is a very simple and experimental deinterlacer,
272 * there is a lot of room for improvement here.
273 *
274 * (For example: Making it work)
275 *
276 */
277 gdImage *fx_deinterlace(gdImage *src, char *options)
278 {
279 int x, y;
280
281 MSG("Deinterlacing image.");
282
283 for(y = 1; y < gdImageSY(src) - 1; y += 2)
284 {
285 for(x = 0; x < gdImageSX(src); x++)
286 {
287 int c, cu, cd, d;
288
289 c = gdImageGetPixel(src, x, y);
290 cu = gdImageGetPixel(src, x, y - 1);
291 cd = gdImageGetPixel(src, x, y + 1);
292
293 /* Calculate the difference of the pixel (x,y) from
294 * the average of it's neighbours above and below. */
295 d = 0xFF - abs(GREY(cu) - GREY(cd));
296 d = (abs(GREY(cu) - (0xFF - GREY(c)) - GREY(cd)) * d) / 0xFF;
297
298 c = RGBMIX(c, RGBMIX(cu, cd, 128), d);
299
300 gdImageSetPixel(src, x, y, c);
301 }
302 }
303
304 return(src);
305 }
306
307 gdImage *fx_invert(gdImage *src, char *options)
308 {
309 int x, y;
310
311 MSG("Inverting image.");
312
313 for(y = 0; y < gdImageSY(src); y++)
314 for(x = 0; x < gdImageSX(src); x++)
315 {
316 /* Overwrite the pixel with a negative of its value. */
317 gdImageSetPixel(src, x, y,
318 0xFFFFFF - gdImageGetPixel(src, x, y));
319 }
320
321 return(src);
322 }
323
324 gdImage *fx_greyscale(gdImage *src, char *options)
325 {
326 int x, y;
327
328 MSG("Greyscaling image.");
329
330 for(y = 0; y < gdImageSY(src); y++)
331 for(x = 0; x < gdImageSX(src); x++)
332 {
333 uint8_t c = GREY(gdImageGetPixel(src, x, y));
334 gdImageSetPixel(src, x, y, RGB(c, c, c));
335 }
336
337 return(src);
338 }
339
97911c8 @fsphil Add option to swap colour channels
authored
340 gdImage *fx_swapchannels(gdImage *src, char *options)
341 {
342 int mode;
343 int x, y;
344
345 if(strlen(options) != 2)
346 {
347 WARN("You can only swap two channels: %s", options);
348 return(src);
349 }
350
351 for(mode = 0, x = 0; x < 2; x++)
352 {
353 char c = toupper(options[x]);
354 if(c == 'R') mode += 0;
355 else if(c == 'G') mode += 1;
356 else if(c == 'B') mode += 2;
357 else mode += 4;
358 }
359
360 if(mode < 1 || mode > 3)
361 {
362 WARN("Cannot swap colour channels '%s'", options);
363 return(src);
364 }
365
366 MSG("Swapping colour channels %c <> %c",
367 toupper(options[0]), toupper(options[1]));
368
369 for(y = 0; y < gdImageSY(src); y++)
370 for(x = 0; x < gdImageSX(src); x++)
371 {
372 int c = gdImageGetPixel(src, x, y);
373
374 if(mode == 1) c = RGB(G(c), R(c), B(c));
375 else if(mode == 2) c = RGB(B(c), G(c), R(c));
376 else if(mode == 3) c = RGB(R(c), B(c), G(c));
377
378 gdImageSetPixel(src, x, y, c);
379 }
380
381 return(src);
382 }
383
Something went wrong with that request. Please try again.