aboutsummaryrefslogtreecommitdiff
path: root/view.c
blob: af237c9427d09b108a05b316779abbf42bf5faca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <stdlib.h>
#include <math.h>
#include <unistd.h>

#include <glib.h>
#include <gio/gio.h>
#include <gio/gunixinputstream.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk-pixbuf/gdk-pixdata.h>

// TODO Unhardcode these
const int char_width = 8;
const int char_height = 15;

const int window_width = 8 * 80;
const int window_height = 15 * 25;

static gboolean view_pixbuf(GdkPixbuf *pixbuf)
{
	gint width = gdk_pixbuf_get_width(pixbuf);
	gint height = gdk_pixbuf_get_height(pixbuf);	

	double scale = 1.0;
	if (width > window_width) {
		scale *= (double)window_width / width;
		width = width * scale;
		height = height * scale;
	}
	if (height > window_height || FALSE) {
		scale *= (double)window_height / height;
		width = width * scale;
		height = height * scale;
	}

	GdkPixbuf *scaled;

	if (scale != 1.0) {
		scaled = gdk_pixbuf_scale_simple(pixbuf, width, height, GDK_INTERP_BILINEAR);
	} else {
		scaled = GDK_PIXBUF(g_object_ref(pixbuf));
	}

	GdkPixdata pixdata;
	gpointer pixdata_p = gdk_pixdata_from_pixbuf(&pixdata, scaled, TRUE);

	if (pixdata_p == NULL) {
		g_object_unref(scaled);
		return FALSE;
	}

	guint size;
	guint8 *data = gdk_pixdata_serialize(&pixdata, &size);
	gchar *str = g_base64_encode(data, size);

	g_print("\033]v;%s\007", str);

	int rows = ceil(height / (double)char_height);
	while (rows > 0) {
		g_print("\n");
		rows--;
	}
	
	g_free(str);
	g_free(data);
	g_free(pixdata.pixel_data);
	g_object_unref(scaled);

	return TRUE;
}


int main(int argc, char * argv[])
{
	g_type_init();

	GError *error = NULL;

	if (!isatty(STDOUT_FILENO)) {
		g_printerr("Refusing to display image on not-terminal\n");
		return EXIT_FAILURE;
	}

	if (argc > 1) {
		int i;
		for (i = 1; i < argc; i++) {
			GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(argv[i], &error);
			if (pixbuf == NULL) {
				g_printerr("Failed to open image '%s': %s\n", argv[i], error->message);
				return EXIT_FAILURE;
			}
			if (!view_pixbuf(pixbuf)) {
				g_printerr("Failed to view image '%s'\n", argv[i]);
				return EXIT_FAILURE;
			}
			g_object_unref(pixbuf);
		}
	} else {
		GInputStream *input = g_unix_input_stream_new(STDIN_FILENO, FALSE);
		GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(input, NULL, &error);
		if (pixbuf == NULL) {
			g_printerr("Failed to open stdin image: %s\n", error->message);
			return EXIT_FAILURE;
		}
		if (!view_pixbuf(pixbuf)) {
			g_printerr("Failed to view stdin image\n");
			return EXIT_FAILURE;
		}
		g_object_unref(pixbuf);
	}

	return EXIT_SUCCESS;
}