source: libpipi/trunk/pipi/context.c @ 3418

Last change on this file since 3418 was 3418, checked in by Sam Hocevar, 11 years ago

wave.c: implement pipi_wave() in addition to pipi_sine(). The effect is
not yet satisfying.

File size: 19.1 KB
Line 
1/*
2 *  libpipi       Pathetic image processing interface library
3 *  Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
4 *                All Rights Reserved
5 *
6 *  $Id$
7 *
8 *  This library is free software. It comes without any warranty, to
9 *  the extent permitted by applicable law. You can redistribute it
10 *  and/or modify it under the terms of the Do What The Fuck You Want
11 *  To Public License, Version 2, as published by Sam Hocevar. See
12 *  http://sam.zoy.org/wtfpl/COPYING for more details.
13 */
14
15/*
16 * context.c: processing stack handling routines
17 */
18
19#include "config.h"
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdarg.h>
24#include <string.h>
25
26#include "pipi.h"
27#include "pipi_internals.h"
28
29pipi_context_t *pipi_create_context()
30{
31    pipi_context_t *ret;
32
33    ret = malloc(sizeof(pipi_context_t));
34    memset(ret, 0, sizeof(pipi_context_t));
35
36    return ret;
37}
38
39void pipi_destroy_context(pipi_context_t *ctx)
40{
41    free(ctx);
42}
43
44pipi_command_t const *pipi_get_command_list(void)
45{
46    static pipi_command_t const list[] =
47    {
48        { "load", 1 },
49        { "save", 1 },
50
51        { "dup", 0 },
52        { "swap", 0 },
53        { "roll", 1 },
54
55        { "gamma", 1 },
56        { "scale", 1 },
57        { "crop", 1 },
58        { "geometry", 1 },
59        { "tile", 1 },
60        { "dither", 1 },
61        { "blur", 1 },
62        { "boxblur", 1 },
63        { "median", 1 },
64        { "gray", 0 },
65        { "brightness", 1 },
66        { "contrast", 1 },
67        { "autocontrast", 0 },
68        { "order", 0 },
69        { "hflip", 0 },
70        { "vflip", 0 },
71        { "rotate90", 0 },
72        { "rotate180", 0 },
73        { "rotate270", 0 },
74        { "invert", 0 },
75        { "threshold", 1 },
76        { "dilate", 0 },
77        { "erode", 0 },
78        { "wrap", 0 },
79        { "combine", 0 },
80        { "split", 0 },
81        { "mean", 0 },
82        { "merge", 1 },
83        { "min", 0 },
84        { "max", 0 },
85        { "add", 0 },
86        { "sub", 0 },
87        { "difference", 0 },
88        { "multiply", 0 },
89        { "divide", 0 },
90        { "screen", 0 },
91        { "overlay", 0 },
92        { "line", 1 },
93        { "sine", 1 },
94        { "wave", 1 },
95
96        /* End marker */
97        { NULL, 0 }
98    };
99
100    return list;
101}
102
103int pipi_command(pipi_context_t *ctx, char const *cmd, ...)
104{
105    if(!strcmp(cmd, "load"))
106    {
107        char const *file;
108        va_list ap;
109
110        va_start(ap, cmd);
111        file = va_arg(ap, char const *);
112        va_end(ap);
113        ctx->images[ctx->nimages] = pipi_load(file);
114        if(ctx->images[ctx->nimages] == NULL)
115            return -1;
116        ctx->nimages++;
117    }
118    else if(!strcmp(cmd, "save"))
119    {
120        char const *file;
121        va_list ap;
122
123        if(ctx->nimages < 1)
124            return -1;
125        ctx->nimages--;
126        va_start(ap, cmd);
127        file = va_arg(ap, char const *);
128        va_end(ap);
129        pipi_save(ctx->images[ctx->nimages], file);
130        pipi_free(ctx->images[ctx->nimages]);
131    }
132    else if(!strcmp(cmd, "gamma"))
133    {
134        char const *val;
135        va_list ap;
136
137        va_start(ap, cmd);
138        val = va_arg(ap, char const *);
139        va_end(ap);
140
141        pipi_set_gamma(atof(val));
142    }
143    else if(!strcmp(cmd, "dither"))
144    {
145        pipi_image_t *src, *dst;
146        char const *method;
147        va_list ap;
148
149        if(ctx->nimages < 1)
150            return -1;
151        va_start(ap, cmd);
152        method = va_arg(ap, char const *);
153        va_end(ap);
154        src = ctx->images[ctx->nimages - 1];
155        dst = NULL;
156        if(!strcmp(method, "ost"))
157            dst = pipi_dither_ostromoukhov(src, 0);
158        else if(!strcmp(method, "sost"))
159            dst = pipi_dither_ostromoukhov(src, 1);
160        else if(!strcmp(method, "ediff"))
161        {
162            if(ctx->nimages < 2)
163                return -1;
164            dst = pipi_dither_ediff(ctx->images[ctx->nimages - 2], src, 0);
165            pipi_free(ctx->images[ctx->nimages - 2]);
166            ctx->nimages--;
167        }
168        else if(!strcmp(method, "sediff"))
169        {
170            if(ctx->nimages < 2)
171                return -1;
172            dst = pipi_dither_ediff(ctx->images[ctx->nimages - 2], src, 1);
173            pipi_free(ctx->images[ctx->nimages - 2]);
174            ctx->nimages--;
175        }
176        else if(!strncmp(method, "ordered", 7))
177        {
178            double scale = 1., angle = .0;
179            if(ctx->nimages < 2)
180                return -1;
181            method = strchr(method, ':');
182            if(method)
183            {
184                scale = atof(method + 1);
185                method = strchr(method + 1, ':');
186                if(method)
187                    angle = atof(method + 1);
188            }
189            if(scale <= 0.)
190                scale = 1.;
191            dst = pipi_dither_ordered_ext(ctx->images[ctx->nimages - 2], src,
192                                          scale, angle);
193            pipi_free(ctx->images[ctx->nimages - 2]);
194            ctx->nimages--;
195        }
196        else if(!strncmp(method, "halftone", 8))
197        {
198            double r, angle = .0;
199            method = strchr(method, ':');
200            if(!method)
201                return -1;
202            r = atof(method + 1);
203            method = strchr(method + 1, ':');
204            if(method)
205                angle = atof(method + 1);
206            if(r < 1.)
207                r = 1.;
208            dst = pipi_dither_halftone(src, r, angle);
209        }
210        else if(!strcmp(method, "random"))
211            dst = pipi_dither_random(src);
212        else if(!strcmp(method, "dbs"))
213            dst = pipi_dither_dbs(src);
214        if(dst == NULL)
215            return -1;
216        pipi_free(src);
217        ctx->images[ctx->nimages - 1] = dst;
218    }
219    else if(!strcmp(cmd, "blur"))
220    {
221        pipi_image_t *src, *dst;
222        char const *arg;
223        va_list ap;
224        double w, h, a = 0.0;
225
226        if(ctx->nimages < 1)
227            return -1;
228        va_start(ap, cmd);
229        arg = va_arg(ap, char const *);
230        va_end(ap);
231        w = h = atof(arg);
232        arg = strchr(arg, 'x');
233        if(arg)
234        {
235            h = atof(arg + 1);
236            arg = strchr(arg, 'r');
237            if(arg)
238                a = atof(arg + 1);
239        }
240        src = ctx->images[ctx->nimages - 1];
241        dst = pipi_gaussian_blur_ext(src, w, h, a, 0.0, 0.0);
242        if(dst == NULL)
243            return -1;
244        pipi_free(src);
245        ctx->images[ctx->nimages - 1] = dst;
246    }
247    else if(!strcmp(cmd, "boxblur") || !strcmp(cmd, "median"))
248    {
249        pipi_image_t *src, *dst = NULL;
250        char const *arg;
251        va_list ap;
252        double w, h;
253
254        if(ctx->nimages < 1)
255            return -1;
256        va_start(ap, cmd);
257        arg = va_arg(ap, char const *);
258        va_end(ap);
259        w = h = atof(arg);
260        arg = strchr(arg, 'x');
261        if(arg)
262            h = atof(arg + 1);
263        src = ctx->images[ctx->nimages - 1];
264        switch(cmd[0])
265        {
266            case 'b': dst = pipi_box_blur_ext(src, w, h); break;
267            case 'm': dst = pipi_median_ext(src, w, h); break;
268        }
269        if(dst == NULL)
270            return -1;
271        pipi_free(src);
272        ctx->images[ctx->nimages - 1] = dst;
273    }
274    else if(!strcmp(cmd, "geometry") || !strcmp(cmd, "tile"))
275    {
276        pipi_image_t *src, *dst = NULL;
277        char const *arg;
278        va_list ap;
279        int w, h;
280
281        if(ctx->nimages < 1)
282            return -1;
283        va_start(ap, cmd);
284        arg = va_arg(ap, char const *);
285        va_end(ap);
286        w = atoi(arg);
287        arg = strchr(arg, 'x');
288        if(!arg)
289            return -1;
290        h = atoi(arg + 1);
291        if(w <= 0 || h <= 0)
292            return -1;
293        src = ctx->images[ctx->nimages - 1];
294        switch(cmd[0])
295        {
296            case 'g': dst = pipi_resize(src, w, h); break;
297            case 't': dst = pipi_tile(src, w, h); break;
298        }
299        if(dst == NULL)
300            return -1;
301        pipi_free(src);
302        ctx->images[ctx->nimages - 1] = dst;
303    }
304    else if(!strcmp(cmd, "scale"))
305    {
306        pipi_image_t *src, *dst;
307        char const *arg;
308        va_list ap;
309        double scale;
310        int w, h;
311
312        if(ctx->nimages < 1)
313            return -1;
314        src = ctx->images[ctx->nimages - 1];
315        va_start(ap, cmd);
316        arg = va_arg(ap, char const *);
317        va_end(ap);
318        scale = atof(arg);
319        w = (int)(scale * src->w + 0.5);
320        h = (int)(scale * src->h + 0.5);
321        if(w <= 0 || h <= 0)
322            return -1;
323        dst = pipi_resize(src, w, h);
324        if(dst == NULL)
325            return -1;
326        pipi_free(src);
327        ctx->images[ctx->nimages - 1] = dst;
328    }
329    else if(!strcmp(cmd, "crop"))
330    {
331        pipi_image_t *tmp;
332        char const *arg;
333        va_list ap;
334        int w, h, x = 0, y = 0;
335        int ret;
336
337        if(ctx->nimages < 1)
338            return -1;
339
340        va_start(ap, cmd);
341        arg = va_arg(ap, char const *);
342        va_end(ap);
343
344        ret = sscanf(arg, "%dx%d+%d+%d", &w, &h, &x, &y);
345        if(ret < 2)
346            return -1;
347
348        tmp = ctx->images[ctx->nimages - 1];
349        ctx->images[ctx->nimages - 1] = pipi_crop(tmp, w, h, x, y);
350        pipi_free(tmp);
351    }
352    else if(!strcmp(cmd, "brightness") || !strcmp(cmd, "contrast")
353             || !strcmp(cmd, "threshold"))
354    {
355        pipi_image_t *src, *dst = NULL;
356        char const *arg;
357        va_list ap;
358        double val;
359
360        if(ctx->nimages < 1)
361            return -1;
362        va_start(ap, cmd);
363        arg = va_arg(ap, char const *);
364        va_end(ap);
365        val = atof(arg);
366        src = ctx->images[ctx->nimages - 1];
367        switch(cmd[0])
368        {
369            case 'b': dst = pipi_brightness(src, val); break;
370            case 'c': dst = pipi_contrast(src, val); break;
371            case 't': dst = pipi_threshold(src, val); break;
372        }
373        if(dst == NULL)
374            return -1;
375        pipi_free(src);
376        ctx->images[ctx->nimages - 1] = dst;
377    }
378    else if(!strcmp(cmd, "hflip"))
379    {
380        pipi_image_t *tmp;
381        if(ctx->nimages < 1)
382            return -1;
383        tmp = ctx->images[ctx->nimages - 1];
384        ctx->images[ctx->nimages - 1] = pipi_hflip(tmp);
385        pipi_free(tmp);
386    }
387    else if(!strcmp(cmd, "vflip"))
388    {
389        pipi_image_t *tmp;
390        if(ctx->nimages < 1)
391            return -1;
392        tmp = ctx->images[ctx->nimages - 1];
393        ctx->images[ctx->nimages - 1] = pipi_vflip(tmp);
394        pipi_free(tmp);
395    }
396    else if(!strcmp(cmd, "rotate90"))
397    {
398        pipi_image_t *tmp;
399        if(ctx->nimages < 1)
400            return -1;
401        tmp = ctx->images[ctx->nimages - 1];
402        ctx->images[ctx->nimages - 1] = pipi_rotate90(tmp);
403        pipi_free(tmp);
404    }
405    else if(!strcmp(cmd, "rotate180"))
406    {
407        pipi_image_t *tmp;
408        if(ctx->nimages < 1)
409            return -1;
410        tmp = ctx->images[ctx->nimages - 1];
411        ctx->images[ctx->nimages - 1] = pipi_rotate180(tmp);
412        pipi_free(tmp);
413    }
414    else if(!strcmp(cmd, "rotate270"))
415    {
416        pipi_image_t *tmp;
417        if(ctx->nimages < 1)
418            return -1;
419        tmp = ctx->images[ctx->nimages - 1];
420        ctx->images[ctx->nimages - 1] = pipi_rotate270(tmp);
421        pipi_free(tmp);
422    }
423    else if(!strcmp(cmd, "order"))
424    {
425        pipi_image_t *tmp;
426        if(ctx->nimages < 1)
427            return -1;
428        tmp = ctx->images[ctx->nimages - 1];
429        ctx->images[ctx->nimages - 1] = pipi_order(tmp);
430        pipi_free(tmp);
431    }
432    else if(!strcmp(cmd, "split"))
433    {
434        pipi_image_t *src;
435
436        if(ctx->nimages < 1)
437            return -1;
438        src = ctx->images[ctx->nimages - 1];
439        ctx->nimages += 2;
440        ctx->images[ctx->nimages - 3] = pipi_red(src);
441        ctx->images[ctx->nimages - 2] = pipi_green(src);
442        ctx->images[ctx->nimages - 1] = pipi_blue(src);
443        pipi_free(src);
444    }
445    else if(!strcmp(cmd, "combine"))
446    {
447        pipi_image_t *dst;
448
449        if(ctx->nimages < 3)
450            return -1;
451        dst = pipi_rgb(ctx->images[ctx->nimages - 3],
452                       ctx->images[ctx->nimages - 2],
453                       ctx->images[ctx->nimages - 1]);
454        if(dst == NULL)
455            return -1;
456        pipi_free(ctx->images[ctx->nimages - 3]);
457        pipi_free(ctx->images[ctx->nimages - 2]);
458        pipi_free(ctx->images[ctx->nimages - 1]);
459        ctx->images[ctx->nimages - 3] = dst;
460        ctx->nimages -= 2;
461    }
462    else if(!strcmp(cmd, "merge"))
463    {
464        pipi_image_t *dst;
465        char const *arg;
466        va_list ap;
467        double val;
468
469        if(ctx->nimages < 2)
470            return -1;
471
472        va_start(ap, cmd);
473        arg = va_arg(ap, char const *);
474        va_end(ap);
475        val = atof(arg);
476
477        dst = pipi_merge(ctx->images[ctx->nimages - 2],
478                         ctx->images[ctx->nimages - 1], val);
479        if(dst == NULL)
480            return -1;
481        pipi_free(ctx->images[ctx->nimages - 2]);
482        pipi_free(ctx->images[ctx->nimages - 1]);
483        ctx->images[ctx->nimages - 2] = dst;
484        ctx->nimages--;
485    }
486    else if(!strcmp(cmd, "mean") || !strcmp(cmd, "min") || !strcmp(cmd, "max")
487             || !strcmp(cmd, "add") || !strcmp(cmd, "sub")
488             || !strcmp(cmd, "difference") || !strcmp(cmd, "multiply")
489             || !strcmp(cmd, "divide") || !strcmp(cmd, "screen")
490             || !strcmp(cmd, "overlay"))
491    {
492        pipi_image_t *dst = NULL;
493
494        if(ctx->nimages < 2)
495            return -1;
496        switch(cmd[2])
497        {
498            case 'a': dst = pipi_mean(ctx->images[ctx->nimages - 2],
499                                      ctx->images[ctx->nimages - 1]);
500                      break;
501            case 'n': dst = pipi_min(ctx->images[ctx->nimages - 2],
502                                     ctx->images[ctx->nimages - 1]);
503                      break;
504            case 'x': dst = pipi_max(ctx->images[ctx->nimages - 2],
505                                     ctx->images[ctx->nimages - 1]);
506                      break;
507            case 'd': dst = pipi_add(ctx->images[ctx->nimages - 2],
508                                     ctx->images[ctx->nimages - 1]);
509                      break;
510            case 'b': dst = pipi_sub(ctx->images[ctx->nimages - 2],
511                                     ctx->images[ctx->nimages - 1]);
512                      break;
513            case 'f': dst = pipi_difference(ctx->images[ctx->nimages - 2],
514                                            ctx->images[ctx->nimages - 1]);
515                      break;
516            case 'l': dst = pipi_multiply(ctx->images[ctx->nimages - 2],
517                                          ctx->images[ctx->nimages - 1]);
518                      break;
519            case 'v': dst = pipi_divide(ctx->images[ctx->nimages - 2],
520                                        ctx->images[ctx->nimages - 1]);
521                      break;
522            case 'r': dst = pipi_screen(ctx->images[ctx->nimages - 2],
523                                        ctx->images[ctx->nimages - 1]);
524                      break;
525            case 'e': dst = pipi_overlay(ctx->images[ctx->nimages - 2],
526                                         ctx->images[ctx->nimages - 1]);
527                      break;
528        }
529        if(dst == NULL)
530            return -1;
531        pipi_free(ctx->images[ctx->nimages - 2]);
532        pipi_free(ctx->images[ctx->nimages - 1]);
533        ctx->images[ctx->nimages - 2] = dst;
534        ctx->nimages--;
535    }
536    else if(!strcmp(cmd, "wrap"))
537    {
538        if(ctx->nimages < 1)
539            return -1;
540        ctx->images[ctx->nimages - 1]->wrap = 1;
541    }
542    else if(!strcmp(cmd, "autocontrast"))
543    {
544        pipi_image_t *tmp;
545        if(ctx->nimages < 1)
546            return -1;
547        tmp = ctx->images[ctx->nimages - 1];
548        ctx->images[ctx->nimages - 1] = pipi_autocontrast(tmp);
549        pipi_free(tmp);
550    }
551    else if(!strcmp(cmd, "invert"))
552    {
553        pipi_image_t *tmp;
554        if(ctx->nimages < 1)
555            return -1;
556        tmp = ctx->images[ctx->nimages - 1];
557        ctx->images[ctx->nimages - 1] = pipi_invert(tmp);
558        pipi_free(tmp);
559    }
560    else if(!strcmp(cmd, "dilate"))
561    {
562        pipi_image_t *tmp;
563        if(ctx->nimages < 1)
564            return -1;
565        tmp = ctx->images[ctx->nimages - 1];
566        ctx->images[ctx->nimages - 1] = pipi_dilate(tmp);
567        pipi_free(tmp);
568    }
569    else if(!strcmp(cmd, "erode"))
570    {
571        pipi_image_t *tmp;
572        if(ctx->nimages < 1)
573            return -1;
574        tmp = ctx->images[ctx->nimages - 1];
575        ctx->images[ctx->nimages - 1] = pipi_erode(tmp);
576        pipi_free(tmp);
577    }
578    else if(!strcmp(cmd, "gray"))
579    {
580        if(ctx->nimages < 1)
581            return -1;
582        pipi_get_pixels(ctx->images[ctx->nimages - 1], PIPI_PIXELS_Y_F32);
583    }
584    else if(!strcmp(cmd, "free"))
585    {
586        if(ctx->nimages < 1)
587            return -1;
588        ctx->nimages--;
589        pipi_free(ctx->images[ctx->nimages]);
590    }
591    else if(!strcmp(cmd, "dup"))
592    {
593        if(ctx->nimages < 1)
594            return -1;
595        ctx->images[ctx->nimages] = pipi_copy(ctx->images[ctx->nimages - 1]);
596        ctx->nimages++;
597    }
598    else if(!strcmp(cmd, "swap"))
599    {
600        pipi_image_t *tmp;
601        if(ctx->nimages < 2)
602            return -1;
603        tmp = ctx->images[ctx->nimages - 1];
604        ctx->images[ctx->nimages - 1] = ctx->images[ctx->nimages - 2];
605        ctx->images[ctx->nimages - 2] = tmp;
606    }
607    else if(!strcmp(cmd, "roll"))
608    {
609        pipi_image_t *tmp;
610        char const *arg;
611        va_list ap;
612        int val;
613
614        va_start(ap, cmd);
615        arg = va_arg(ap, char const *);
616        va_end(ap);
617        val = atoi(arg);
618        if(val <= 0 || ctx->nimages < val)
619            return -1;
620        if(val == 1)
621            return 0;
622        tmp = ctx->images[ctx->nimages - val];
623        memmove(ctx->images + ctx->nimages - val,
624                ctx->images + ctx->nimages - val + 1,
625                (val - 1) * sizeof(*ctx->images));
626        ctx->images[ctx->nimages - 1] = tmp;
627    }
628    else if(!strcmp(cmd, "line"))
629    {
630        char const *arg;
631        va_list ap;
632        int x1, y1, x2, y2, aa = 0, ret;
633        uint32_t color = 0;
634
635        if(ctx->nimages < 1)
636            return -1;
637
638        va_start(ap, cmd);
639        arg = va_arg(ap, char const *);
640        va_end(ap);
641
642        ret = sscanf(arg, "%d,%d,%d,%d,%08x,%d",
643               &x1, &y1, &x2, &y2, &color, &aa);
644        if(ret < 5) return -1;
645
646        ctx->images[ctx->nimages] = pipi_copy(ctx->images[ctx->nimages - 1]);
647        pipi_draw_line(ctx->images[ctx->nimages],
648                       x1,  y1,  x2,  y2, color, aa);
649        ctx->nimages++;
650    }
651    else if(!strcmp(cmd, "sine") || !strcmp(cmd, "wave"))
652    {
653        pipi_image_t *src, *dst = NULL;
654        char const *arg;
655        va_list ap;
656        float dw, dh, d = 0.0, a = 0.0;
657        int ret;
658
659        if(ctx->nimages < 1)
660            return -1;
661
662        va_start(ap, cmd);
663        arg = va_arg(ap, char const *);
664        va_end(ap);
665
666        ret = sscanf(arg, "%gx%g+%gr%g", &dw, &dh, &d, &a);
667        if(ret < 2)
668            return -1;
669
670        src = ctx->images[ctx->nimages - 1];
671        switch(cmd[0])
672        {
673            case 's': dst = pipi_sine(src, dw, dh, d, a); break;
674            case 'w': dst = pipi_wave(src, dw, dh, d, a); break;
675        }
676        if(dst == NULL)
677            return -1;
678        pipi_free(src);
679        ctx->images[ctx->nimages - 1] = dst;
680    }
681    else
682    {
683        return -1;
684    }
685
686    return 0;
687}
688
Note: See TracBrowser for help on using the repository browser.