aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/kern-linux.c91
-rw-r--r--src/kern.h5
-rw-r--r--src/png.c1
-rw-r--r--src/scrotty.c31
4 files changed, 72 insertions, 56 deletions
diff --git a/src/kern-linux.c b/src/kern-linux.c
index e6ca1a2..071d3fc 100644
--- a/src/kern-linux.c
+++ b/src/kern-linux.c
@@ -20,6 +20,9 @@
#include "kern.h"
#include "png.h"
+#include <sys/ioctl.h>
+#include <linux/fb.h>
+
/**
@@ -27,6 +30,14 @@
*/
const int alt_fbpath_limit = 2;
+struct data
+{
+ unsigned long start;
+ unsigned long end;
+ long hblank;
+ unsigned long position;
+};
+
/**
@@ -67,53 +78,49 @@ get_fbpath (int altpath, int fbno)
* Get the dimensions of a framebuffer.
*
* @param fbno The number of the framebuffer.
- * @param fbpath The path to the framebuffer device..
+ * @param fbfd File descriptor for framebuffer device.
* @param width Output parameter for the width of the image.
* @param height Output parameter for the height of the image.
* @parma data Additional data to pass to `convert_fb_to_png`.
* @return Zero on success, -1 on error.
*/
int
-measure (int fbno, char *restrict fbpath, long *restrict width,
- long *restrict height, void **restrict data)
+measure (int fbno, int fbfd, long *restrict width, long *restrict height, void **restrict data)
{
- static char buf[sizeof (SYSDIR "/class/graphics/fb/virtual_size") + 3 * sizeof(int)];
- /* The string "/class/graphics/fb/virtual_size" is large enought for the call (*) "*/
- char *delim;
- int sizefd = -1;
- ssize_t got;
- int saved_errno;
+ static struct data d;
+ struct fb_fix_screeninfo fixinfo;
+ struct fb_var_screeninfo varinfo;
+ unsigned long int linelength;
- /* Open the file with the framebuffer's dimensions. */
- sprintf (buf, "%s/class/graphics/fb%i/virtual_size", SYSDIR, fbno);
- sizefd = open (buf, O_RDONLY);
- if (sizefd == -1)
- FILE_FAILURE (buf);
+ if (ioctl (fbfd, FBIOGET_FSCREENINFO, &fixinfo))
+ goto fail;
- /* Get the dimensions of the framebuffer. */
- got = read (sizefd, buf, sizeof (buf) / sizeof (char) - 1); /* (*) */
- if (got < 0)
+ if (ioctl (fbfd, FBIOGET_VSCREENINFO, &varinfo))
goto fail;
- close (sizefd);
- /* The read content is formated as `%{width},%{height}\n`,
- convert it to `%{width}\0%{height}\0` and parse it. */
- buf[got] = '\0';
- delim = strchr (buf, ',');
- *delim++ = '\0';
- *width = atol (buf);
- *height = atol (delim);
+ *width = varinfo.xres;
+ *height = varinfo.yres;
- return 0;
+ if (varinfo.bits_per_pixel & 7)
+ {
+ fprintf(stderr, _("%s: Unsupported framebuffer configurations: "
+ "pixels are not encoded in whole bytes.\n"), execname);
+ exit(1);
+ }
+ linelength = fixinfo.line_length / (varinfo.bits_per_pixel / 8);
+ d.start = varinfo.yoffset * linelength;
+ d.start += varinfo.xoffset;
+ d.end = d.start + linelength * varinfo.yres;
+ d.hblank = linelength - *width;
+ d.position = 0;
+
+ /* TODO depth support */
+
+ *data = &d;
+ return 0;
fail:
- saved_errno = errno;
- if (sizefd >= 0)
- close (sizefd);
- errno = saved_errno;
return -1;
-
- (void) fbpath;
}
@@ -133,16 +140,19 @@ measure (int fbno, char *restrict fbpath, long *restrict width,
* @param data Data from `measure`.
* @return Zero on success, -1 on error.
*/
-int convert_fb_to_png (png_struct *pngbuf, png_byte *restrict pixbuf, const char *restrict buf,
- size_t n, long width3, size_t *restrict adjustment, long *restrict state,
- void *restrict data)
+int
+convert_fb_to_png (png_struct *pngbuf, png_byte *restrict pixbuf, const char *restrict buf, size_t n,
+ long width3, size_t *restrict adjustment, long *restrict state, void *restrict data)
{
const uint32_t *restrict pixel;
int r, g, b;
size_t off;
long x3 = *state;
+ struct data d = *(struct data *)data;
+ unsigned long pos = d.position;
+ long lineend = width3 + d.hblank * 3;
- for (off = 0; off < n; off += 4)
+ for (off = 0; off < n; off += 4, pos++)
{
/* A pixel in the framebuffer is formatted as `%{blue}%{green}%{red}%{x}`
in big-endian binary, or `%{x}%{red}%{green}%{blue}` in little-endian binary. */
@@ -151,9 +161,13 @@ int convert_fb_to_png (png_struct *pngbuf, png_byte *restrict pixbuf, const char
g = (*pixel >> 8) & 255;
b = (*pixel >> 0) & 255;
- SAVE_PNG_PIXEL (pixbuf, x3, r, g, b);
+ if ((pos < d.start) || (pos >= d.end))
+ continue;
+
+ if (x3 < width3)
+ SAVE_PNG_PIXEL (pixbuf, x3, r, g, b);
x3 += 3;
- if (x3 == width3)
+ if (x3 == lineend)
{
SAVE_PNG_ROW (pngbuf, pixbuf);
x3 = 0;
@@ -162,6 +176,7 @@ int convert_fb_to_png (png_struct *pngbuf, png_byte *restrict pixbuf, const char
*adjustment = (off != n ? 4 : 0);
*state = x3;
+ ((struct data *)data)->position = pos;
return 0;
}
diff --git a/src/kern.h b/src/kern.h
index 5bd191c..3810c5f 100644
--- a/src/kern.h
+++ b/src/kern.h
@@ -55,14 +55,13 @@ char *get_fbpath (int altpath, int fbno);
* Get the dimensions of a framebuffer.
*
* @param fbno The number of the framebuffer.
- * @param fbpath The path to the framebuffer device..
+ * @param fbfd File descriptor for framebuffer device.
* @param width Output parameter for the width of the image.
* @param height Output parameter for the height of the image.
* @parma data Additional data to pass to `convert_fb_to_png`.
* @return Zero on success, -1 on error.
*/
-int measure (int fbno, char *restrict fbpath, long *restrict width,
- long *restrict height, void **restrict data);
+int measure (int fbno, int fbfd, long *restrict width, long *restrict height, void **restrict data);
/**
* Convert read data from a framebuffer to PNG pixel data.
diff --git a/src/png.c b/src/png.c
index ad889e1..504cdf0 100644
--- a/src/png.c
+++ b/src/png.c
@@ -71,6 +71,7 @@ save_png (int fbfd, long width, long height, int imgfd, void *restrict data)
goto fail;
/* Initialise PNG write, and write head. */
+ errno = 0;
if (setjmp (png_jmpbuf(pngbuf))) /* Failing libpng calls jump here. */
goto fail;
png_init_io (pngbuf, file);
diff --git a/src/scrotty.c b/src/scrotty.c
index bce7036..5ab39fe 100644
--- a/src/scrotty.c
+++ b/src/scrotty.c
@@ -66,7 +66,7 @@ static int try_alt_fbpath = 0;
/**
* Create an image of a framebuffer.
*
- * @param fbname The framebuffer device.
+ * @param fbfd File descriptor for framebuffer device.
* @param imgname The pathname of the output image, `NULL` for piping.
* @param width The width of the image.
* @param height The height of the image.
@@ -74,10 +74,10 @@ static int try_alt_fbpath = 0;
* @return Zero on success, -1 on error.
*/
static int
-save (const char *fbpath, const char *imgpath, long width,
+save (int fbfd, const char *imgpath, long width,
long height, void *restrict data)
{
- int imgfd = STDOUT_FILENO, fbfd = -1, piping = (imgpath == NULL);
+ int imgfd = STDOUT_FILENO, piping = (imgpath == NULL);
int saved_errno;
/* Open output file. */
@@ -89,11 +89,6 @@ save (const char *fbpath, const char *imgpath, long width,
FILE_FAILURE (imgpath);
}
- /* Open the framebuffer device for reading. */
- fbfd = open (fbpath, O_RDONLY);
- if (fbfd == -1)
- FILE_FAILURE (fbpath);
-
/* Save image. */
if (save_png (fbfd, width, height, imgfd, data) < 0)
goto fail;
@@ -105,8 +100,6 @@ save (const char *fbpath, const char *imgpath, long width,
fail:
saved_errno = errno;
- if (fbfd >= 0)
- close (fbfd);
if ((imgfd >= 0) && !piping)
close (imgfd);
errno = saved_errno;
@@ -198,6 +191,7 @@ save_fb (int fbno, const char *filepattern, const char *execpattern)
char *execargs = NULL;
long width, height;
void *data = NULL;
+ int fbfd = -1;
int rc = 0, saved_errno = 0;
/* Get pathname for framebuffer, and stop if we have read all existing ones. */
@@ -205,8 +199,13 @@ save_fb (int fbno, const char *filepattern, const char *execpattern)
if (access (fbpath, F_OK))
return 1;
+ /* Open the framebuffer device for reading. */
+ fbfd = open (fbpath, O_RDONLY);
+ if (fbfd == -1)
+ FILE_FAILURE (fbpath);
+
/* Get the size of the framebuffer. */
- if (measure (fbno, fbpath, &width, &height, &data) < 0)
+ if (measure (fbno, fbfd, &width, &height, &data) < 0)
goto fail;
/* Get output pathname. */
@@ -218,7 +217,7 @@ save_fb (int fbno, const char *filepattern, const char *execpattern)
}
/* Take a screenshot of the current framebuffer. */
- if (save (fbpath, imgpath, width, height, data) < 0)
+ if (save (fbfd, imgpath, width, height, data) < 0)
goto fail;
if (imgpath)
fprintf (stderr, _("Saved framebuffer %i to %s.\n"), fbno, imgpath);
@@ -242,6 +241,8 @@ save_fb (int fbno, const char *filepattern, const char *execpattern)
saved_errno = errno;
rc = -1;
done:
+ if (fbfd >= 0)
+ close (fbfd);
free (execargs);
free (imgpath);
return errno = saved_errno, rc;
@@ -407,11 +408,11 @@ main (int argc, char *argv[])
return 0;
fail:
- if (failure_file == NULL)
- perror (execname);
- else
+ if (failure_file != NULL)
fprintf (stderr, _("%s: %s: %s\n"),
execname, strerror (errno), failure_file);
+ else if (errno)
+ perror (execname);
return 1;
no_fb: