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

Last change on this file since 4696 was 4696, checked in by Sam Hocevar, 9 years ago

Implement bicubic resampling. Lacks some blurring in the pre-pass, maybe.

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