diff options
-rwxr-xr-x | src/scrotty | 78 | ||||
-rw-r--r-- | src/scrotty.c | 187 |
2 files changed, 187 insertions, 78 deletions
diff --git a/src/scrotty b/src/scrotty deleted file mode 100755 index b334042..0000000 --- a/src/scrotty +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python3 -# -*- python -*- -''' -scrotty — Screenshot program for Linux's TTY -Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) - -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 Foundation, either version 3 of the License, or -(at your option) any later version. - -This program 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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -''' - -import os, sys - -fbno = 0 - -def write(string): - os.write(pipe_write, string.encode('utf-8')) - -while os.path.exists('/dev/fb%i' % fbno): - with open('/dev/fb%i' % fbno, 'rb') as file: - data = file.read() - - pathname = 'fb%i.png' % fbno - if os.path.exists(pathname): - i = 2 - while os.path.exists('%s.%i' % (pathname, i)): - i += 1 - pathname = '%s.%i' % (pathname, i) - - (pipe_read, pipe_write) = os.pipe() - pid = os.fork() - - if pid == 0: - os.close(pipe_write) - if pipe_read != 0: - os.close(0) - os.dup2(pipe_read, 0) - os.close(pipe_read) - os.execlp('convert', 'convert', '/dev/stdin', pathname) - - os.close(pipe_read) - - write('P3\n') - with open('/sys/class/graphics/fb%i/virtual_size' % fbno, 'rb') as file: - write(file.read().decode('utf-8', 'strict').replace(',', ' ')) - write('255\n') - - j = 0 - data_length = len(data) - for i in range(0, data_length, 4): - r, g, b = data[i + 2], data[i + 1], data[i + 0] - j += 1 - if (j == 5) or (i + 4 == data_length): - j = 0 - write('%i %i %i\n' % (r, g, b)) - else: - write('%i %i %i ' % (r, g, b)) - - os.close(pipe_write) - - reaped = 0 - while reaped != pid: - (reaped, status) = os.waitpid(pid, 0) - if status == 0: - print('Saved framebuffer %i to %s' % (fbno, pathname), file = sys.stderr) - else: - sys.exit(1) - fbno += 1 - diff --git a/src/scrotty.c b/src/scrotty.c new file mode 100644 index 0000000..6552abf --- /dev/null +++ b/src/scrotty.c @@ -0,0 +1,187 @@ +/** + * scrotty — Screenshot program for Linux's TTY + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * 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 Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif +#ifndef DEVDIR +# define DEVDIR "/dev" +#endif +#ifndef SYSDIR +# define SYSDIR "/sys" +#endif + + +#define LIST_0_9(P) P"0\n", P"1\n", P"2\n", P"3\n", P"4\n", P"5\n", P"6\n", P"7\n", P"8\n", P"9\n" +static const char* inttable[] = + { + LIST_0_9(""), LIST_0_9("1"), LIST_0_9("2"), LIST_0_9("3"), LIST_0_9("4"), + LIST_0_9("5"), LIST_0_9("6"), LIST_0_9("7"), LIST_0_9("8"), LIST_0_9("9"), + + LIST_0_9("10"), LIST_0_9("11"), LIST_0_9("12"), LIST_0_9("13"), LIST_0_9("14"), + LIST_0_9("15"), LIST_0_9("16"), LIST_0_9("17"), LIST_0_9("18"), LIST_0_9("19"), + + LIST_0_9("20"), LIST_0_9("21"), LIST_0_9("22"), LIST_0_9("23"), LIST_0_9("24"), + "250\n", "251\n", "252\n", "253\n", "254\n", "255\n" + }; + + +static int save_pnm(const char* fbpath, int fbno, int fd) +{ + char buf[PATH_MAX]; + FILE* file; + int saved_errno, sizefd, fbfd, r, g, b; + ssize_t got, off; + + sprintf(buf, SYSDIR "/class/graphics/fb%i/virtual_size", fbno); + if (sizefd = open(buf, O_RDONLY), sizefd < 0) + return -1; + + if (got = read(sizefd, buf, sizeof(buf) / sizeof(char) - 1), got < 0) + return saved_errno = errno, close(sizefd), errno = saved_errno, -1; + close(sizefd); + buf[got] = '\0'; + *strchr(buf, ',') = ' '; + + fbfd = open(fbpath, O_RDONLY); + if (fbfd < 0) + return -1; + + file = fdopen(fd, "w"); + if (file == NULL) + return saved_errno = errno, close(fbfd), errno = saved_errno, -1; + fprintf(file, "P3\n%s255\n", buf); + + for (off = 0;;) + { + got = read(fbfd, buf + off, sizeof(buf) - off * sizeof(char)); + if (got < 0) + return saved_errno = errno, fclose(file), close(fbfd), errno = saved_errno, -1; + if (got += off, got == 0) + break; + + for (off = 0; off < got; off += 4) + { + r = buf[off + 2] & 255; + g = buf[off + 1] & 255; + b = buf[off + 0] & 255; + fprintf(file, "%s%s%s", inttable[r], inttable[g], inttable[b]); + } + if (off != got) + { + off -= 4; + memcpy(buf, buf + off, (got - off) * sizeof(char)); + off = got - off; + } + else + off = 0; + } + + fflush(file); + fclose(file); + close(fbfd); + return 0; +} + + +static int save(const char* fbpath, const char* imgpath, int fbno, const char* execname) +{ + int pipe_rw[2]; + pid_t pid, reaped; + int saved_errno, status; + + if (pipe(pipe_rw) < 0) + return -1; + + if (pid = fork(), pid == -1) + return saved_errno = errno, close(pipe_rw[0]), close(pipe_rw[1]), errno = saved_errno, -1; + + if (pid == 0) + { + close(pipe_rw[1]); + if (pipe_rw[0] != STDIN_FILENO) + { + close(STDIN_FILENO); + dup2(pipe_rw[0], STDIN_FILENO); + close(pipe_rw[0]); + } + execlp("convert", "convert", DEVDIR "/stdin", imgpath, NULL); + perror(execname); + exit(1); + } + + close(pipe_rw[0]); + + if (save_pnm(fbpath, fbno, pipe_rw[1]) < 0) + return saved_errno = errno, close(pipe_rw[1]), errno = saved_errno, -1; + + close(pipe_rw[1]); + + reaped = 0; + while (reaped != pid) + { + reaped = waitpid(pid, &status, 0); + if (reaped < 0) + return -1; + } + + return status == 0 ? 0 : -1; +} + + +int main(int argc, char* argv[]) +{ + char fbpath[PATH_MAX]; + char imgpath[PATH_MAX]; + int i, fbno; + + (void) argc; + + for (fbno = 0;; fbno++) + { + sprintf(fbpath, DEVDIR "/fb%i", fbno); + if (access(fbpath, F_OK)) + break; + + sprintf(imgpath, "fb%i.png", fbno); + if (access(imgpath, F_OK) == 0) + for (i = 2;; i++) + { + sprintf(imgpath, "fb%i.png.%i", fbno, i); + if (access(imgpath, F_OK)) + break; + } + + if (save(fbpath, imgpath, fbno, *argv) < 0) + return perror(*argv), 1; + fprintf(stderr, "Saved framebuffer %i to %s\n", fbno, imgpath); + } + + return 0; +} + |