This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via dc4ff99fcfb3320e4627e7f7c35c09c916da0809 (commit) via 67843356569850ec5c7f6e4e77c55dcb97fc6721 (commit) via 12806aae7921c0e11b2908d3bb842f294d1acdab (commit) via e66493630e62bac979731f58c0232c14c1f699d9 (commit) via d12cf1d15e383df010846ee3a53a36cc7ac64724 (commit) via 6c19433d1a062473a6bdc2a21b67168d3cec04fd (commit) via 15db0fc3351d6a78f3f654defde550aaf8813a7d (commit) via 5adcb7f068d9c8814fc1abecea76de442a3267bc (commit) via 8dba9bc6f1f94b008a6f4475d0af9d1e8c810f36 (commit) from 3d14cb78419fe54e86e6a838b919a303ae9e536f (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/dc4ff99fcfb3320e4627e7f7c35c09c916da0...
commit dc4ff99fcfb3320e4627e7f7c35c09c916da0809 Author: Cyril Hrubis metan@ucw.cz Date: Thu Oct 10 22:39:59 2013 +0200
spiv: Rewrite configuration, add config file.
* Rewrite spiv command line parameters parsing (adds long options)
* Add support for configuration files (now it tries /etc/spiv.conf and ~/.spiv)
* Add --print-man switch to generate man page
Not finished yet, more will come soon.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/demos/spiv/Makefile b/demos/spiv/Makefile index 93750f3..80cfa29 100644 --- a/demos/spiv/Makefile +++ b/demos/spiv/Makefile @@ -12,7 +12,7 @@ LDLIBS+=$(LDLIBS_LOADERS) $(LDLIBS_BACKENDS) APPS=spiv
spiv: cpu_timer.o image_cache.o image_list.o image_actions.o spiv_help.o- image_loader.o + image_loader.o cfg.o spiv_config.o
include $(TOPDIR)/app.mk include $(TOPDIR)/post.mk diff --git a/demos/spiv/cfg.c b/demos/spiv/cfg.c new file mode 100644 index 0000000..629929d --- /dev/null +++ b/demos/spiv/cfg.c @@ -0,0 +1,525 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <core/GP_Debug.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> +#include <stdarg.h> +#include <getopt.h> + +#include "cfg.h" + +static int terminal(struct cfg_opt *opt) +{ + return opt->key == NULL && opt->opt == 0 && opt->opt_long == NULL; +} + +struct cfg_opt *opt_by_key(struct cfg_opt *cfg_opts, const char *name_space, + const char *key) +{ + struct cfg_opt *i; + + GP_DEBUG(1, "Looking for key '%s' in name space '%s'", + key, name_space); + + for (i = cfg_opts; !terminal(i); i++) { + if (name_space == NULL) { + if (i->name_space == NULL && !strcmp(key, i->key)) + break; + } else { + if (i->name_space != NULL && !strcmp(key, i->key)) + break; + } + } + + if (terminal(i)) + return NULL; + + return i; +} + +int cfg_getopt(struct cfg_opt *opts, int argc, char *argv[]) +{ + unsigned int count = 0; + unsigned int long_count = 0; + struct cfg_opt *i; + int c, opt_idx; + + for (i = opts; !terminal(i); i++) { + if (i->opt) { + count++; + + if (i->opt_has_value) + count++; + } + + if (i->opt_long) + long_count++; + } + + char gopt[count+1]; + struct option gopt_long[long_count+1]; + struct cfg_opt *gopts_long[long_count+1]; + struct cfg_opt *gopts[256]; + + memset(gopt_long, 0, sizeof(gopt_long)); + memset(gopts, 0, sizeof(gopts)); + + count = 0; + long_count = 0; + + for (i = opts; !terminal(i); i++) { + if (i->opt) { + gopt[count++] = i->opt; + + if (i->opt_has_value) + gopt[count++] = ':'; + + if ((unsigned)i->opt >= sizeof(gopts)/(sizeof(*gopts))) { + GP_WARN("Char value > 256???"); + } else { + gopts[(unsigned)i->opt] = i; + } + } + + if (i->opt_long) { + gopt_long[long_count].name = i->opt_long; + gopt_long[long_count].has_arg = i->opt_has_value; + gopt_long[long_count].flag = NULL; + gopt_long[long_count].val = 0; + gopts_long[long_count] = i; + long_count++; + } + } + + gopt[count] = 0; + + GP_DEBUG(1, "Have getopt string '%s' and %u long opts", + gopt, long_count); + + for (;;) { + c = getopt_long(argc, argv, gopt, gopt_long, &opt_idx); + + switch (c) { + case -1: + return optind; + case 0: + GP_DEBUG(2, "Long option '%s'", + gopts_long[opt_idx]->opt_long); + + i = gopts_long[opt_idx]; + i->val = optarg; + + if (i->set(i, 0)) + return -1; + break; + default: + GP_DEBUG(2, "Short option '%c'", c); + + if ((unsigned)((char)c) >= sizeof(gopts)/(sizeof(*gopts))) { + GP_WARN("Getopt returned %i???", c); + break; + } + + i = gopts[(unsigned)((char)c)]; + + if (!i) + return -1; + + i->val = optarg; + + if (i->set(i, 0)) + return -1; + break; + } + + } +} + +struct parser_state { + struct cfg_opt *opts; + unsigned int lineno; + FILE *f; + char name_space[128]; + char buf[1024]; +}; + +static void parser_error(struct parser_state *state, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +static void parser_error(struct parser_state *state, const char *fmt, ...) +{ + va_list va; + + fprintf(stderr, "ERROR: %u: ", state->lineno); + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); + fprintf(stderr, "n"); +} + +static void read_comment(struct parser_state *state) +{ + int c; + + for (;;) { + c = getc_unlocked(state->f); + + switch (c) { + case EOF: + return; + case 'n': + state->lineno++; + return; + default: + break; + } + } +} + +static int parse_namespace(struct parser_state *state) +{ + size_t len = 0; + int c; + + for (;;) { + c = getc_unlocked(state->f); + + switch (c) { + case EOF: + parser_error(state, + "End of file while parsing namespace"); + return 1; + case 'n': + parser_error(state, "Newline while parsing namespace"); + return 1; + case ']': + state->name_space[len] = '0'; + return 0; + default: + state->name_space[len++] = c; + + if (len >= sizeof(state->name_space)) { + parser_error(state, "Namespace too long"); + return 1; + } + break; + } + } + + + GP_DEBUG(1, "In namespace '%s'", state->name_space); +} + +static int read_key(struct parser_state *state) +{ + size_t len = 0; + int c; + + for (;;) { + c = getc_unlocked(state->f); + + switch (c) { + case 'n': + state->lineno++; + case EOF: + case ' ': + case 't': + state->buf[len] = '0'; + GP_DEBUG(1, "Have key '%s'", state->buf); + return 0; + default: + state->buf[len++] = c; + + if (len >= sizeof(state->buf)) { + state->buf[sizeof(state->buf) - 1] = '0'; + parser_error(state, "Key '%s...' is too long", + state->buf); + return 1; + } + break; + } + } +} + +static void read_whitespaces(struct parser_state *state) +{ + int c; + + for (;;) { + c = getc_unlocked(state->f); + + switch (c) { + case 'n': + state->lineno++; + case ' ': + case 't': + break; + case EOF: + return; + default: + ungetc(c, state->f); + return; + } + } +} + +static const char *name_space(struct parser_state *state) +{ + if (state->name_space[0]) + return state->name_space; + + return NULL; +} + +static int parse_pair(struct parser_state *state) +{ + struct cfg_opt *opt; + int c; + + if (read_key(state)) + return 1; + + opt = opt_by_key(state->opts, name_space(state), state->buf); + + if (!opt) { + parser_error(state, "There is no key '%s' in name space '%s'", + state->buf, name_space(state)); + return 1; + } + + if (!opt->opt_has_value) { + if (opt->set(opt, state->lineno)) + return 1; + + return 0; + } + + read_whitespaces(state); + + c = fgetc_unlocked(state->f); + + switch (c) { + case EOF: + parser_error(state, "End of file while looking for ="); + return 1; + case '=': + break; + default: + parser_error(state, "Expected = got '%c'", c); + } + + read_whitespaces(state); + + //TODO write read val with quotation marks and poker + if (read_key(state)) + return 1; + + opt->val = state->buf; + + if (opt->set(opt, state->lineno)) + return 1; + + return 0; +} + +static int parse_cfg(struct parser_state *state) +{ + int c; + + for (;;) { + c = getc_unlocked(state->f); + + switch (c) { + case EOF: + GP_DEBUG(1, "End of config reached at %u", + state->lineno); + return 0; + case 'n': + state->lineno++; + case ' ': + case 't': + break; + case '#': + read_comment(state); + break; + case '[': + if (parse_namespace(state)) + return 1; + break; + default: + ungetc(c, state->f); + if (parse_pair(state)) + return 1; + break; + } + } +} + +int cfg_load(struct cfg_opt *opts, const char *path) +{ + struct parser_state state; + int ret; + + state.opts = opts; + state.lineno = 1; + state.f = fopen(path, "r"); + state.name_space[0] = '0'; + + if (!state.f) { + GP_WARN("Failed to open '%s': %s'", path, strerror(errno)); + return 1; + } + + ret = parse_cfg(&state); + fclose(state.f); + + return ret; +} + +const char *has_value(struct cfg_opt *opt) +{ + if (opt->opt_has_value) + return "=value"; + + return ""; +} + +void cfg_print_help(struct cfg_opt *opts) +{ + struct cfg_opt *i; + const char *name_space = NULL; + + printf("n"); + + for (i = opts; !terminal(i); i++) { + if ((name_space && !i->name_space) || + (name_space && strcmp(i->name_space, name_space)) || + (!name_space && i->name_space)) { + + printf("n"); + + if (i->name_space) + printf(" %s:n", i->name_space); + + name_space = i->name_space; + } + + if (i->opt && !i->opt_long) + printf(" -%c%sn", i->opt, has_value(i)); + + if (!i->opt && i->opt_long) + printf(" --%s%sn", i->opt_long, has_value(i)); + + if (i->opt && i->opt_long) { + printf(" -%c%s, --%s%sn", i->opt, has_value(i), + i->opt_long, has_value(i)); + } + + if (i->help) + printf(" t%snn", i->help); + } +} + +static void man_escape_print(const char *str) +{ + while (*str) { + switch (*str) { + case '-': + printf("-"); + break; + default: + printf("%c", *str); + break; + } + str++; + } +} + +void cfg_print_man(struct cfg_opt *opts) +{ + struct cfg_opt *i; + const char *name_space = NULL; + + printf(".SH OPTIONSn"); + + for (i = opts; !terminal(i); i++) { + if ((name_space && !i->name_space) || + (name_space && strcmp(i->name_space, name_space)) || + (!name_space && i->name_space)) { + + if (i->name_space) + printf(".TPn.I %sn", i->name_space); + + name_space = i->name_space; + } + + if (i->opt || i->opt_long) + printf(".TPn"); + + if (i->opt && !i->opt_long) + printf(".B -%c%sn", i->opt, has_value(i)); + + if (!i->opt && i->opt_long) + printf(".B --"); + + if (i->opt && i->opt_long) + printf(".B -%c%s, --", i->opt, has_value(i)); + + if (i->opt_long) { + man_escape_print(i->opt_long); + printf("%sn", has_value(i)); + } + + if (i->help) { + man_escape_print(i->help); + printf("n"); + } + } + + printf(".SH CONFIGURATION FILEn"); + + printf("Configuraton file has simple key = value syntax, "); + printf("keys without values are written just as key.n"); + printf("Lines started with # are comments.n"); + printf("Keys are grouped in namespaces, namespace block is startedn"); + printf("by [NameSpace] and continues until next namespace.n"); + + name_space = NULL; + + for (i = opts; !terminal(i); i++) { + if ((name_space && !i->name_space) || + (name_space && strcmp(i->name_space, name_space)) || + (!name_space && i->name_space)) { + if (i->name_space) + printf(".TPn.I [%s]n", i->name_space); + + name_space = i->name_space; + } + if (i->key) { + printf(".TPn.B %s%sn", i->key, has_value(i)); + if (i->help) + printf("%sn", i->help); + } + } +} diff --git a/demos/spiv/cfg.h b/demos/spiv/cfg.h new file mode 100644 index 0000000..49107b7 --- /dev/null +++ b/demos/spiv/cfg.h @@ -0,0 +1,79 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + + /* + + Configuration loader/storage. + + Configuration is simple namespace,key -> value storage, the configuration + could either be loaded from config file and/or overriden by argumant parser. + + */ + +#ifndef __CFG_H__ +#define __CFG_H__ + +struct cfg_opt { + /* Could be NULL for global values */ + const char *name_space; + /* Must be set */ + const char *key; + /* Short command line option, i.e. -f */ + const char opt; + /* Long command option, i.e. --foo */ + const char *opt_long; + /* set to 1 if option has parameter */ + int opt_has_value; + /* help string */ + const char *help; + /* setter function, called for each parset key = val pair */ + int (*set)(struct cfg_opt *self, unsigned int lineno); + /* pointer to pass value from parser */ + const char *val; +}; + +/* + * Loads configuration from a file. + * + * Returns zero on success, non-zero on failure (and prints error message into + * stderr). + */ +int cfg_load(struct cfg_opt *opts, const char *path); + +/* + * Parses configuration options from command line parameters. + * + * Returns number of used strings from argv on success, -1 on failure. + */ +int cfg_getopt(struct cfg_opt *opts, int argc, char *argv[]); + +/* + * Prints help for switches. + */ +void cfg_print_help(struct cfg_opt *opts); + +/* + * Prints man-page formatted options + config. + */ +void cfg_print_man(struct cfg_opt *opts); + +#endif /* __CFG_H__ */ diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c index 076bea3..4b2d414 100644 --- a/demos/spiv/spiv.c +++ b/demos/spiv/spiv.c @@ -26,7 +26,6 @@
*/
-#include <unistd.h> #include <errno.h> #include <signal.h> #include <string.h> @@ -39,6 +38,7 @@ #include "image_loader.h" #include "image_actions.h" #include "spiv_help.h" +#include "spiv_config.h" #include "cpu_timer.h"
static GP_Pixel black_pixel; @@ -80,19 +80,11 @@ struct loader_params { /* current resize ratio */ float rat;
- /* show loader progress */ - long show_progress:1; long show_progress_once:2; - /* show image info in topleft corner */ - long show_info:3; /* use nearest neighbour resampling first */ long show_nn_first:4; - /* use dithering when blitting to display */ - long use_dithering:5; /* use low pass before resampling */ long use_low_pass:6; - /* image orientation 0, 90, 180, 270 */ - int orientation; /* resampling method */ int resampling_method;
@@ -278,7 +270,7 @@ static void show_info(struct loader_params *params, GP_Context *img,
set_caption(img_path, params->rat);
- if (!params->show_info) + if (!config.show_info) return;
GP_Size th = GP_TextHeight(NULL); @@ -314,18 +306,18 @@ static void update_display(struct loader_params *params, GP_Context *img, struct cpu_timer timer; GP_ProgressCallback callback = {.callback = image_loader_callback};
- switch (params->orientation) { - case 0: + switch (config.orientation) { + case ROTATE_0: break; - case 90: + case ROTATE_90: callback.priv = "Rotating image (90)"; img = GP_FilterRotate90Alloc(img, &callback); break; - case 180: + case ROTATE_180: callback.priv = "Rotating image (180)"; img = GP_FilterRotate180Alloc(img, &callback); break; - case 270: + case ROTATE_270: callback.priv = "Rotating image (270)"; img = GP_FilterRotate270Alloc(img, &callback); break; @@ -354,7 +346,7 @@ static void update_display(struct loader_params *params, GP_Context *img,
cpu_timer_start(&timer, "Blitting");
- if (params->use_dithering) { + if (config.floyd_steinberg) { callback.priv = "Dithering"; GP_SubContext(context, &sub_display, cx, cy, img->w, img->h); GP_FilterFloydSteinberg(img, &sub_display, NULL); @@ -384,7 +376,7 @@ static void update_display(struct loader_params *params, GP_Context *img,
show_info(params, img, orig_img);
- if (params->orientation) + if (config.orientation) GP_ContextFree(img);
GP_BackendFlip(backend); @@ -472,13 +464,13 @@ static float calc_img_size(struct loader_params *params, float w_rat; float h_rat;
- switch (params->orientation) { - case 0: - case 180: + switch (config.orientation) { + case ROTATE_0: + case ROTATE_180: default: break; - case 90: - case 270: + case ROTATE_90: + case ROTATE_270: GP_SWAP(src_w, src_h); break; } @@ -509,7 +501,7 @@ static void *image_loader(void *ptr)
cpu_timer_start(&sum_timer, "sum");
- show_progress = params->show_progress || params->show_progress_once; + show_progress = config.show_progress || params->show_progress_once; params->show_progress_once = 0;
if ((orig_img = load_image(0)) == NULL) { @@ -679,18 +671,12 @@ static uint32_t timer_callback(GP_Timer *self) int main(int argc, char *argv[]) { GP_Context *context = NULL; - const char *backend_opts = "X11"; - int opt; int shift_flag; - GP_PixelType emul_type = GP_PIXEL_UNKNOWN; + int opts;
struct loader_params params = { - .show_progress = 0, .show_progress_once = 0, - .show_info = 0, .show_nn_first = 0, - .use_dithering = 0, - .orientation = 0, .resampling_method = GP_INTERP_LINEAR_LF_INT,
.zoom_type = ZOOM_FIT, @@ -703,77 +689,29 @@ int main(int argc, char *argv[])
GP_TIMER_DECLARE(timer, 0, 0, "Slideshow", timer_callback, ¶ms);
- while ((opt = getopt(argc, argv, "b:ce:fhIPr:s:tz:0:1:2:3:4:5:6:7:8:9:")) != -1) { - switch (opt) { - case 'I': - params.show_info = 1; - break; - case 'P': - params.show_progress = 1; - break; - case 'f': - params.use_dithering = 1; - break; - case 's': - params.sleep_ms = 1000 * atof(optarg) + 0.5; - break; - case 'c': - params.resampling_method = GP_INTERP_CUBIC_INT; - /* Cubic resampling needs low pass */ - params.use_low_pass = 1; - /* Cubic resampling is slow, show nn first */ - params.show_nn_first = 1; - break; - case 'e': - emul_type = GP_PixelTypeByName(optarg); - - if (emul_type == GP_PIXEL_UNKNOWN) { - fprintf(stderr, "Invalid pixel type '%s'n", optarg); - return 1; - } - break; - case 'r': - if (!strcmp(optarg, "90")) - params.orientation = 90; - else if (!strcmp(optarg, "180")) - params.orientation = 180; - else if (!strcmp(optarg, "270")) - params.orientation = 270; - case 'b': - backend_opts = optarg; - break; - case 'h': - print_help(); - exit(0); - break; - case 't': - cpu_timer_switch(1); - break; - case 'z': - switch (optarg[0]) { - case 'f': - params.zoom_type = ZOOM_FIXED; - break; - case 'w': - params.zoom_type = ZOOM_FIXED_WIN; - break; - } - break; - case '0': - /* -0 is mapped to action 10 */ - image_action_set(9, optarg); - break; - case '1' ... '9': - image_action_set(opt - '1', optarg); - break; - default: - fprintf(stderr, "Invalid paramter '%c'n", opt); - print_help(); - return 1; - } + if (access("/etc/spiv.conf", R_OK) == 0) + spiv_config_load("/etc/spiv.conf"); + + if (getenv("HOME")) { + char buf[256]; + + snprintf(buf, sizeof(buf), "%s/%s", getenv("HOME"), ".spiv"); + + if (access(buf, R_OK) == 0) + spiv_config_load(buf); }
- if (optind >= argc) { + opts = spiv_config_parse_args(argc, argv); + + if (opts < 0) { + print_help(); + return 1; + } + + cpu_timer_switch(config.timers); + params.sleep_ms = 1000 * config.slideshow_delay + 0.5; + + if (opts >= argc) { fprintf(stderr, "Requires path to at least one imagenn"); print_help(); return 1; @@ -784,13 +722,15 @@ int main(int argc, char *argv[]) signal(SIGBUS, sighandler); signal(SIGABRT, sighandler);
- if (init_loader(¶ms, (const char **)argv + optind)) + if (init_loader(¶ms, (const char **)argv + opts)) return 1;
- init_backend(backend_opts); + init_backend(config.backend_init);
- if (emul_type != GP_PIXEL_UNKNOWN) - backend = GP_BackendVirtualInit(backend, emul_type, GP_BACKEND_CALL_EXIT); + if (config.emul_type != GP_PIXEL_UNKNOWN) { + backend = GP_BackendVirtualInit(backend, config.emul_type, + GP_BACKEND_CALL_EXIT); + }
context = backend->context;
@@ -849,18 +789,28 @@ int main(int argc, char *argv[]) GP_BackendX11RequestFullscreen(backend, 2); break; case GP_KEY_I: - params.show_info = !params.show_info; + config.show_info = !config.show_info;
params.show_progress_once = 1; show_image(¶ms); break; case GP_KEY_P: - params.show_progress = !params.show_progress; + config.show_progress = !config.show_progress; break; case GP_KEY_R: - params.orientation += 90; - if (params.orientation > 270) - params.orientation = 0; + config.orientation++; + + if (config.orientation > ROTATE_270) + config.orientation = 0; + + params.show_progress_once = 1; + show_image(¶ms); + break; + case GP_KEY_E: + if (config.orientation > 0) + config.orientation--; + else + config.orientation = ROTATE_270;
params.show_progress_once = 1; show_image(¶ms); diff --git a/demos/spiv/spiv_config.c b/demos/spiv/spiv_config.c new file mode 100644 index 0000000..08b2f63 --- /dev/null +++ b/demos/spiv/spiv_config.c @@ -0,0 +1,348 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "cfg.h" +#include "image_actions.h" +#include "spiv_config.h" + +/* + * These are default config values, you can hardcompile yours here. + */ +struct spiv_config config = { + .slideshow_delay = 0, + .show_info = 0, + .backend_init = "X11", + .emul_type = GP_PIXEL_UNKNOWN, +}; + +static int set_zoom_strategy(struct cfg_opt *self, unsigned int lineno) +{ + (void) lineno; + //TODO!!! + printf("ZoomStrategy = %sn", self->val); + + return 0; +} + +static int set_action(struct cfg_opt *self, unsigned int lineno) +{ + (void) lineno; + image_action_set(atoi(self->key), self->val); + return 0; +} + +static int set_opt(struct cfg_opt *self, unsigned int lineno) +{ + (void) self; + (void) lineno; + + switch (self->opt) { + case 'f': + config.floyd_steinberg = 1; + break; + case 'i': + config.show_info = 1; + break; + case 'p': + config.show_progress = 1; + break; + case 't': + config.timers = 1; + break; + } + + return 0; +} + +static int set_orientation(struct cfg_opt *self, unsigned int lineno) +{ + if (!strcmp("0", self->val)) { + config.orientation = ROTATE_0; + return 0; + } + + if (!strcmp("90", self->val)) { + config.orientation = ROTATE_90; + return 0; + } + + if (!strcmp("180", self->val)) { + config.orientation = ROTATE_180; + return 0; + } + + if (!strcmp("270", self->val)) { + config.orientation = ROTATE_270; + return 0; + } + + fprintf(stderr, "ERROR: %u: Invalid orientation '%s'n", + lineno, self->val); + return 1; +} + +static int set_backend_init(struct cfg_opt *self, unsigned int lineno) +{ + if (strlen(self->val) + 1 >= sizeof(config.backend_init)) { + fprintf(stderr, "ERROR: %u: Backend init string too longn", + lineno); + return 1; + } + + strcpy(config.backend_init, self->val); + + return 0; +} + +static int set_slideshow(struct cfg_opt *self, unsigned int lineno) +{ + config.slideshow_delay = atof(self->val); + + if (config.slideshow_delay == 0) { + fprintf(stderr, "ERROR: %u: Invalid slideshow delay '%s'n", + lineno, self->val); + return 1; + } + + return 0; +} + +static int set_emulation(struct cfg_opt *self, unsigned int lineno) +{ + config.emul_type = GP_PixelTypeByName(optarg); + + if (config.emul_type == GP_PIXEL_UNKNOWN) { + fprintf(stderr, "ERROR: %u: Invalid pixel type '%s'n", + lineno, self->val); + return 1; + } + + return 0; +} + +static int help(struct cfg_opt *self, unsigned int lineno) +{ + (void) self; + (void) lineno; + + print_help(); + exit(0); +} + +static int man(struct cfg_opt *self, unsigned int lineno) +{ + (void) self; + (void) lineno; + + print_man(); + exit(0); +} + +struct cfg_opt spiv_opts[] = { + {.name_space = NULL, + .key = NULL, + .opt = 'h', + .opt_long = "help", + .opt_has_value = 0, + .set = help, + .help = "Shows this help", + }, + + {.name_space = "Gui", + .key = "ShowInfo", + .opt = 'i', + .opt_long = "show-info", + .opt_has_value = 0, + .set = set_opt, + .help = "Show image info such as filename, size, etc...", + }, + {.name_space = "Gui", + .key = "ShowProgress", + .opt = 'p', + .opt_long = "show-progress", + .set = set_opt, + .help = "Show progress bar when loading/resampling/... images", + }, + {.name_space = "Gui", + .key = "SlideshowDelay", + .opt = 's', + .opt_long = "slideshow-delay", + .opt_has_value = 1, + .set = set_slideshow, + .help = "Delay between images in seconds (float) for slideshow", + }, + {.name_space = "Gui", + .key = "UseFloydSteinberg", + .opt = 'f', + .opt_long = "floyd-steinberg", + .opt_has_value = 0, + .set = set_opt, + .help = "Turn on Floyd-Steinberg dithering", + }, + {.name_space = "Gui", + .key = "Orientation", + .opt = 'o', + .opt_long = "orientation", + .opt_has_value = 1, + .set = set_orientation, + .help = "Orientation, one of 0, 90, 180, 270", + }, + {.name_space = "Gui", + .key = "BackendInit", + .opt = 'b', + .opt_long = "backend-init", + .opt_has_value = 1, + .set = set_backend_init, + .help = "Backend init string, set it to 'help' for more info", + }, + + {.name_space = "Zoom", + .key = "ZoomStrategy", + .opt = 'z', + .opt_long = "zoom-strategy", + .opt_has_value = 1, + .set = set_zoom_strategy, + .help = "Zoom strategy", + }, + + + {.name_space = "Actions", + .key = "1", + .opt = '1', + .opt_long = "action-1", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "2", + .opt = '2', + .opt_long = "action-2", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "3", + .opt = '3', + .opt_long = "action-3", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "4", + .opt = '4', + .opt_long = "action-4", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "5", + .opt = '5', + .opt_long = "action-5", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "6", + .opt = '6', + .opt_long = "action-6", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "7", + .opt = '7', + .opt_long = "action-7", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "8", + .opt = '8', + .opt_long = "action-8", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "9", + .opt = '9', + .opt_long = "action-9", + .opt_has_value = 1, + .set = set_action, + }, + {.name_space = "Actions", + .key = "10", + .opt = '0', + .opt_long = "action-10", + .opt_has_value = 1, + .set = set_action, + .help = "Sets command line for action 1-10", + }, + + {.name_space = "Devel", + .key = "Timers", + .opt = 't', + .opt_long = "timers", + .opt_has_value = 0, + .set = set_opt, + .help = "Turns on cpu and wall clock measurement (printed to stdout)", + }, + {.name_space = "Devel", + .key = "BackendEmulation", + .opt_long = "backend-emulation", + .opt_has_value = 1, + .set = set_emulation, + .help = "Emulate different backend pixel type (G1, G2, RGB555, ...)", + }, + {.name_space = "Devel", + .key = NULL, + .opt_long = "print-man", + .opt_has_value = 0, + .set = man, + .help = "Prints spiv man page to stdout", + }, + + {NULL} +}; + +int spiv_config_load(const char *path) +{ + return cfg_load(spiv_opts, path); +} + +int spiv_config_parse_args(int argc, char *argv[]) +{ + return cfg_getopt(spiv_opts, argc, argv); +} + +void spiv_config_print_help(void) +{ + cfg_print_help(spiv_opts); +} + +void spiv_config_print_man(void) +{ + cfg_print_man(spiv_opts); +} diff --git a/demos/spiv/spiv_config.h b/demos/spiv/spiv_config.h new file mode 100644 index 0000000..41a83b2 --- /dev/null +++ b/demos/spiv/spiv_config.h @@ -0,0 +1,56 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#ifndef __SPIV_CONFIG_H__ +#define __SPIV_CONFIG_H__ + +#include <GP.h> + +enum orientation { + ROTATE_0, + ROTATE_90, + ROTATE_180, + ROTATE_270, +}; + +struct spiv_config { + float slideshow_delay; + enum orientation orientation; + int show_progress:1; + int show_info:1; + int floyd_steinberg:1; + int timers:1; + char backend_init[128]; + GP_PixelType emul_type; +}; + +extern struct spiv_config config; + +int spiv_config_load(const char *path); + +int spiv_config_parse_args(int argc, char *argv[]); + +void spiv_config_print_help(void); + +void spiv_config_print_man(void); + +#endif /* __SPIV_CONFIG_H__ */ diff --git a/demos/spiv/spiv_help.c b/demos/spiv/spiv_help.c index f6abe41..0d6a6b6 100644 --- a/demos/spiv/spiv_help.c +++ b/demos/spiv/spiv_help.c @@ -23,102 +23,207 @@ #include <stdio.h> #include <GP.h>
-static const char *keys_help[] = { - "Keyboard control:", - "", - "Esc, Enter, Q - quit spiv", - "", - "< or KP Minus - zoom out by 1.5", - "> or KP Plus - zoom in by 1.5", - "R - rotate by 90 degrees clockwise", - "Up, Down, Left, Right - move image by 1px", - " (by 10 with Shift)", - "", - "Space - move to the next image", - "BackSpace - move to the prev image", - "PgDown - move to the start of directory", - "PgUp - move to the end of directory", - "Home - move to the first image", - "End - move to the last image", - "", - "I - toggle show info box", - "P - toggle show progress", - "S - stop/restart slideshow", - "", - "] - change to next resampling method", - "[ - change to prev resampling method", - " (current method is shown in info box)", - "L - toggle low pass filter", - "D - drop image cache", - "H - toggle help", - "", - "F1-F10 - execute action 1 - 10", - "", - "1 - resize spiv window to the image size", - "2 - resize spiv window to the half of the image size", - "3 - resize spiv window to the third of the image size", - "...", - "9 - resize spiv window to the ninth of the image size", - "0 - resize spiv window to the tenth of the image size", - "", - "Shift 2 - resize spiv window twice of the image size", - "Shift 3 - resize spiv window three times of the image size", - "...", +#include "spiv_config.h" +#include "spiv_help.h" + +struct key_help { + const char *keys; + const char *desc; +}; + +#define KEYS_MAX "13" + +static struct key_help help_keys[] = { + {"Esc, Enter, Q", "Quit spiv"}, + {"Space", "Move to the next image"}, + {"BackSpace", "Move to the prev image"}, + {"PgDown", "Move to the start of directory"}, + {"PgUp", "Move to the end of directory"}, + {"Home", "Move to the first image"}, + {"End", "Move to the last image"}, + {"R", "Rotate by 90 degrees clockwise"}, + {"E", "Rotate by 90 degrees counterclockwise"}, + {"H", "Show help"}, + {"I", "Toggle show info box"}, + {"P", "Toggle show progress"}, + {"S", "Start/stop slideshow"}, + {"", ""}, + {"F1-F10", "Execute action 1 - 10"}, + {"", ""}, + {"<, KP Minus", "Zoom out by 50%"}, + {">, KP Plus", "Zoom in by 50%"}, + {"1", "Resize spiv window to the image size"}, + {"2", "Resize spiv window to a half of the image size"}, + {"3", "Resize spiv window to one third of the image size"}, + {"9", "Resize spiv window to one ninth of the image size"}, + {"...", ""}, + {"0", "Resize spiv window to one tenth of the image size"}, + {"Shift 2", "Resize spiv window twice of the image size"}, + {"Shift 3", "Resize spiv window three times of the image size"}, + {"...", ""}, + {"Up", "Move image by 1px up (by 10 with Shift)"}, + {"Down", "Move image by 1px down (by 10 with Shift)"}, + {"Left", "Move image by 1px left (by 10 with Shift)"}, + {"Right", "Move image by 1px right (by 10 with Shift)"}, + {"", ""}, + {"]", "Change to next resampling method"}, + {"[", "Change to prev resampling method"}, + {"L", "Toggle low pass filter"}, + {"D", "Drop image cache"}, };
-static const int keys_help_len = sizeof(keys_help) / sizeof(char*); +static const int help_keys_len = sizeof(help_keys) / sizeof(*help_keys); + +struct examples { + const char *example; + const char *desc; +}; + +static const struct examples examples[] = { + {"spiv *.jpg", + "Shows all jpeg images in current directory"}, + {"spiv images.zip", + "Shows all images stored in zip file"}, + {"spiv .", + "Shows all loadable images in current directory"}, + {"spiv -t 5 vacation/", + "Runs slideshow with 5 second delay"}, + {"spiv -1 'cp %F sorted' images/", + "Copies currently loaded image into directory 'sorted/' on pressing F1"}, + {"spiv -e G1 -f images/", + "Emulates 1-bit Grayscale display and turns on Floyd-Steinberg dithering"}, + {"spiv -b 'X11:ROOT_WIN' -t 10 images/", + "Runs slideshow using X root window as backend window"}, + {"spiv -b 'X11:CREATE_ROOT' -t 10 images/", + "Same as abowe but works in KDEn"} +}; + +static const int examples_len = sizeof(examples) / sizeof(*examples); + +struct actions { + const char modifier; + const char *desc; +}; + +static struct actions actions[] = { + {'f', "Path to current image"}, + {'F', "Shell escaped path to current image"}, + {'n', "Current image filename without extension"}, + {'N', "Shell escaped image filename without extension"}, + {'e', "Current image file extension"}, +}; + +static const int actions_len = sizeof(actions) / sizeof(*actions);
void print_help(void) { int i;
- printf("Usage: spiv [opts] images or dirs with imagesnn"); - printf(" -I show image info boxn"); - printf(" -P show loading progressn"); - printf(" -f use floyd-steinberg ditheringn"); - printf(" -s sec slideshow interval in seconds (floating point value)n"); - printf(" -c turns on bicubic resampling (experimental)n"); - printf(" -e pixel_type turns on backend type emulationn"); - printf(" for example -e G1 sets 1-bit grayscalen"); - printf(" -r angle rotate display 90,180 or 270 degreesn"); - printf(" -z moden"); - printf(" -zf zoom is set and modified by usern"); - printf(" -zw zoom is fixed to window size (currently default)n"); - printf(" -b pass backend init string to backend initn"); - printf(" pass -b help for more infon"); - printf(" -t enable timersn"); - printf(" if set timers that measure cpu and wall timen"); - printf(" of certain operations are printed into stdoutn"); - puts("n"); - printf("Actions:nn"); - printf(" -1 'cmd' sets first actionn"); - printf(" ...n"); - printf(" -9 'cmd' sets ninth actionn"); - printf(" -0 'cmd' sets tenth actionn"); - puts(""); - printf(" actions are shell commands with following modifiers:n"); - printf(" %%f path to current imagen"); - printf(" %%F shell escaped path to current imagen"); - printf(" %%n current image filename without extensionn"); - printf(" %%N shell escaped image filename without extensionn"); - printf(" %%e current image file extensionn"); - puts("n"); + printf("Usage: spiv [opts] images or dirs with imagesn"); + spiv_config_print_help(); + + printf(" Action shell command modifiers:n");
- for (i = 0; i < keys_help_len; i++) - puts(keys_help[i]); + for (i = 0; i < actions_len; i++) + printf(" %%%c %sn", actions[i].modifier, actions[i].desc); + + printf("n"); + + printf("Keyboard controls:nn"); + + for (i = 0; i < help_keys_len; i++) { + if (help_keys[i].desc[0] == '0') { + printf(" %sn", help_keys[i].keys); + } else { + printf(" %-"KEYS_MAX"s - %sn", + help_keys[i].keys, help_keys[i].desc); + } + }
puts("");
- printf("Some cool options to try:nn"); - printf("spiv -0 'cp %%F sorted' [images]n"); - printf("tcopies current image into directory 'sorted/' on F1n"); - printf("spiv -e G1 -f [images]n"); - printf("truns spiv in 1-bit bitmap mode and turns on ditheringnn"); - printf("spiv -b 'X11:ROOT_WIN' [images]n"); - printf("truns spiv using X root window as backend windownn"); - printf("spiv -b 'X11:CREATE_ROOT' [images]n"); - printf("tSame as abowe but works in KDEn"); + printf("Example usage:nn");
+ for (i = 0; i < examples_len; i++) + printf("%snt%sn", examples[i].example, examples[i].desc); +} + +const char *man_head = + ".TH spiv 1 2013 GFXprim "Simple yet Powerful Image Viewer"nn" + ".SH NAMEn" + "spiv - Simple yet Powerful Image Viewern" + ".SH SYNOPSISn" + ".B spivn" + "[options] images|dirsn" + ".SH DESCRIPTIONn" + ".B spivn" + "is a fast, lightweight and minimalistic image viewer build on then" + "top of the GFXprim library.n" + ".PPn" + "Spiv supports wide range of image formats, currently supported aren" + "JPEG, PNG, GIF, BMP, TIFF, PSP, PPM, JP2 and CBZ (as well generaln" + "ZIP archives with images), and more will come in the near future.n" + ".PPn" + "Spiv supports variety of video backends (via GFXprim backends)n" + "currently these are X11, Linux Framebuffer, SDL and AAlib. Spiv alson" + "supports wide range of backend pixel types from 1bit Grayscale to 32bit RGBn" + "with optional Floyd-Steinberg dithering (even, for example, from RGB888 to RGB565).n" + ".PPn" + "Spiv implements feh-like image actions, which are short shell scripts withn" + "printf-like modifiers.n" + "Seen.B ACTIONSnbellow for further information.n"; + +static const char *man_tail = + ".SH BUGSn" + "Bugs happen. If you find one, report it on the GFXprim mailing list atn" + ".I gfxprim@ucw.czn" + ".SH AUTHORSn" + "Spiv is developed by Cyril Hrubis chrubis@ucw.czn" + ".PPnGFXprim was/is developed by:n" + ".PPn.nfnCyril Hrubis chrubis@ucw.czn" + ".nfnJiri "BlueBear" Dluhos jiri.bluebear.dluhos@gmail.comn" + ".nfnTomas Gavenciak gavento@ucw.czn"; + +static const char *actions_help = + ".SH ACTIONSn" + "Actions are short shell scripts with printf-like modifiers, the n" + "modifiers are substituted to current image path, name, etc. and executedn" + "by pressing function keys).n" + ".PPn" + "Actions could be set via command line parameters or written into then" + "configuration file and support following modifiers:n"; + +void print_man(void) +{ + int i; + + puts(man_head); + + printf(".SH KEYBOARD CONTROLn"); + + for (i = 0; i < help_keys_len; i++) { + if (help_keys[i].desc[0] != '0') { + printf(".IP "%s"n", help_keys[i].keys); + printf("%sn", help_keys[i].desc); + } + } + + spiv_config_print_man(); + + puts(".PPnConfiguration is loaded from /etc/spiv.conf"); + puts("then ~/.spiv and overriden by command line parameters.n"); + + puts(actions_help); + + for (i = 0; i < actions_len; i++) + printf(".PPn.B %%%cn%sn", actions[i].modifier, actions[i].desc); + + puts(".SH EXAMPLES"); + + for (i = 0; i < examples_len; i++) + printf(".PPn.B %sn.nfn%snn", examples[i].desc, examples[i].example); + + puts(man_tail); }
static int redraw_help(GP_Backend *backend, unsigned int loff, GP_Coord xoff) @@ -130,14 +235,17 @@ static int redraw_help(GP_Backend *backend, unsigned int loff, GP_Coord xoff)
GP_Fill(c, black);
- for (i = loff; i < keys_help_len; i++) { - GP_Coord h = 2 + (i - loff) * 15; + GP_Print(c, NULL, 20 + 10 * xoff, 2, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, + white, black, "%s", "Keyboard Controls:"); + + for (i = loff; i < help_keys_len; i++) { + GP_Coord h = 2 + (i - loff + 1) * 15;
if (h + 2 >= (GP_Coord)c->h) goto out;
GP_Print(c, NULL, 20 + 10 * xoff, h, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - white, black, "%s", keys_help[i]); + white, black, "%-"KEYS_MAX"s - %s", help_keys[i].keys, help_keys[i].desc); }
out: @@ -167,7 +275,7 @@ void draw_help(GP_Backend *backend)
switch (ev.val.key.key) { case GP_KEY_DOWN: - if (last < keys_help_len) + if (last < help_keys_len) last = redraw_help(backend, ++loff, xoff); break; case GP_KEY_UP: @@ -181,8 +289,8 @@ void draw_help(GP_Backend *backend) last = redraw_help(backend, loff, ++xoff); break; case GP_KEY_PAGE_DOWN: - if (last < keys_help_len) { - if (loff + max_lines(backend) >= keys_help_len) + if (last < help_keys_len) { + if (loff + max_lines(backend) >= help_keys_len) break;
loff += max_lines(backend);
http://repo.or.cz/w/gfxprim.git/commit/67843356569850ec5c7f6e4e77c55dcb97fc6...
commit 67843356569850ec5c7f6e4e77c55dcb97fc6721 Author: Cyril Hrubis metan@ucw.cz Date: Sat Oct 12 02:07:59 2013 +0200
doc: Add AALib to supported backend in general info.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/doc/general.txt b/doc/general.txt index 00dd795..2c5bc9f 100644 --- a/doc/general.txt +++ b/doc/general.txt @@ -201,8 +201,8 @@ Backends
link:backends.html[Backends] together with link:input.html[Input] are API for drawing on screen (or into a window) and for getting keystrokes/mouse -coordinates. So far we support X11, linux framebuffer and SDL as a graphics -backend. +coordinates. So far we support X11, linux framebuffer, SDL and AALib as a +graphics backend.
There is also a virtual backend used for testing that allows you to create a backend of any pixel type on the top of other backends.
http://repo.or.cz/w/gfxprim.git/commit/12806aae7921c0e11b2908d3bb842f294d1ac...
commit 12806aae7921c0e11b2908d3bb842f294d1acdab Author: Cyril Hrubis metan@ucw.cz Date: Thu Oct 10 16:18:44 2013 +0200
spiv: Another cleanup.
Shuffle the code a bit, remove unused cruft.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/demos/spiv/spiv.c b/demos/spiv/spiv.c index 4eb4433..076bea3 100644 --- a/demos/spiv/spiv.c +++ b/demos/spiv/spiv.c @@ -92,7 +92,7 @@ struct loader_params { /* use low pass before resampling */ long use_low_pass:6; /* image orientation 0, 90, 180, 270 */ - int rotate; + int orientation; /* resampling method */ int resampling_method;
@@ -168,31 +168,6 @@ static void resize_backend(float ratio, int shift_flag) }
-static float calc_img_size(struct loader_params *params, - uint32_t img_w, uint32_t img_h, - uint32_t src_w, uint32_t src_h) -{ - float w_rat; - float h_rat; - - switch (params->zoom_type) { - case ZOOM_FIT_DOWNSCALE: - if (img_w <= src_w && img_h <= src_h) - return 1.00; - case ZOOM_FIT: - w_rat = 1.00 * src_w / img_w; - h_rat = 1.00 * src_h / img_h; - return GP_MIN(w_rat, h_rat); - case ZOOM_FIXED: - return params->zoom; - case ZOOM_FIXED_WIN: - resize_backend(params->zoom, 0); - return params->zoom; - } - - return 1.00; -} - static const char *img_name(const char *img_path) { int i, len = strlen(img_path); @@ -272,6 +247,66 @@ static void pattern_fill(GP_Context *ctx, unsigned int x0, unsigned int y0, } }
+ +static void info_printf(GP_Context *ctx, GP_Coord x, GP_Coord y, + const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +static void info_printf(GP_Context *ctx, GP_Coord x, GP_Coord y, + const char *fmt, ...) +{ + va_list va, vac; + + va_start(va, fmt); + + va_copy(vac, va); + GP_VPrint(ctx, NULL, x-1, y-1, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, + black_pixel, white_pixel, fmt, vac); + va_end(vac); + + GP_VPrint(ctx, NULL, x, y, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, + white_pixel, black_pixel, fmt, va); + + va_end(va); +} + +static void show_info(struct loader_params *params, GP_Context *img, + GP_Context *orig_img) +{ + GP_Context *context = backend->context; + const char *img_path = image_loader_img_path(); + + set_caption(img_path, params->rat); + + if (!params->show_info) + return; + + GP_Size th = GP_TextHeight(NULL); + + info_printf(context, 10, 10, "%ux%u (%ux%u) 1:%3.3f", + img->w, img->h, orig_img->w, orig_img->h, params->rat); + + info_printf(context, 10, 12 + th, "%s", img_name(img_path)); + + info_printf(context, 10, 14 + 2 * th, "%s%s", + params->use_low_pass && params->rat < 1 ? "Gaussian LP + " : "", + GP_InterpolationTypeName(params->resampling_method)); + + unsigned int count = image_loader_count(); + unsigned int pos = image_loader_pos() + 1; + + info_printf(context, 10, 16 + 3 * th, "%u of %u", pos, count); + + if (!image_loader_is_in_dir()) + return; + + unsigned int dir_count = image_loader_dir_count(); + unsigned int dir_pos = image_loader_dir_pos() + 1; + + info_printf(context, 10, 18 + 4 * th, + "%u of %u in directory", dir_pos, dir_count); +} + static void update_display(struct loader_params *params, GP_Context *img, GP_Context *orig_img) { @@ -279,7 +314,7 @@ static void update_display(struct loader_params *params, GP_Context *img, struct cpu_timer timer; GP_ProgressCallback callback = {.callback = image_loader_callback};
- switch (params->rotate) { + switch (params->orientation) { case 0: break; case 90: @@ -347,61 +382,9 @@ static void update_display(struct loader_params *params, GP_Context *img, if (h > 0) GP_FillRectXYWH(context, 0, img->h + cy, context->w, h, black_pixel);
- const char *img_path = image_loader_img_path(); - - set_caption(img_path, params->rat); - - if (!params->show_info) - goto out; - - GP_Size th = GP_TextHeight(NULL); - - GP_Print(context, NULL, 11, 11, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - black_pixel, white_pixel, "%ux%u (%ux%u) 1:%3.3f", - img->w, img->h, orig_img->w, orig_img->h, params->rat); - - GP_Print(context, NULL, 10, 10, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - white_pixel, black_pixel, "%ux%u (%ux%u) 1:%3.3f", - img->w, img->h, orig_img->w, orig_img->h, params->rat); - - GP_Print(context, NULL, 11, 13 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - black_pixel, white_pixel, "%s", img_name(img_path)); - - GP_Print(context, NULL, 10, 12 + th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - white_pixel, black_pixel, "%s", img_name(img_path)); - - GP_Print(context, NULL, 11, 13 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - black_pixel, white_pixel, "%s%s", - params->use_low_pass && params->rat < 1 ? "Gaussian LP + " : "", - GP_InterpolationTypeName(params->resampling_method)); - - GP_Print(context, NULL, 10, 14 + 2 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - white_pixel, black_pixel, "%s%s", - params->use_low_pass && params->rat < 1 ? "Gaussian LP + " : "", - GP_InterpolationTypeName(params->resampling_method)); - - unsigned int count = image_loader_count(); - unsigned int pos = image_loader_pos() + 1; - - GP_Print(context, NULL, 11, 17 + 3 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - black_pixel, white_pixel, "%u of %u", pos, count); - - GP_Print(context, NULL, 10, 16 + 3 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - white_pixel, black_pixel, "%u of %u", pos, count); - - if (!image_loader_is_in_dir()) - goto out; - - unsigned int dir_count = image_loader_dir_count(); - unsigned int dir_pos = image_loader_dir_pos() + 1; - - GP_Print(context, NULL, 11, 19 + 4 * th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - black_pixel, white_pixel, "%u of %u in directory", dir_pos, dir_count); + show_info(params, img, orig_img);
- GP_Print(context, NULL, 10, 18 + 4* th, GP_ALIGN_RIGHT|GP_VALIGN_BOTTOM, - white_pixel, black_pixel, "%u of %u in directory", dir_pos, dir_count); -out: - if (params->rotate) + if (params->orientation) GP_ContextFree(img);
GP_BackendFlip(backend); @@ -457,13 +440,7 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size cpu_timer_start(&timer, "Resampling"); callback.priv = "Resampling Image"; GP_Context *i1 = GP_FilterResizeAlloc(img, w, h, params->resampling_method, &callback); -// img->gamma = NULL; -// GP_Context *i2 = GP_FilterResizeAlloc(img, w, h, params->resampling_method, &callback); -// img = GP_FilterDifferenceAlloc(i2, i1, NULL); -// img = GP_FilterInvert(img, NULL, NULL); img = i1; -// if (params->resampling_method == GP_INTERP_CUBIC_INT) -// GP_FilterEdgeSharpening(img, img, 0.2, NULL); cpu_timer_stop(&timer);
/* @@ -488,50 +465,73 @@ GP_Context *load_resized_image(struct loader_params *params, GP_Size w, GP_Size return img; }
-static void *image_loader(void *ptr) +static float calc_img_size(struct loader_params *params, + uint32_t img_w, uint32_t img_h, + uint32_t src_w, uint32_t src_h) { - struct loader_params *params = ptr; - struct cpu_timer sum_timer; - GP_Context *img, *orig_img, *context = backend->context; - - cpu_timer_start(&sum_timer, "sum"); - - show_progress = params->show_progress || params->show_progress_once; - params->show_progress_once = 0; - - /* Figure out rotation */ - GP_Size w, h; + float w_rat; + float h_rat;
- switch (params->rotate) { + switch (params->orientation) { case 0: case 180: default: - w = context->w; - h = context->h; break; case 90: case 270: - w = context->h; - h = context->w; + GP_SWAP(src_w, src_h); break; }
+ switch (params->zoom_type) { + case ZOOM_FIT_DOWNSCALE: + if (img_w <= src_w && img_h <= src_h) + return 1.00; + case ZOOM_FIT: + w_rat = 1.00 * src_w / img_w; + h_rat = 1.00 * src_h / img_h; + return GP_MIN(w_rat, h_rat); + case ZOOM_FIXED: + return params->zoom; + case ZOOM_FIXED_WIN: + resize_backend(params->zoom, 0); + return params->zoom; + } + + return 1.00; +} + +static void *image_loader(void *ptr) +{ + struct loader_params *params = ptr; + struct cpu_timer sum_timer; + GP_Context *img, *orig_img, *context = backend->context; + + cpu_timer_start(&sum_timer, "sum"); + + show_progress = params->show_progress || params->show_progress_once; + params->show_progress_once = 0; + if ((orig_img = load_image(0)) == NULL) { loader_running = 0; return NULL; }
- params->rat = calc_img_size(params, orig_img->w, orig_img->h, w, h); + /* Figure out rotation */ + GP_Size w, h; + + params->rat = calc_img_size(params, orig_img->w, orig_img->h, + context->w, context->h); + + w = orig_img->w * params->rat + 0.5; + h = orig_img->h * params->rat + 0.5;
/* Special case => no need to resize */ - if (params->rat == 1.0) { + if (w == orig_img->w && h == orig_img->h) { img = orig_img; goto update; }
- w = orig_img->w * params->rat + 0.5; - h = orig_img->h * params->rat + 0.5; - img = load_resized_image(params, w, h);
if (img == NULL) { @@ -539,7 +539,6 @@ static void *image_loader(void *ptr) return NULL; }
- //image_cache_print(params->img_resized_cache); update: update_display(params, img, orig_img); cpu_timer_stop(&sum_timer); @@ -691,7 +690,7 @@ int main(int argc, char *argv[]) .show_info = 0, .show_nn_first = 0, .use_dithering = 0, - .rotate = 0, + .orientation = 0, .resampling_method = GP_INTERP_LINEAR_LF_INT,
.zoom_type = ZOOM_FIT, @@ -735,11 +734,11 @@ int main(int argc, char *argv[]) break; case 'r': if (!strcmp(optarg, "90")) - params.rotate = 90; + params.orientation = 90; else if (!strcmp(optarg, "180")) - params.rotate = 180; + params.orientation = 180; else if (!strcmp(optarg, "270")) - params.rotate = 270; + params.orientation = 270; case 'b': backend_opts = optarg; break; @@ -859,9 +858,9 @@ int main(int argc, char *argv[]) params.show_progress = !params.show_progress; break; case GP_KEY_R: - params.rotate += 90; - if (params.rotate > 270) - params.rotate = 0; + params.orientation += 90; + if (params.orientation > 270) + params.orientation = 0;
params.show_progress_once = 1; show_image(¶ms);
http://repo.or.cz/w/gfxprim.git/commit/e66493630e62bac979731f58c0232c14c1f69...
commit e66493630e62bac979731f58c0232c14c1f699d9 Author: Cyril Hrubis metan@ucw.cz Date: Thu Oct 10 15:02:05 2013 +0200
text: Add va_list variant for GP_Print()
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/doc/text_api.txt b/doc/text_api.txt index 1a77a7d..46f93f3 100644 --- a/doc/text_api.txt +++ b/doc/text_api.txt @@ -35,6 +35,11 @@ void GP_Text(GP_Context *context, const GP_TextStyle *style, GP_Size GP_Print(GP_Context *context, const GP_TextStyle *style, GP_Coord x, GP_Coord y, int align, GP_Pixel fg_color, GP_Pixel bg_color, const char *fmt, ...); + +GP_Size GP_VPrint(GP_Context *context, const GP_TextStyle *style, + GP_Coord x, GP_Coord y, int align, + GP_Pixel fg_color, GP_Pixel bg_color, + const char *fmt, va_list va); --------------------------------------------------------------------------------
Draws text at the position x and y; the alignment of the text in relation diff --git a/include/text/GP_Text.h b/include/text/GP_Text.h index 6834417..30176d0 100644 --- a/include/text/GP_Text.h +++ b/include/text/GP_Text.h @@ -26,6 +26,8 @@ #ifndef TEXT_GP_TEXT_H #define TEXT_GP_TEXT_H
+#include <stdarg.h> + #include "core/GP_Context.h"
#include "text/GP_TextStyle.h" @@ -91,6 +93,10 @@ GP_Size GP_Print(GP_Context *context, const GP_TextStyle *style, GP_Pixel fg_color, GP_Pixel bg_color, const char *fmt, ...) __attribute__ ((format (printf, 8, 9)));
+GP_Size GP_VPrint(GP_Context *context, const GP_TextStyle *style, + GP_Coord x, GP_Coord y, int align, + GP_Pixel fg_color, GP_Pixel bg_color, + const char *fmt, va_list va); /* * Clears rectangle that would be used to draw text of size pixels. */ diff --git a/libs/text/GP_Text.c b/libs/text/GP_Text.c index 8a712ec..07df462 100644 --- a/libs/text/GP_Text.c +++ b/libs/text/GP_Text.c @@ -19,11 +19,10 @@ * Copyright (C) 2009-2011 Jiri "BlueBear" Dluhos * * jiri.bluebear.dluhos@gmail.com * * * - * Copyright (C) 2009-2011 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
-#include <stdarg.h> #include "gfx/GP_Gfx.h" #include "core/GP_FnPerBpp.h" #include "core/GP_Debug.h" @@ -96,18 +95,16 @@ void GP_Text(GP_Context *context, const GP_TextStyle *style, align & GP_TEXT_NOBG, fg_color, bg_color, str); }
- -GP_Size GP_Print(GP_Context *context, const GP_TextStyle *style, - GP_Coord x, GP_Coord y, int align, - GP_Pixel fg_color, GP_Pixel bg_color, const char *fmt, ...) +GP_Size GP_VPrint(GP_Context *context, const GP_TextStyle *style, + GP_Coord x, GP_Coord y, int align, + GP_Pixel fg_color, GP_Pixel bg_color, + const char *fmt, va_list va) { - va_list va, vac; + va_list vac; int size;
- va_start(va, fmt); va_copy(vac, va); size = vsnprintf(NULL, 0, fmt, va); - va_end(va); char buf[size+1]; vsnprintf(buf, sizeof(buf), fmt, vac); va_end(vac); @@ -117,6 +114,20 @@ GP_Size GP_Print(GP_Context *context, const GP_TextStyle *style, return GP_TextWidth(style, buf); }
+GP_Size GP_Print(GP_Context *context, const GP_TextStyle *style, + GP_Coord x, GP_Coord y, int align, + GP_Pixel fg_color, GP_Pixel bg_color, const char *fmt, ...) +{ + va_list va; + GP_Size ret; + + va_start(va, fmt); + ret = GP_VPrint(context, style, x, y, align, + fg_color, bg_color, fmt, va); + va_end(va); + + return ret; +}
void GP_TextClear(GP_Context *context, const GP_TextStyle *style, GP_Coord x, GP_Coord y, int align,
http://repo.or.cz/w/gfxprim.git/commit/d12cf1d15e383df010846ee3a53a36cc7ac64...
commit d12cf1d15e383df010846ee3a53a36cc7ac64724 Author: Cyril Hrubis metan@ucw.cz Date: Tue Oct 8 13:57:09 2013 +0200
filters: GaussianNoise: Set errno.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/libs/filters/GP_GaussianNoise.gen.c.t b/libs/filters/GP_GaussianNoise.gen.c.t index 2ec5a92..939533b 100644 --- a/libs/filters/GP_GaussianNoise.gen.c.t +++ b/libs/filters/GP_GaussianNoise.gen.c.t @@ -87,6 +87,7 @@ static int GP_FilterGaussianNoiseAdd_{{ pt.name }}_Raw(const GP_Context *src,
if (GP_ProgressCallbackReport(callback, y, h_src, w_src)) { GP_TempAllocFree(temp); + errno = ECANCELED; return 1; } } @@ -153,7 +154,7 @@ GP_Context *GP_FilterGaussianNoiseAddExAlloc(const GP_Context *src, float sigma, float mu, GP_ProgressCallback *callback) { - int ret; + int ret, err;
GP_Context *dst = GP_ContextAlloc(w_src, h_src, src->pixel_type);
@@ -164,7 +165,9 @@ GP_Context *GP_FilterGaussianNoiseAddExAlloc(const GP_Context *src, dst, 0, 0, sigma, mu, callback);
if (ret) { + err = errno; GP_ContextFree(dst); + errno = err; return NULL; }
http://repo.or.cz/w/gfxprim.git/commit/6c19433d1a062473a6bdc2a21b67168d3cec0...
commit 6c19433d1a062473a6bdc2a21b67168d3cec04fd Author: Cyril Hrubis metan@ucw.cz Date: Tue Oct 8 13:48:22 2013 +0200
backends: X11: Avoid warning on GravityNotify
Avoid useless warning on GravityNotify event.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/libs/backends/GP_InputDriverX11.c b/libs/backends/GP_InputDriverX11.c index fc6149f..a271360 100644 --- a/libs/backends/GP_InputDriverX11.c +++ b/libs/backends/GP_InputDriverX11.c @@ -292,6 +292,9 @@ void GP_InputDriverX11EventPut(struct GP_EventQueue *event_queue, case ReparentNotify: GP_DEBUG(1, "ReparentNotify event received"); break; + case GravityNotify: + GP_DEBUG(1, "GravityNotify event received"); + break; default: GP_WARN("Unhandled X11 event type %u", ev->type); }
http://repo.or.cz/w/gfxprim.git/commit/15db0fc3351d6a78f3f654defde550aaf8813...
commit 15db0fc3351d6a78f3f654defde550aaf8813a7d Author: Cyril Hrubis metan@ucw.cz Date: Tue Oct 8 13:34:26 2013 +0200
tests: filters: Fix filters compare.
Some of the filters cannot run in-place, fix it by passing src as the first arg.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/tests/filters/FiltersCompare.gen.c.t b/tests/filters/FiltersCompare.gen.c.t index 5ee38c6..d22890b 100644 --- a/tests/filters/FiltersCompare.gen.c.t +++ b/tests/filters/FiltersCompare.gen.c.t @@ -60,21 +60,17 @@ All results from filters listed under one name are compared. ['SymmetryAlloc', ['src', 'GP_MIRROR_V', 'NULL']], ], ['Rotate90', - ['Rotate90', ['dst', 'dst', 'NULL']], ['Rotate90Alloc', ['src', 'NULL']], - ['Symmetry', ['dst', 'dst', 'GP_ROTATE_90', 'NULL']], ['SymmetryAlloc', ['src', 'GP_ROTATE_90', 'NULL']], ], ['Rotate180', - ['Rotate180', ['dst', 'dst', 'NULL']], + ['Rotate180', ['src', 'dst', 'NULL']], ['Rotate180Alloc', ['src', 'NULL']], - ['Symmetry', ['dst', 'dst', 'GP_ROTATE_180', 'NULL']], + ['Symmetry', ['src', 'dst', 'GP_ROTATE_180', 'NULL']], ['SymmetryAlloc', ['src', 'GP_ROTATE_180', 'NULL']], ], ['Rotate270', - ['Rotate270', ['dst', 'dst', 'NULL']], ['Rotate270Alloc', ['src', 'NULL']], - ['Symmetry', ['dst', 'dst', 'GP_ROTATE_270', 'NULL']], ['SymmetryAlloc', ['src', 'GP_ROTATE_270', 'NULL']], ],
@@ -105,16 +101,16 @@ All results from filters listed under one name are compared. ],
['Laplace', - ['Laplace', ['dst', 'dst', 'NULL']], + ['Laplace', ['src', 'dst', 'NULL']], ['LaplaceAlloc', ['src', 'NULL']], ], ['EdgeSharpening', - ['EdgeSharpening', ['dst', 'dst', '0.2', 'NULL']], + ['EdgeSharpening', ['src', 'dst', '0.2', 'NULL']], ['EdgeSharpeningAlloc', ['src', '0.2', 'NULL']], ],
['Median', - ['Median', ['dst', 'dst', '3', '2', 'NULL']], + ['Median', ['src', 'dst', '3', '2', 'NULL']], ['MedianAlloc', ['src', '3', '2', 'NULL']], ],
http://repo.or.cz/w/gfxprim.git/commit/5adcb7f068d9c8814fc1abecea76de442a326...
commit 5adcb7f068d9c8814fc1abecea76de442a3267bc Author: Cyril Hrubis metan@ucw.cz Date: Mon Oct 7 18:59:19 2013 +0200
filters: ResizeCubicInt: Set errno.
Set errno on invalid pixel types.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/libs/filters/GP_ResizeCubic.gen.c.t b/libs/filters/GP_ResizeCubic.gen.c.t index 9120fa7..ae84901 100644 --- a/libs/filters/GP_ResizeCubic.gen.c.t +++ b/libs/filters/GP_ResizeCubic.gen.c.t @@ -210,6 +210,7 @@ static int resize_cubic(const GP_Context *src, GP_Context *dst, %% endif %% endfor default: + errno = EINVAL; return -1; } }
http://repo.or.cz/w/gfxprim.git/commit/8dba9bc6f1f94b008a6f4475d0af9d1e8c810...
commit 8dba9bc6f1f94b008a6f4475d0af9d1e8c810f36 Author: Cyril Hrubis metan@ucw.cz Date: Mon Oct 7 18:52:36 2013 +0200
filters: GaussianNoise: Set errno.
Set errno to EINVAL on unsupported pixel types (palette).
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/libs/filters/GP_GaussianNoise.gen.c.t b/libs/filters/GP_GaussianNoise.gen.c.t index 3e4764b..2ec5a92 100644 --- a/libs/filters/GP_GaussianNoise.gen.c.t +++ b/libs/filters/GP_GaussianNoise.gen.c.t @@ -26,6 +26,8 @@
%% block body
+#include <errno.h> + #include "core/GP_Context.h" #include "core/GP_GetPutPixel.h" #include "core/GP_TempAlloc.h" @@ -117,6 +119,7 @@ int GP_FilterGaussianNoiseAdd_Raw(const GP_Context *src, %% endif %% endfor default: + errno = EINVAL; return -1; } }
-----------------------------------------------------------------------
Summary of changes: demos/spiv/Makefile | 2 +- demos/spiv/cfg.c | 525 ++++++++++++++++++++ include/loaders/GP_JP2.h => demos/spiv/cfg.h | 52 ++- demos/spiv/spiv.c | 367 ++++++-------- demos/spiv/spiv_config.c | 348 +++++++++++++ .../pretty_print.c => spiv/spiv_config.h} | 41 +- demos/spiv/spiv_help.c | 288 ++++++++---- doc/general.txt | 4 +- doc/text_api.txt | 5 + include/text/GP_Text.h | 6 + libs/backends/GP_InputDriverX11.c | 3 + libs/filters/GP_GaussianNoise.gen.c.t | 8 +- libs/filters/GP_ResizeCubic.gen.c.t | 1 + libs/text/GP_Text.c | 29 +- tests/filters/FiltersCompare.gen.c.t | 14 +- 15 files changed, 1344 insertions(+), 349 deletions(-) create mode 100644 demos/spiv/cfg.c copy include/loaders/GP_JP2.h => demos/spiv/cfg.h (56%) create mode 100644 demos/spiv/spiv_config.c copy demos/{c_simple/pretty_print.c => spiv/spiv_config.h} (75%)
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.