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

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

Implement pipi_rotate(). Currently nearest-neighbour only, supersample if
you need more precision.

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