Rename GP_Context -> GP_Pixmap
[gfxprim.git] / demos / grinder / grinder.c
blobfe40e2529e2a9bacfde53fdabd92a670b2fce1bc
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2012 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
29 #include "GP.h"
31 #include "params.h"
32 #include "histogram.h"
34 static GP_ProgressCallback *progress_callback = NULL;
36 static const char *progress_prefix = NULL;
38 static int show_progress(GP_ProgressCallback *self)
40 fprintf(stderr, "\r%s %3.2f%%",
41 progress_prefix, self->percentage);
43 return 0;
46 static int param_err(const struct param *self, const char *val, void *priv)
48 /* invalid parameter name */
49 if (self == NULL) {
50 fprintf(stderr, "ERROR: %s: Unknown parameter name '%s'\n",
51 (char*)priv, val);
52 return 1;
55 /* just regular error */
56 fprintf(stderr, "ERROR: %s: Invalid %s parameter value %s = '%s'",
57 (char *)priv, param_type_name(self->type), self->name, val);
59 if (self->type == PARAM_ENUM) {
60 unsigned int i;
62 fprintf(stderr, " is not in [");
64 for (i = 0; self->enum_table[i] != NULL; i++)
65 if (self->enum_table[i+1] == NULL)
66 fprintf(stderr, "'%s']", self->enum_table[i]);
67 else
68 fprintf(stderr, "'%s' | ", self->enum_table[i]);
71 fprintf(stderr, "\n");
73 return 1;
76 static void print_error(const char *error)
78 fprintf(stderr, "ERROR: %s\n", error);
81 /* resize filter */
83 static const char *resize_algs[] = {
84 "nn",
85 "linear-int",
86 "linear-lf-int",
87 "cubic",
88 "cubic-int",
89 NULL
92 static int resize_check_ratio(const struct param *self __attribute__((unused)),
93 void *val, int count __attribute__((unused)))
95 float f = *((float*)val);
97 if (f <= 0)
98 return -1;
100 return 0;
103 static struct param resize_params[] = {
104 {"alg", PARAM_ENUM, "algorithm to be used", resize_algs, NULL},
105 {"ratio", PARAM_FLOAT, "scale ratio", NULL, resize_check_ratio},
106 {NULL, 0, NULL, NULL, NULL}
109 static int resize(GP_Pixmap **c, const char *params)
111 int alg = 1;
112 float ratio = -1;
114 if (param_parse(params, resize_params, "resize", param_err,
115 &alg, &ratio))
116 return EINVAL;
118 if (ratio == -1) {
119 print_error("resize: ratio parameter is missing");
120 return EINVAL;
123 GP_Size w = ratio * (*c)->w;
124 GP_Size h = ratio * (*c)->h;
125 GP_Pixmap *res = NULL;
127 res = GP_FilterResizeAlloc(*c, w, h, alg, progress_callback);
129 if (res == NULL)
130 return EINVAL;
132 GP_PixmapFree(*c);
133 *c = res;
135 return 0;
138 /* scale filter */
140 static const char *scale_algs[] = {
141 "nn",
142 "linear-int",
143 "linear-lf-int",
144 "cubic",
145 "cubic-int",
146 NULL
149 static int scale_check_size(const struct param *self __attribute__((unused)),
150 void *val, int count __attribute__((unused)))
152 int i = *((int*)val);
154 if (i <= 0)
155 return 1;
157 return 0;
160 static struct param scale_params[] = {
161 {"alg", PARAM_ENUM, "algorithm to be used", scale_algs, NULL},
162 {"w", PARAM_INT, "new width (only width may be passed)", NULL, scale_check_size},
163 {"h", PARAM_INT, "new height (only height may be passed)", NULL, scale_check_size},
164 {NULL, 0, NULL, NULL, NULL}
167 static int scale(GP_Pixmap **c, const char *params)
169 int alg = 1;
170 int w = -1;
171 int h = -1;
173 if (param_parse(params, scale_params, "scale", param_err,
174 &alg, &w, &h))
175 return EINVAL;
177 if (w == -1 && h == -1) {
178 print_error("scale: w and/or h missing");
179 return EINVAL;
182 if (w == -1)
183 w = (*c)->w * (1.00 * h/(*c)->h) + 0.5;
185 if (h == -1)
186 h = (*c)->h * (1.00 * w/(*c)->w) + 0.5;
188 GP_Pixmap *res = NULL;
190 res = GP_FilterResizeAlloc(*c, w, h, alg, progress_callback);
192 if (res == NULL)
193 return EINVAL;
195 GP_PixmapFree(*c);
196 *c = res;
198 return 0;
201 /* rotate filter */
203 static const char *rotate_rots[] = {
204 "90",
205 "180",
206 "270",
209 static struct param rotate_params[] = {
210 {"rot", PARAM_ENUM, "image rotation", rotate_rots, NULL},
211 {NULL, 0, NULL, NULL, NULL}
214 static int rotate(GP_Pixmap **c, const char *params)
216 int rot = -1;
218 if (param_parse(params, rotate_params, "rotate", param_err, &rot))
219 return EINVAL;
221 if (rot == -1) {
222 print_error("rotate: rot parameter is missing");
223 return EINVAL;
226 GP_Pixmap *res = NULL;
228 switch (rot) {
229 case 0:
230 res = GP_FilterRotate90Alloc(*c, progress_callback);
231 break;
232 case 1:
233 res = GP_FilterRotate180Alloc(*c, progress_callback);
234 break;
235 case 2:
236 res = GP_FilterRotate270Alloc(*c, progress_callback);
237 break;
240 if (res == NULL)
241 return ENOMEM;
243 GP_PixmapFree(*c);
244 *c = res;
246 return 0;
249 /* mirror filter */
251 static struct param mirror_params[] = {
252 {"vert", PARAM_BOOL, "mirror vertically", NULL, NULL},
253 {"horiz", PARAM_BOOL, "mirror horizontally", NULL, NULL},
254 {NULL, 0, NULL, NULL, NULL}
257 static int mirror(GP_Pixmap **c, const char *params)
259 int vert = 0, horiz = 0;
261 if (param_parse(params, mirror_params, "mirror", param_err, &vert, &horiz))
262 return EINVAL;
264 if (vert)
265 GP_FilterMirrorV(*c, *c, progress_callback);
267 if (horiz)
268 GP_FilterMirrorH(*c, *c, progress_callback);
270 return 0;
273 /* brightness filter */
275 static struct param bright_params[] = {
276 {"inc", PARAM_FLOAT, "brightness increment", NULL, NULL},
277 {NULL, 0, NULL, NULL, NULL}
280 static int bright(GP_Pixmap **c, const char *params)
282 float bright = 0;
284 if (param_parse(params, bright_params, "bright", param_err, &bright))
285 return EINVAL;
287 GP_FilterBrightness(*c, *c, bright, progress_callback);
289 return 0;
292 /* contrast */
294 static struct param contrast_params[] = {
295 {"mul", PARAM_FLOAT, "contrast (1.5 = +50%, 0.5 = -50%)", NULL, NULL},
296 {NULL, 0, NULL, NULL, NULL}
299 static int contrast(GP_Pixmap **c, const char *params)
301 float mul = 0;
303 if (param_parse(params, contrast_params, "contrast", param_err, &mul))
304 return EINVAL;
306 if (mul <= 0) {
307 print_error("contrast: mul parameter must be >= 0");
308 return EINVAL;
311 GP_FilterContrast(*c, *c, mul, progress_callback);
313 return 0;
316 /* invert */
318 static struct param invert_params[] = {
319 {NULL, 0, NULL, NULL, NULL}
322 static int invert(GP_Pixmap **c, const char *params)
324 if (param_parse(params, invert_params, "invert", param_err))
325 return EINVAL;
327 GP_FilterInvert(*c, *c, progress_callback);
329 return 0;
332 /* blur */
334 static struct param blur_params[] = {
335 {"sigma", PARAM_FLOAT, "sigma parameter, radii of blur (sets both)", NULL, NULL},
336 {"sigma_x", PARAM_FLOAT, "sigma parameter for horizontal direction", NULL, NULL},
337 {"sigma_y", PARAM_FLOAT, "sigma parameter for vertical direction", NULL, NULL},
338 {NULL, 0, NULL, NULL, NULL}
341 static int blur(GP_Pixmap **c, const char *params)
343 float sigma = 0;
344 float sigma_x = 0;
345 float sigma_y = 0;
347 if (param_parse(params, blur_params, "blur", param_err, &sigma, &sigma_x, &sigma_y))
348 return EINVAL;
350 if (sigma > 0) {
351 sigma_x = sigma;
352 sigma_y = sigma;
355 if (sigma_x <= 0 && sigma_y <= 0) {
356 print_error("blur: at least one of sigma_x and sigma_y must be >= 0");
357 return EINVAL;
360 GP_FilterGaussianBlur(*c, *c, sigma_x, sigma_y, progress_callback);
362 return 0;
365 /* dithering */
367 //TODO: this should be generated
368 static const char *dither_formats[] = {
369 "g1",
370 "g2",
371 "g4",
372 "g8",
373 "rgb565",
374 "rgb666",
375 NULL,
378 static const GP_PixelType dither_pixel_types[] = {
379 GP_PIXEL_G1,
380 GP_PIXEL_G2,
381 GP_PIXEL_G4,
382 GP_PIXEL_G8,
383 GP_PIXEL_RGB565,
384 GP_PIXEL_RGB666,
387 static struct param dither_params[] = {
388 {"format", PARAM_ENUM, "pixel type to be used", dither_formats, NULL},
389 {NULL, 0, NULL, NULL, NULL}
392 static int dither(GP_Pixmap **c, const char *params)
394 int fmt = -1;
396 if (param_parse(params, dither_params, "dither", param_err, &fmt))
397 return EINVAL;
399 if (fmt == -1) {
400 print_error("dither: invalid format or format param missing");
401 return EINVAL;
404 GP_Pixmap *bw;
405 bw = GP_FilterFloydSteinbergAlloc(*c, dither_pixel_types[fmt],
406 progress_callback);
408 //TODO: so far we convert the pixmap back to RGB888
409 //(so we can do further work with it)
410 GP_Blit(bw, 0, 0, GP_PixmapW(bw), GP_PixmapH(bw), *c, 0, 0);
412 GP_PixmapFree(bw);
414 return 0;
417 /* jpg save filter */
419 static struct param save_jpg_params[] = {
420 {"file", PARAM_STR, "Filename to save the result", NULL, NULL},
421 {NULL, 0, NULL, NULL, NULL}
424 static int save_jpg(GP_Pixmap **c, const char *params)
426 char *file = NULL;
428 if (param_parse(params, save_jpg_params, "jpg", param_err, &file))
429 return EINVAL;
431 if (file == NULL) {
432 print_error("jpg: filename missing");
433 return EINVAL;
436 GP_SaveJPG(*c, file, progress_callback);
438 return 0;
441 /* png save filter */
443 static struct param save_png_params[] = {
444 {"file", PARAM_STR, "Filename to save the result", NULL, NULL},
445 {NULL, 0, NULL, NULL, NULL}
448 static int save_png(GP_Pixmap **c, const char *params)
450 char *file = NULL;
452 if (param_parse(params, save_png_params, "png", param_err, &file))
453 return EINVAL;
455 if (file == NULL) {
456 print_error("png: filename missing");
457 return EINVAL;
460 GP_SavePNG(*c, file, progress_callback);
462 return 0;
465 /* median filter */
467 static struct param median_params[] = {
468 {"radius", PARAM_INT, "median radius for both x and y", NULL, NULL},
469 {"radius_x", PARAM_INT, "median radius for x", NULL, NULL},
470 {"radius_y", PARAM_INT, "median radius for y", NULL, NULL},
471 {NULL, 0, NULL, NULL, NULL}
474 static int median(GP_Pixmap **c, const char *params)
476 int rad = -1, rad_x, rad_y;
478 if (param_parse(params, median_params, "median", param_err, &rad, &rad_x, &rad_y))
479 return EINVAL;
481 if (rad != -1) {
482 rad_x = rad;
483 rad_y = rad;
486 if (rad_x < 0 || rad_y < 0)
487 return EINVAL;
489 GP_Pixmap *ret = GP_FilterMedianAlloc(*c, rad_x, rad_y, progress_callback);
491 if (ret == NULL)
492 return ENOMEM;
494 GP_PixmapFree(*c);
495 *c = ret;
497 return 0;
500 /* sigma mean filter */
502 static struct param sigma_mean_params[] = {
503 {"radius", PARAM_INT, "median radius for both x and y", NULL, NULL},
504 {"min", PARAM_INT, "minimal number of pixels to use for the mean", NULL, NULL},
505 {"sigma", PARAM_FLOAT, "sigma scaled to [0,1] interval", NULL, NULL},
506 {"radius_x", PARAM_INT, "median radius for x", NULL, NULL},
507 {"radius_y", PARAM_INT, "median radius for y", NULL, NULL},
508 {NULL, 0, NULL, NULL, NULL}
511 static int sigma_mean(GP_Pixmap **c, const char *params)
513 int rad = -1, rad_x, rad_y, min = 0;
514 float sigma = 0.1;
516 if (param_parse(params, sigma_mean_params, "sigma", param_err,
517 &rad, &min, &sigma, &rad_x, &rad_y))
518 return EINVAL;
520 if (rad != -1) {
521 rad_x = rad;
522 rad_y = rad;
525 if (rad_x < 0 || rad_y < 0)
526 return EINVAL;
528 (*c)->gamma = GP_GammaAcquire((*c)->pixel_type, 1.2);
530 GP_Pixmap *ret = GP_FilterSigmaAlloc(*c, rad_x, rad_y, min, sigma, progress_callback);
532 if (ret == NULL)
533 return ENOMEM;
535 GP_PixmapFree(*c);
536 *c = ret;
538 return 0;
541 /* laplacian edge sharpening filter */
543 static struct param sharpen_params[] = {
544 {"weight", PARAM_FLOAT, "sharpening weight from [0,1] interval", NULL, NULL},
545 {NULL, 0, NULL, NULL, NULL}
548 static int sharpen(GP_Pixmap **c, const char *params)
550 float weight = 0.1;
552 if (param_parse(params, sharpen_params, "sigma", param_err, &weight))
553 return EINVAL;
555 GP_Pixmap *ret = GP_FilterEdgeSharpeningAlloc(*c, weight, progress_callback);
557 if (ret == NULL)
558 return ENOMEM;
560 GP_PixmapFree(*c);
561 *c = ret;
563 return 0;
566 /* gaussian additive noise filter */
568 static struct param gauss_noise_params[] = {
569 {"sigma", PARAM_FLOAT, "sigma: amount of noise between [0,1]", NULL, NULL},
570 {"mu", PARAM_FLOAT, "mu: offset of noise between [0,1]", NULL, NULL},
571 {NULL, 0, NULL, NULL, NULL}
574 static int gauss_noise(GP_Pixmap **c, const char *params)
576 float sigma = 0.1;
577 float mu = 0;
579 if (param_parse(params, gauss_noise_params, "gaussian noise", param_err, &sigma, &mu))
580 return EINVAL;
582 GP_FilterGaussianNoiseAdd(*c, *c, sigma, mu, progress_callback);
584 return 0;
587 /* arithmetics */
589 static const char *arithmetic_ops[] = {
590 "difference",
591 "addition",
592 "multiply",
593 "min",
594 "max",
595 NULL
598 static struct param arithmetic_params[] = {
599 {"file", PARAM_STR, "Filename of image to use.", NULL, NULL},
600 {"op", PARAM_ENUM, "Arithmetic peration", arithmetic_ops, NULL},
601 {NULL, 0, NULL, NULL, NULL}
604 static int arithmetic(GP_Pixmap **c, const char *params)
606 char *file = NULL;
607 int op = -1;
609 if (param_parse(params, arithmetic_params, "arithmetic", param_err, &file, &op))
610 return EINVAL;
612 if (file == NULL) {
613 print_error("arithmetic: Filename missing");
614 return EINVAL;
617 GP_Pixmap *img, *res = NULL;
619 if ((img = GP_LoadImage(file, progress_callback)) == NULL) {
620 print_error("arithmetic: Invalid image.");
621 return EINVAL;
624 switch (op) {
625 case 0:
626 res = GP_FilterDifferenceAlloc(*c, img, progress_callback);
627 break;
628 case 1:
629 res = GP_FilterAdditionAlloc(*c, img, progress_callback);
630 break;
631 case 2:
632 res = GP_FilterMultiplyAlloc(*c, img, progress_callback);
633 break;
634 case 3:
635 res = GP_FilterMinAlloc(*c, img, progress_callback);
636 break;
637 case 4:
638 res = GP_FilterMaxAlloc(*c, img, progress_callback);
639 break;
642 if (res == NULL)
643 return ENOMEM;
645 GP_PixmapFree(*c);
647 *c = res;
649 return 0;
652 /* histogram */
654 static struct param histogram_params[] = {
655 {"file", PARAM_STR, "Filename of image to use.", NULL, NULL},
656 {NULL, 0, NULL, NULL, NULL}
659 static int histogram(GP_Pixmap **c, const char *params)
661 char *file = "histogram.png";
663 if (param_parse(params, histogram_params, "histogram", param_err, &file))
664 return EINVAL;
666 if (file == NULL) {
667 print_error("histogram: Filename missing");
668 return EINVAL;
671 histogram_to_png(*c, file);
672 return 0;
675 /* filters */
677 struct filter {
678 const char *name;
679 const char *desc;
680 struct param *param_desc;
681 int (*apply)(GP_Pixmap **c, const char *params);
684 static struct filter filter_table[] = {
685 {"rotate", "rotate image", rotate_params, rotate},
686 {"mirror", "mirror vertically/horizontally", mirror_params, mirror},
687 {"scale", "scale image to given width and height", scale_params, scale},
688 {"resize", "resize image by given ratio", resize_params, resize},
689 {"bright", "alter image brightness", bright_params, bright},
690 {"contrast", "alter image contrast", contrast_params, contrast},
691 {"invert", "inverts image", invert_params, invert},
692 {"blur", "gaussian blur", blur_params, blur},
693 {"dither", "dithers bitmap", dither_params, dither},
694 {"arithmetic", "arithmetic operation", arithmetic_params, arithmetic},
695 {"histogram", "save histogram into image file", histogram_params, histogram},
696 {"median", "median filter", median_params, median},
697 {"sigma", "sigma (mean) filter", sigma_mean_params, sigma_mean},
698 {"sharpen", "laplacian edge sharpening", sharpen_params, sharpen},
699 {"gauss_noise", "additive gaussian (normaly distributed) noise", gauss_noise_params, gauss_noise},
700 {"jpg", "save jpg image", save_jpg_params, save_jpg},
701 {"png", "save png image", save_png_params, save_png},
702 {NULL, NULL, NULL, NULL}
705 static struct filter *get_filter(const char *name)
707 unsigned int i;
709 for (i = 0; filter_table[i].name != NULL; i++) {
710 if (!strcasecmp(filter_table[i].name, name))
711 return &filter_table[i];
714 return NULL;
717 static void print_filter_help(void)
719 unsigned int i, j;
721 for (i = 0; filter_table[i].name != NULL; i++) {
722 printf("%s\n", filter_table[i].name);
724 j = strlen(filter_table[i].name);
726 while (j--)
727 putchar('-');
728 putchar('\n');
730 printf("* %s\n", filter_table[i].desc);
731 putchar('\n');
733 param_describe(filter_table[i].param_desc, " ");
734 putchar('\n');
738 /* application */
740 #define FILTERS_MAX 255
742 static const char *filter_params[FILTERS_MAX];
743 static const struct filter *filters[FILTERS_MAX];
744 static unsigned int filter_cnt = 0;
746 static void add_filter(char *params)
748 if (filter_cnt >= FILTERS_MAX) {
749 fprintf(stderr, "Maximal number of filters exceeded (%u), "
750 "increase and recompile.", FILTERS_MAX);
751 exit(1);
754 const char *name = strsep(&params, ":");
756 filters[filter_cnt] = get_filter(name);
758 if (filters[filter_cnt] == NULL) {
759 fprintf(stderr, "Invalid filter name '%s'\n", name);
760 exit(1);
763 filter_params[filter_cnt++] = params;
766 static void apply_filters(GP_Pixmap **src)
768 unsigned int i;
769 int ret;
771 for (i = 0; i < filter_cnt; i++) {
772 char buf[255];
774 snprintf(buf, sizeof(buf), "Filter %s", filters[i]->name);
776 progress_prefix = buf;
778 if ((ret = filters[i]->apply(src, filter_params[i]))) {
779 fprintf(stderr, "Error: %s\n", strerror(ret));
780 exit(1);
783 if (progress_callback != NULL)
784 fprintf(stderr, " done\n");
788 static const char *app_help = {
789 " \n"
790 " <<<<<<<<<< Bitmap Grinder >>>>>>>>>>> \n"
791 " \n"
792 " +~+-----+ \n"
793 " /| | +-+| .11. \n"
794 " +-{ D| |010101011. \n"
795 " | \\| | +-.0100101. \n"
796 " O=+ +~+-----+ .10110101. \n"
797 " .010101. \n"
798 " .1. \n"
799 " \n"
800 " Program options \n"
801 " =============== \n"
802 " \n"
803 "-h - prints this help \n"
804 "-p - show filter progress \n"
805 "-v int - sets gfxprim verbosity level \n"
806 "-o fmt - output format, ppm, jpg, png \n"
807 "-f params - apply filter, multiple filters may be used\n"
808 " \n"
809 " Example usage \n"
810 " ============= \n"
811 " \n"
812 " grider -f resize:ratio=1.5 -f contrast:mul=1.2 in.png\n"
813 " \n"
814 " * will resize image 1.5 times and increases contrast \n"
815 " by 20%. The result is, just for now, saved to \n"
816 " out_X.ppm where X is number which is increased for \n"
817 " each image given as parameter. \n"
818 " \n"
819 " List of filters \n"
820 " =============== \n"
823 static void print_help(void)
825 puts(app_help);
826 print_filter_help();
829 static const char *out_fmts[] = {
830 "ppm",
831 "jpg",
832 "png",
833 NULL
836 static void check_fmt(const char *fmt)
838 unsigned int i;
840 for (i = 0; out_fmts[i] != NULL; i++)
841 if (!strcmp(out_fmts[i], fmt))
842 return;
844 fprintf(stderr, "Invalid output format '%s'\n", fmt);
845 exit(1);
848 static void save_by_fmt(struct GP_Pixmap *bitmap, const char *name, const char *fmt)
850 int ret;
852 progress_prefix = "Saving Image";
854 if (!strcmp(fmt, "ppm"))
855 ret = GP_SavePPM(bitmap, name, progress_callback);
856 else if (!strcmp(fmt, "jpg"))
857 ret = GP_SaveJPG(bitmap, name, progress_callback);
858 else if (!strcmp(fmt, "png"))
859 ret = GP_SavePNG(bitmap, name, progress_callback);
860 else {
861 printf("Invalid format %s\n", fmt);
862 exit(1);
865 if (ret) {
866 fprintf(stderr, "Failed to save bitmap: %s\n",
867 strerror(errno));
868 exit(1);
871 if (progress_callback != NULL)
872 fprintf(stderr, " done\n");
875 int main(int argc, char *argv[])
877 GP_Pixmap *bitmap;
878 int opt, i;
879 const char *out_fmt = "ppm";
881 GP_ProgressCallback callback = {
882 .callback = show_progress,
885 while ((opt = getopt(argc, argv, "f:ho:pv:")) != -1) {
886 switch (opt) {
887 case 'h':
888 print_help();
889 return 0;
890 break;
891 case 'v':
892 i = atoi(optarg);
894 if (i == 0) {
895 fprintf(stderr, "ERROR: invalid debug level "
896 "'%s', expected number > 0\n",
897 optarg);
898 return 1;
901 GP_SetDebugLevel(i);
902 break;
903 case 'o':
904 out_fmt = optarg;
905 check_fmt(out_fmt);
906 break;
907 case 'f':
908 add_filter(optarg);
909 break;
910 case 'p':
911 progress_callback = &callback;
912 break;
913 default:
914 print_help();
915 return 1;
919 if (optind >= argc) {
920 fprintf(stderr, "ERROR: Expected bitmap filenames\n");
921 return 1;
924 for (i = optind; i < argc; i++) {
925 char buf[255];
927 snprintf(buf, sizeof(buf), "out_%03i.%s", i - optind + 1, out_fmt);
928 fprintf(stderr, "Processing '%s' -> '%s'\n", argv[i], buf);
930 progress_prefix = "Loading image";
932 if ((bitmap = GP_LoadImage(argv[i], progress_callback)) == NULL) {
933 fprintf(stderr, "Failed to load bitmap: %s\n", strerror(errno));
934 return 1;
937 if (progress_callback != NULL)
938 fprintf(stderr, " done\n");
940 apply_filters(&bitmap);
942 save_by_fmt(bitmap, buf, out_fmt);
945 return 0;