loaders: Added Exif to MetaData parser.
[gfxprim.git] / demos / grinder / grinder.c
blob3da50377161c9f979e6691b438cd2010d7e57071
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-2011 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: invalid parameter '%s'\n",
51 (char*)priv, val);
52 return 1;
55 /* just regular error */
56 fprintf(stderr, "ERROR: %s: invalid %s parameter %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 GP_RetCode resize(GP_Context **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 GP_EINVAL;
118 if (ratio == -1) {
119 print_error("resize: ratio parameter is missing");
120 return GP_EINVAL;
123 GP_Size w = ratio * (*c)->w;
124 GP_Size h = ratio * (*c)->h;
125 GP_Context *res = NULL;
127 res = GP_FilterResize(*c, NULL, alg, w, h, progress_callback);
129 if (res == NULL)
130 return GP_EINVAL;
132 GP_ContextFree(*c);
133 *c = res;
135 return GP_ESUCCESS;
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 GP_RetCode scale(GP_Context **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 GP_EINVAL;
177 if (w == -1 && h == -1) {
178 print_error("scale: w and/or h missing");
179 return GP_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_Context *res = NULL;
190 res = GP_FilterResize(*c, NULL, alg, w, h, progress_callback);
192 if (res == NULL)
193 return GP_EINVAL;
195 GP_ContextFree(*c);
196 *c = res;
198 return GP_ESUCCESS;
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 GP_RetCode rotate(GP_Context **c, const char *params)
216 int rot = -1;
218 if (param_parse(params, rotate_params, "rotate", param_err, &rot))
219 return GP_EINVAL;
221 if (rot == -1) {
222 print_error("rotate: rot parameter is missing");
223 return GP_EINVAL;
226 GP_Context *res = NULL;
228 switch (rot) {
229 case 0:
230 res = GP_FilterRotate90_Alloc(*c, progress_callback);
231 break;
232 case 1:
233 res = GP_FilterRotate180_Alloc(*c, progress_callback);
234 break;
235 case 2:
236 res = GP_FilterRotate270_Alloc(*c, progress_callback);
237 break;
240 if (res == NULL)
241 return GP_ENOMEM;
243 GP_ContextFree(*c);
244 *c = res;
246 return GP_ESUCCESS;
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 GP_RetCode mirror(GP_Context **c, const char *params)
259 int vert = 0, horiz = 0;
261 if (param_parse(params, mirror_params, "mirror", param_err, &vert, &horiz))
262 return GP_EINVAL;
264 if (vert)
265 GP_FilterMirrorV(*c, *c, progress_callback);
267 if (horiz)
268 GP_FilterMirrorH(*c, *c, progress_callback);
270 return GP_ESUCCESS;
273 /* brightness filter */
275 static struct param bright_params[] = {
276 {"inc", PARAM_INT, "brightness increment", NULL, NULL},
277 {"chann", PARAM_STR, "Channel name {R, G, B, A, V, ...}", NULL, NULL},
278 {NULL, 0, NULL, NULL, NULL}
281 static GP_RetCode bright(GP_Context **c, const char *params)
283 int bright = 0;
284 char *chann = NULL;
286 if (param_parse(params, bright_params, "bright", param_err, &bright, &chann))
287 return GP_EINVAL;
289 if (bright == 0) {
290 print_error("bright: bright parameter is zero or missing");
291 return GP_EINVAL;
294 GP_FILTER_PARAMS((*c)->pixel_type, filter_params);
296 if (chann == NULL) {
297 GP_FilterParamSetIntAll(filter_params, bright);
298 } else {
299 GP_FilterParam *param = GP_FilterParamChannel(filter_params, chann);
301 if (param == NULL) {
302 print_error("bright: Invalid channel name");
303 return GP_EINVAL;
306 GP_FilterParamSetIntAll(filter_params, 0);
307 param->val.i = bright;
310 GP_FilterBrightness(*c, *c, filter_params, progress_callback);
312 return GP_ESUCCESS;
315 /* contrast */
317 static struct param contrast_params[] = {
318 {"mul", PARAM_FLOAT, "contrast (1.5 = +50%, 0.5 = -50%)", NULL, NULL},
319 {"chann", PARAM_STR, "Channel name {R, G, B, A, V, ...}", NULL, NULL},
320 {NULL, 0, NULL, NULL, NULL}
323 static GP_RetCode contrast(GP_Context **c, const char *params)
325 float mul = 0;
326 char *chann = NULL;
328 if (param_parse(params, contrast_params, "contrast", param_err, &mul, &chann))
329 return GP_EINVAL;
331 if (mul <= 0) {
332 print_error("contrast: mul parameter must be >= 0");
333 return GP_EINVAL;
336 GP_FILTER_PARAMS((*c)->pixel_type, filter_params);
338 if (chann == NULL) {
339 GP_FilterParamSetFloatAll(filter_params, mul);
340 } else {
341 GP_FilterParam *param = GP_FilterParamChannel(filter_params, chann);
343 if (param == NULL) {
344 print_error("contrast: Invalid channel name");
345 return GP_EINVAL;
348 GP_FilterParamSetFloatAll(filter_params, 1);
349 param->val.f = mul;
352 GP_FilterContrast(*c, *c, filter_params, progress_callback);
354 return GP_ESUCCESS;
357 /* invert */
359 static struct param invert_params[] = {
360 {NULL, 0, NULL, NULL, NULL}
363 static GP_RetCode invert(GP_Context **c, const char *params)
365 if (param_parse(params, invert_params, "invert", param_err))
366 return GP_EINVAL;
368 GP_FilterInvert(*c, *c, progress_callback);
370 return GP_ESUCCESS;
373 /* blur */
375 static struct param blur_params[] = {
376 {"sigma", PARAM_FLOAT, "sigma parameter, radii of blur (sets both)", NULL, NULL},
377 {"sigma_x", PARAM_FLOAT, "sigma parameter for horizontal direction", NULL, NULL},
378 {"sigma_y", PARAM_FLOAT, "sigma parameter for vertical direction", NULL, NULL},
379 {NULL, 0, NULL, NULL, NULL}
382 static GP_RetCode blur(GP_Context **c, const char *params)
384 float sigma = 0;
385 float sigma_x = 0;
386 float sigma_y = 0;
388 if (param_parse(params, blur_params, "blur", param_err, &sigma, &sigma_x, &sigma_y))
389 return GP_EINVAL;
391 if (sigma > 0) {
392 sigma_x = sigma;
393 sigma_y = sigma;
396 if (sigma_x <= 0 && sigma_y <= 0) {
397 print_error("blur: at least one of sigma_x and sigma_y must be >= 0");
398 return GP_EINVAL;
401 GP_FilterGaussianBlur_Raw(*c, *c, sigma_x, sigma_y, progress_callback);
403 return GP_ESUCCESS;
406 /* dithering */
408 //TODO: this should be generated
409 static const char *dither_formats[] = {
410 "g1",
411 "g2",
412 "g4",
413 "g8",
414 "rgb333",
415 "rgb565",
416 "rgb666",
417 NULL,
420 static const GP_PixelType dither_pixel_types[] = {
421 GP_PIXEL_G1,
422 GP_PIXEL_G2,
423 GP_PIXEL_G4,
424 GP_PIXEL_G8,
425 GP_PIXEL_xRGB7333,
426 GP_PIXEL_RGB565,
427 GP_PIXEL_RGB666,
430 static struct param dither_params[] = {
431 {"format", PARAM_ENUM, "pixel type to be used", dither_formats, NULL},
432 {NULL, 0, NULL, NULL, NULL}
435 static GP_RetCode dither(GP_Context **c, const char *params)
437 int fmt = -1;
439 if (param_parse(params, dither_params, "dither", param_err, &fmt))
440 return GP_EINVAL;
442 if (fmt == -1) {
443 print_error("dither: invalid format or format param missing");
444 return GP_EINVAL;
447 GP_Context *bw;
448 bw = GP_FilterFloydSteinberg_RGB888_Alloc(*c, dither_pixel_types[fmt],
449 progress_callback);
451 //TODO: so far we convert the context back to RGB888
452 //(so we can do further work with it)
453 GP_Blit(bw, 0, 0, GP_ContextW(bw), GP_ContextH(bw), *c, 0, 0);
455 GP_ContextFree(bw);
457 return GP_ESUCCESS;
460 /* jpg save filter */
462 static struct param save_jpg_params[] = {
463 {"file", PARAM_STR, "Filename to save the result", NULL, NULL},
464 {NULL, 0, NULL, NULL, NULL}
467 static GP_RetCode save_jpg(GP_Context **c, const char *params)
469 char *file = NULL;
471 if (param_parse(params, save_jpg_params, "jpg", param_err, &file))
472 return GP_EINVAL;
474 if (file == NULL) {
475 print_error("jpg: filename missing");
476 return GP_EINVAL;
479 GP_SaveJPG(*c, file, progress_callback);
481 return GP_ESUCCESS;
484 /* png save filter */
486 static struct param save_png_params[] = {
487 {"file", PARAM_STR, "Filename to save the result", NULL, NULL},
488 {NULL, 0, NULL, NULL, NULL}
491 static GP_RetCode save_png(GP_Context **c, const char *params)
493 char *file = NULL;
495 if (param_parse(params, save_png_params, "png", param_err, &file))
496 return GP_EINVAL;
498 if (file == NULL) {
499 print_error("png: filename missing");
500 return GP_EINVAL;
503 GP_SavePNG(*c, file, progress_callback);
505 return GP_ESUCCESS;
508 /* noise filter */
510 static struct param add_noise_params[] = {
511 {"percents", PARAM_FLOAT, "Percents of noise to add", NULL, NULL},
512 {"chann", PARAM_STR, "Channel name {R, G, B, A, V, ...}", NULL, NULL},
513 {NULL, 0, NULL, NULL, NULL}
516 static uint32_t add_noise_op(uint32_t val, uint8_t bits, GP_FilterParam *param)
518 float perc;
519 int max = (1<<bits) - 1;
520 int ret;
522 perc = param->val.f;
524 ret = val * (1 - perc) + (random() % max) * perc;
526 if (ret < 0)
527 ret = 0;
529 if (ret > max)
530 ret = max;
532 return ret;
535 static uint32_t no_op(uint32_t val)
537 return val;
540 static GP_RetCode add_noise(GP_Context **c, const char *params)
542 float percents = 0;
543 char *chann = NULL;
545 if (param_parse(params, add_noise_params, "add_noise", param_err, &percents, &chann))
546 return GP_EINVAL;
548 GP_FILTER_PARAMS((*c)->pixel_type, priv);
549 GP_FilterParamSetFloatAll(priv, percents/100);
550 GP_FILTER_PARAMS((*c)->pixel_type, op_callbacks);
552 if (chann == NULL) {
553 GP_FilterParamSetPtrAll(op_callbacks, add_noise_op);
554 } else {
555 GP_FilterParam *param = GP_FilterParamChannel(op_callbacks, chann);
557 if (param == NULL) {
558 print_error("add_noise: Invalid channel name");
559 return GP_EINVAL;
563 GP_FilterParamSetPtrAll(op_callbacks, no_op);
564 param->val.ptr = add_noise_op;
567 GP_FilterPoint(*c, *c, op_callbacks, priv, progress_callback);
569 return GP_ESUCCESS;
572 /* arithmetics */
574 static const char *arithmetic_ops[] = {
575 "difference",
576 "addition",
577 "multiply",
578 "min",
579 "max",
580 NULL
583 static struct param arithmetic_params[] = {
584 {"file", PARAM_STR, "Filename of image to use.", NULL, NULL},
585 {"op", PARAM_ENUM, "Arithmetic peration", arithmetic_ops, NULL},
586 {NULL, 0, NULL, NULL, NULL}
589 static GP_RetCode arithmetic(GP_Context **c, const char *params)
591 char *file = NULL;
592 int op = -1;
594 if (param_parse(params, arithmetic_params, "arithmetic", param_err, &file, &op))
595 return GP_EINVAL;
597 if (file == NULL) {
598 print_error("arithmetic: Filename missing");
599 return GP_EINVAL;
602 GP_Context *img, *res = NULL;
604 if ((img = GP_LoadImage(file, progress_callback)) == NULL) {
605 print_error("arithmetic: Invalid image.");
606 return GP_EINVAL;
609 switch (op) {
610 case 0:
611 res = GP_FilterDifference(*c, img, NULL, progress_callback);
612 break;
613 case 1:
614 res = GP_FilterAddition(*c, img, NULL, progress_callback);
615 break;
616 case 2:
617 res = GP_FilterMultiply(*c, img, NULL, progress_callback);
618 break;
619 case 3:
620 res = GP_FilterMin(*c, img, NULL, progress_callback);
621 break;
622 case 4:
623 res = GP_FilterMax(*c, img, NULL, progress_callback);
624 break;
627 if (res == NULL)
628 return GP_EINVAL;
630 GP_ContextFree(*c);
632 *c = res;
634 return GP_ESUCCESS;
637 /* histogram */
639 static struct param histogram_params[] = {
640 {"file", PARAM_STR, "Filename of image to use.", NULL, NULL},
641 {NULL, 0, NULL, NULL, NULL}
644 static GP_RetCode histogram(GP_Context **c, const char *params)
646 char *file = "histogram.png";
648 if (param_parse(params, histogram_params, "histogram", param_err, &file))
649 return GP_EINVAL;
651 if (file == NULL) {
652 print_error("histogram: Filename missing");
653 return GP_EINVAL;
656 histogram_to_png(*c, file);
657 return GP_ESUCCESS;
660 /* filters */
662 struct filter {
663 const char *name;
664 const char *desc;
665 struct param *param_desc;
666 GP_RetCode (*apply)(GP_Context **c, const char *params);
669 static struct filter filter_table[] = {
670 {"rotate", "rotate image", rotate_params, rotate},
671 {"mirror", "mirror vertically/horizontally", mirror_params, mirror},
672 {"scale", "scale image to given width and height", scale_params, scale},
673 {"resize", "resize image by given ratio", resize_params, resize},
674 {"bright", "alter image brightness", bright_params, bright},
675 {"contrast", "alter image contrast", contrast_params, contrast},
676 {"invert", "inverts image", invert_params, invert},
677 {"add_noise", "adds noise", add_noise_params, add_noise},
678 {"blur", "gaussian blur", blur_params, blur},
679 {"dither", "dithers bitmap", dither_params, dither},
680 {"arithmetic", "arithmetic operation", arithmetic_params, arithmetic},
681 {"histogram", "save histogram into image file", histogram_params, histogram},
682 {"jpg", "save jpg image", save_jpg_params, save_jpg},
683 {"png", "save png image", save_png_params, save_png},
684 {NULL, NULL, NULL, NULL}
687 static struct filter *get_filter(const char *name)
689 unsigned int i;
691 for (i = 0; filter_table[i].name != NULL; i++) {
692 if (!strcasecmp(filter_table[i].name, name))
693 return &filter_table[i];
696 return NULL;
699 static void print_filter_help(void)
701 unsigned int i, j;
703 for (i = 0; filter_table[i].name != NULL; i++) {
704 printf("%s\n", filter_table[i].name);
706 j = strlen(filter_table[i].name);
708 while (j--)
709 putchar('-');
710 putchar('\n');
712 printf("* %s\n", filter_table[i].desc);
713 putchar('\n');
715 param_describe(filter_table[i].param_desc, " ");
716 putchar('\n');
720 /* application */
722 #define FILTERS_MAX 255
724 static const char *filter_params[FILTERS_MAX];
725 static const struct filter *filters[FILTERS_MAX];
726 static unsigned int filter_cnt = 0;
728 static void add_filter(char *params)
730 if (filter_cnt >= FILTERS_MAX) {
731 fprintf(stderr, "Maximal number of filters exceeded (%u), "
732 "increase and recompile.", FILTERS_MAX);
733 exit(1);
736 const char *name = strsep(&params, ":");
738 filters[filter_cnt] = get_filter(name);
740 if (filters[filter_cnt] == NULL) {
741 fprintf(stderr, "Invalid filter name '%s'\n", name);
742 exit(1);
745 filter_params[filter_cnt++] = params;
748 static void apply_filters(GP_Context **src)
750 unsigned int i;
751 GP_RetCode ret;
753 for (i = 0; i < filter_cnt; i++) {
754 char buf[255];
756 snprintf(buf, sizeof(buf), "Filter %s", filters[i]->name);
758 progress_prefix = buf;
760 if ((ret = filters[i]->apply(src, filter_params[i]))) {
761 fprintf(stderr, "Error: %s\n", GP_RetCodeName(ret));
762 exit(1);
765 if (progress_callback != NULL)
766 fprintf(stderr, " done\n");
770 static const char *app_help = {
771 " \n"
772 " <<<<<<<<<< Bitmap Grinder >>>>>>>>>>> \n"
773 " \n"
774 " +~+-----+ \n"
775 " /| | +-+| .11. \n"
776 " +-{ D| |010101011. \n"
777 " | \\| | +-.0100101. \n"
778 " O=+ +~+-----+ .10110101. \n"
779 " .010101. \n"
780 " .1. \n"
781 " \n"
782 " Program options \n"
783 " =============== \n"
784 " \n"
785 "-h - prints this help \n"
786 "-p - show filter progress \n"
787 "-v int - sets gfxprim verbosity level \n"
788 "-o fmt - output format, ppm, jpg, png \n"
789 "-f params - apply filter, multiple filters may be used\n"
790 " \n"
791 " Example usage \n"
792 " ============= \n"
793 " \n"
794 " grider -f resize:ratio=1.5 -f contrast:mul=1.2 in.png\n"
795 " \n"
796 " * will resize image 1.5 times and increases contrast \n"
797 " by 20%. The result is, just for now, saved to \n"
798 " out_X.ppm where X is number which is increased for \n"
799 " each image given as parameter. \n"
800 " \n"
801 " List of filters \n"
802 " =============== \n"
805 static void print_help(void)
807 puts(app_help);
808 print_filter_help();
811 static const char *out_fmts[] = {
812 "ppm",
813 "jpg",
814 "png",
815 NULL
818 static void check_fmt(const char *fmt)
820 unsigned int i;
822 for (i = 0; out_fmts[i] != NULL; i++)
823 if (!strcmp(out_fmts[i], fmt))
824 break;
826 fprintf(stderr, "Invalid output format '%s'\n", fmt);
829 static void save_by_fmt(struct GP_Context *bitmap, const char *name, const char *fmt)
831 GP_RetCode ret;
833 progress_prefix = "Saving Image";
835 if (!strcmp(fmt, "ppm"))
836 ret = GP_SavePPM(name, bitmap, "b");
837 else if (!strcmp(fmt, "jpg"))
838 ret = GP_SaveJPG(bitmap, name, progress_callback);
839 else if (!strcmp(fmt, "png"))
840 ret = GP_SavePNG(bitmap, name, progress_callback);
842 if (ret) {
843 fprintf(stderr, "Failed to save bitmap: %s\n", GP_RetCodeName(ret));
844 exit(1);
847 if (progress_callback != NULL)
848 fprintf(stderr, " done\n");
851 int main(int argc, char *argv[])
853 GP_Context *bitmap;
854 int opt, i;
855 const char *out_fmt = "ppm";
857 GP_ProgressCallback callback = {
858 .callback = show_progress,
861 while ((opt = getopt(argc, argv, "f:ho:pv:")) != -1) {
862 switch (opt) {
863 case 'h':
864 print_help();
865 return 0;
866 break;
867 case 'v':
868 i = atoi(optarg);
870 if (i == 0) {
871 fprintf(stderr, "ERROR: invalid debug level "
872 "'%s', expected number > 0\n",
873 optarg);
874 return 1;
877 GP_SetDebugLevel(i);
878 break;
879 case 'o':
880 out_fmt = optarg;
881 check_fmt(out_fmt);
882 break;
883 case 'f':
884 add_filter(optarg);
885 break;
886 case 'p':
887 progress_callback = &callback;
888 break;
889 default:
890 print_help();
891 return 1;
895 if (optind >= argc) {
896 fprintf(stderr, "ERROR: Expected bitmap filenames\n");
897 return 1;
900 for (i = optind; i < argc; i++) {
901 char buf[255];
903 snprintf(buf, sizeof(buf), "out_%03i.%s", i - optind + 1, out_fmt);
904 fprintf(stderr, "Processing '%s' -> '%s'\n", argv[i], buf);
906 progress_prefix = "Loading image";
908 if ((bitmap = GP_LoadImage(argv[i], progress_callback)) == NULL) {
909 fprintf(stderr, "Failed to load bitmap: %s\n", strerror(errno));
910 return 1;
913 if (progress_callback != NULL)
914 fprintf(stderr, " done\n");
916 apply_filters(&bitmap);
918 save_by_fmt(bitmap, buf, out_fmt);
921 return 0;