aboutsummaryrefslogtreecommitdiffstats
path: root/src/pnm.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/pnm.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/pnm.c b/src/pnm.c
new file mode 100644
index 0000000..da9dd3a
--- /dev/null
+++ b/src/pnm.c
@@ -0,0 +1,118 @@
+/**
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#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.
+ * @return Zero on success, -1 on error.
+ */
+int
+save_pnm (int fbfd, long width, long height, int imgfd)
+{
+ 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) < 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;
+}
+