/** * scrotty — Screenshot program for Linux's TTY * * Copyright © 2014, 2015 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 . */ #include "common.h" #include "pnm.h" #include "kern.h" #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" /** * [0, 255]-integer-to-text convertion lookup table for faster conversion from * raw framebuffer data to the PNM format. The values have a whitespace at the * end for even faster conversion. * Lines should not be longer than 70 (although most programs will probably * work even if there are longer lines), therefore the selected whitespace * is LF (new line). * * ASCII has wider support than binary, and is create for version control, * especifially with one datum per line. */ 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" }; /** * Create an PNM file. * * @param fbfd The file descriptor connected to framebuffer device. * @param width The width of the image. * @param height The height of the image. * @param imgfd The file descriptor connected to conversion process's stdin. * @param data Additional data for `convert_fb_to_pnm` * and `convert_fb_to_png`. * @return Zero on success, -1 on error. */ int save_pnm (int fbfd, long width, long height, int imgfd, void *restrict data) { char buf[8 << 10]; FILE *file = NULL; ssize_t got, off; size_t adjustment; int saved_errno; /* Create a FILE *, for writing, for the image file. */ file = fdopen (imgfd, "w"); if (file == NULL) goto fail; /* The PNM image should begin with `P3\n%{width} %{height}\n%{colour max=255}\n`. ('\n' and ' ' can be exchanged at will.) */ if (fprintf (file, "P3\n%li %li\n255\n", width, height) < 0) goto fail; /* Convert raw framebuffer data into a PNM image. */ for (off = 0;;) { /* Read data from the framebuffer, we may have up to 3 bytes buffered. */ got = read (fbfd, buf + off, sizeof (buf) - (size_t)off * sizeof (char)); if (got < 0) goto fail; if (got == 0) break; got += off; /* Convert read pixels. */ if (convert_fb_to_pnm (file, buf, (size_t)got, &adjustment, data) < 0) goto fail; /* If we read a whole number of pixels, reset the buffer, otherwise, move the unconverted bytes to the beginning of the buffer. */ if (adjustment) { off -= (ssize_t)adjustment; memcpy (buf, buf + off, (size_t)(got - off) * sizeof (char)); off = got - off; } else off = 0; } /* Close file and return successfully. */ fflush (file); fclose (file); return 0; fail: saved_errno = errno; if (file != NULL) fclose (file); errno = saved_errno; return -1; }