aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/imv.124
-rw-r--r--src/loader.c57
-rw-r--r--src/loader.h6
-rw-r--r--src/main.c68
-rw-r--r--src/util.c29
-rw-r--r--src/util.h3
6 files changed, 150 insertions, 37 deletions
diff --git a/doc/imv.1 b/doc/imv.1
index cbd5c68..d883611 100644
--- a/doc/imv.1
+++ b/doc/imv.1
@@ -21,12 +21,8 @@ It supports a wide variety of image file formats, including animated gif files.
.Nm
reloads the current image if it detects changes to the file.
.Pp
-When run with argument
-.Sq - ,
.Nm
-reads the list of images from standard input.
-.Pp
-The options are as follows:
+accepts following flags:
.Bl -tag -width Ds
.It Fl a
Default to showing images at actual size.
@@ -66,6 +62,17 @@ Setting this to zero disables slideshow mode, which is the default.
.It Fl u
Use nearest neighbour resampling. Recommended for pixel art.
.El
+.Ss Reading from standard input
+When run with argument
+.Sq - ,
+.Nm
+reads image from standard input.
+Argument
+.Sq -
+may occur among other arguments, but only once.
+.Pp
+If no arguments supplied, reads list of files from standard input.
+.Pp
.Sh CONTROLS
.Bl -tag -width Ds
.It Aq Cm left mouse button
@@ -111,6 +118,13 @@ Increase slideshow delay by one second
.It Cm T
Decrease slideshow delay by one second.
When delay is zero, slideshow mode is disabled.
+.Sh EXAMPLES
+Load all files from directory
+.Pa dir :
+.Pp
+.Dl $ ls dir | imv
+or
+.Dl $ ls dir | xargs imv
.Sh LEGAL
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/src/loader.c b/src/loader.c
index 71c0e84..1250289 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -17,6 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "loader.h"
#include "texture.h"
+#include <limits.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
@@ -67,7 +68,8 @@ void imv_destroy_loader(struct imv_loader *ldr)
}
}
-void imv_loader_load_path(struct imv_loader *ldr, const char *path)
+void imv_loader_load(struct imv_loader *ldr, const char *path,
+ const void *buffer, const size_t buffer_size)
{
/* cancel existing thread if already running */
if(ldr->bg_thread) {
@@ -80,6 +82,12 @@ void imv_loader_load_path(struct imv_loader *ldr, const char *path)
free(ldr->path);
}
ldr->path = strdup(path);
+ if (strncmp(path, "-", 2) == 0) {
+ ldr->buffer = (BYTE *)buffer;
+ ldr->buffer_size = buffer_size;
+ } else if (ldr->fi_buffer != NULL) {
+ FreeImage_CloseMemory(ldr->fi_buffer);
+ }
pthread_create(&ldr->bg_thread, NULL, &bg_new_img, ldr);
pthread_mutex_unlock(&ldr->lock);
}
@@ -149,16 +157,31 @@ static void *bg_new_img(void *data)
block_usr1_signal();
struct imv_loader *ldr = data;
+ char path[PATH_MAX] = "-";
pthread_mutex_lock(&ldr->lock);
- char *path = strdup(ldr->path);
+ int from_stdin = !strncmp(path, ldr->path, 2);
+ if(!from_stdin) {
+ (void)snprintf(path, PATH_MAX, "%s", ldr->path);
+ }
pthread_mutex_unlock(&ldr->lock);
- FREE_IMAGE_FORMAT fmt = FreeImage_GetFileType(path, 0);
-
+ FREE_IMAGE_FORMAT fmt;
+ if (from_stdin) {
+ pthread_mutex_lock(&ldr->lock);
+ ldr->fi_buffer = FreeImage_OpenMemory(ldr->buffer, ldr->buffer_size);
+ fmt = FreeImage_GetFileTypeFromMemory(ldr->fi_buffer, 0);
+ pthread_mutex_unlock(&ldr->lock);
+ } else {
+ fmt = FreeImage_GetFileType(path, 0);
+ }
if(fmt == FIF_UNKNOWN) {
+ if (from_stdin) {
+ pthread_mutex_lock(&ldr->lock);
+ FreeImage_CloseMemory(ldr->fi_buffer);
+ pthread_mutex_unlock(&ldr->lock);
+ }
error_occurred(ldr);
- free(path);
return NULL;
}
@@ -169,12 +192,18 @@ static void *bg_new_img(void *data)
int raw_frame_time = 100; /* default to 100 */
if(fmt == FIF_GIF) {
- mbmp = FreeImage_OpenMultiBitmap(FIF_GIF, path,
+ if(from_stdin) {
+ pthread_mutex_lock(&ldr->lock);
+ mbmp = FreeImage_LoadMultiBitmapFromMemory(FIF_GIF, ldr->fi_buffer,
+ GIF_LOAD256);
+ pthread_mutex_unlock(&ldr->lock);
+ } else {
+ mbmp = FreeImage_OpenMultiBitmap(FIF_GIF, path,
/* don't create file */ 0,
/* read only */ 1,
/* keep in memory */ 1,
/* flags */ GIF_LOAD256);
- free(path);
+ }
if(!mbmp) {
error_occurred(ldr);
return NULL;
@@ -198,10 +227,20 @@ static void *bg_new_img(void *data)
} else {
/* Future TODO: If we load image line-by-line we could stop loading large
* ones before wasting much more time/memory on them. */
- FIBITMAP *image = FreeImage_Load(fmt, path, 0);
- free(path);
+ FIBITMAP *image;
+ if(from_stdin) {
+ pthread_mutex_lock(&ldr->lock);
+ image = FreeImage_LoadFromMemory(fmt, ldr->fi_buffer, 0);
+ pthread_mutex_unlock(&ldr->lock);
+ } else {
+ image = FreeImage_Load(fmt, path, 0);
+ }
if(!image) {
error_occurred(ldr);
+ pthread_mutex_lock(&ldr->lock);
+ FreeImage_CloseMemory(ldr->fi_buffer);
+ ldr->fi_buffer = NULL;
+ pthread_mutex_unlock(&ldr->lock);
return NULL;
}
diff --git a/src/loader.h b/src/loader.h
index 65c8689..6e20349 100644
--- a/src/loader.h
+++ b/src/loader.h
@@ -28,6 +28,9 @@ struct imv_loader {
pthread_mutex_t lock;
pthread_t bg_thread;
char *path;
+ BYTE *buffer;
+ size_t buffer_size;
+ FIMEMORY *fi_buffer;
FIBITMAP *out_bmp;
int out_is_new_image;
char *out_err;
@@ -48,7 +51,8 @@ void imv_init_loader(struct imv_loader *img);
void imv_destroy_loader(struct imv_loader *img);
/* Asynchronously load the given file */
-void imv_loader_load_path(struct imv_loader *ldr, const char *path);
+void imv_loader_load(struct imv_loader *ldr, const char *path,
+ const void *buffer, const size_t buffer_size);
/* Returns 1 if image data is available. 0 if not. Caller is responsible for
* cleaning up the data returned. Each image is only returned once.
diff --git a/src/main.c b/src/main.c
index f3c197b..7ba55ec 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <FreeImage.h>
#include <getopt.h>
#include <ctype.h>
+#include <errno.h>
#include "loader.h"
#include "texture.h"
@@ -33,7 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
struct {
int fullscreen;
- int sin;
+ int stdin_list;
int recursive;
int actual;
int nearest_neighbour;
@@ -49,7 +50,7 @@ struct {
const char *font;
} g_options = {
.fullscreen = 0,
- .sin = 0,
+ .stdin_list = 0,
.recursive = 0,
.actual = 0,
.nearest_neighbour = 0,
@@ -72,7 +73,7 @@ static void print_usage(const char* name)
"Usage: %s [-rfaudlh] [-n <NUM|PATH>] [-b BG] [-e FONT:SIZE] [-t SECONDS] [-] [images...]\n"
"\n"
"Flags:\n"
- " -: Read paths from stdin. One path per line.\n"
+ " -: Read image from stdin. One path per line.\n"
" -r: Recursively search input paths.\n"
" -f: Start in fullscreen mode\n"
" -a: Default to images' actual size\n"
@@ -137,8 +138,8 @@ static void parse_args(int argc, char** argv)
switch(o) {
case 'f': g_options.fullscreen = 1; break;
case 'i':
- g_options.sin = 1;
- fprintf(stderr, "Warning: '-i' is deprecated. Just use '-' instead.\n");
+ g_options.stdin_list = 1;
+ fprintf(stderr, "Warning: '-i' is deprecated. No flag is needed.\n");
break;
case 'r': g_options.recursive = 1; break;
case 'a': g_options.actual = 1; break;
@@ -193,30 +194,22 @@ static void parse_args(int argc, char** argv)
int main(int argc, char** argv)
{
- if(argc < 2) {
- print_usage(argv[0]);
- exit(1);
- }
-
struct imv_navigator nav;
imv_navigator_init(&nav);
/* parse any command line options given */
parse_args(argc, argv);
- /* handle any image paths given as arguments */
- for(int i = optind; i < argc; ++i) {
- /* special case: '-' is actually an option */
- if(!strcmp("-",argv[i])) {
- g_options.sin = 1;
- continue;
- }
- /* add the given path to the list to load */
- imv_navigator_add(&nav, argv[i], g_options.recursive);
+ argc -= optind;
+ argv += optind;
+
+ /* if no names are given, expect them on stdin */
+ if(argc == 0) {
+ g_options.stdin_list = 1;
}
/* if the user asked us to load paths from stdin, now is the time */
- if(g_options.sin) {
+ if(g_options.stdin_list) {
char buf[PATH_MAX];
while(fgets(buf, sizeof(buf), stdin)) {
size_t len = strlen(buf);
@@ -229,6 +222,30 @@ int main(int argc, char** argv)
}
}
+ void *stdin_buffer = NULL;
+ size_t stdin_buffer_size = 0;
+ int stdin_error = 0;
+
+ /* handle any image paths given as arguments */
+ for(int i = 0; i < argc; ++i) {
+ /* special case: '-' is actually an option */
+ if(!strcmp("-",argv[i])) {
+ if (stdin_buffer) {
+ fprintf(stderr, "Can't read from stdin twice\n");
+ exit(1);
+ }
+ stdin_buffer_size = read_from_stdin(&stdin_buffer);
+ if (stdin_buffer_size == 0) {
+ perror(NULL);
+ continue; /* we can't recover from the freed buffer, just ignore it */
+ }
+ stdin_error = errno;
+ errno = 0; /* clear errno */
+ }
+ /* add the given path to the list to load */
+ imv_navigator_add(&nav, argv[i], g_options.recursive);
+ }
+
/* if we weren't given any paths we have nothing to view. exit */
if(!imv_navigator_selection(&nav)) {
fprintf(stderr, "No input files. Exiting.\n");
@@ -435,6 +452,15 @@ int main(int argc, char** argv)
char *err_path = imv_loader_get_error(&ldr);
if(err_path) {
imv_navigator_remove(&nav, err_path);
+ if (strncmp(err_path, "-", 2) == 0) {
+ free(stdin_buffer);
+ stdin_buffer_size = 0;
+ if (stdin_error != 0) {
+ errno = stdin_error;
+ perror("Failed to load image from standard input");
+ errno = 0;
+ }
+ }
free(err_path);
}
@@ -451,7 +477,7 @@ int main(int argc, char** argv)
nav.cur_path + 1, nav.num_paths, current_path);
imv_viewport_set_title(&view, title);
- imv_loader_load_path(&ldr, current_path);
+ imv_loader_load(&ldr, current_path, stdin_buffer, stdin_buffer_size);
view.playing = 1;
}
diff --git a/src/util.c b/src/util.c
index dac23d4..0a15238 100644
--- a/src/util.c
+++ b/src/util.c
@@ -16,9 +16,36 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "util.h"
-
+#include <unistd.h>
+#include <stddef.h>
+#include <errno.h>
#include <fontconfig/fontconfig.h>
+size_t read_from_stdin(void **buffer) {
+ size_t len = 0;
+ ssize_t r;
+ size_t step = 1024; /* Arbitrary value of 1 KiB */
+ void *p;
+
+ errno = 0; /* clear errno */
+
+ for(*buffer = NULL; (*buffer = realloc((p = *buffer), len + step));
+ len += (size_t)r) {
+ if((r = read(STDIN_FILENO, (uint8_t *)*buffer + len, step)) <= 0) {
+ break;
+ }
+ }
+
+ /* realloc(3) leaves old buffer allocated in case of error */
+ if(*buffer == NULL && p != NULL) {
+ int save = errno;
+ free(p);
+ errno = save;
+ len = 0;
+ }
+ return len;
+}
+
TTF_Font *load_font(const char *font_spec)
{
int font_size;
diff --git a/src/util.h b/src/util.h
index 3625a6c..09d5554 100644
--- a/src/util.h
+++ b/src/util.h
@@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
+/* Read binary data from stdin into buffer */
+size_t read_from_stdin(void **buffer);
+
/* Creates a new SDL_Texture* containing a chequeboard texture */
SDL_Texture *create_chequered(SDL_Renderer *renderer);