aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremersion <contact@emersion.fr>2018-06-30 23:16:53 +0100
committeremersion <contact@emersion.fr>2018-06-30 23:18:13 +0100
commita7a96d7644ee00b29f9376576a0da8a26cf3cba6 (patch)
treee58ce0aca39c0cf8d00d2086776da2a686336d44
parentdbb01cbcd01d191e406d99d2837c84a9d73d34a0 (diff)
examples/screencopy: use libpng
-rw-r--r--examples/meson.build14
-rw-r--r--examples/screencopy.c101
2 files changed, 57 insertions, 58 deletions
diff --git a/examples/meson.build b/examples/meson.build
index a290dc82..18f44fde 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -1,6 +1,8 @@
threads = dependency('threads')
wayland_cursor = dependency('wayland-cursor')
+libpng = dependency('libpng', required: false)
+
# These versions correspond to ffmpeg 4.0
libavutil = dependency('libavutil', version: '>=56.14.100', required: false)
libavcodec = dependency('libavcodec', version: '>=58.18.100', required: false)
@@ -57,8 +59,10 @@ if libavutil.found() and libavcodec.found() and libavformat.found()
)
endif
-executable(
- 'screencopy',
- 'screencopy.c',
- dependencies: [wayland_client, wlr_protos, wlroots]
-)
+if libpng.found()
+ executable(
+ 'screencopy',
+ 'screencopy.c',
+ dependencies: [wayland_client, wlr_protos, wlroots, libpng]
+ )
+endif
diff --git a/examples/screencopy.c b/examples/screencopy.c
index dc1984e6..4e58cd3b 100644
--- a/examples/screencopy.c
+++ b/examples/screencopy.c
@@ -26,6 +26,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <png.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -37,6 +38,11 @@
#include <wayland-client-protocol.h>
#include "wlr-screencopy-unstable-v1-client-protocol.h"
+struct format {
+ enum wl_shm_format wl_format;
+ bool is_bgr;
+};
+
static struct wl_shm *shm = NULL;
static struct zwlr_screencopy_manager_v1 *screencopy_manager = NULL;
static struct wl_output *output = NULL;
@@ -50,16 +56,13 @@ static struct {
} buffer;
bool buffer_copy_done = false;
-// wl_shm_format describes little-endian formats, ImageMagick uses big-endian
-// formats.
-static const struct {
- enum wl_shm_format wl_format;
- char *str_format;
-} formats[] = {
- {WL_SHM_FORMAT_XRGB8888, "BGRA"},
- {WL_SHM_FORMAT_ARGB8888, "BGRA"},
- {WL_SHM_FORMAT_XBGR8888, "RGBA"},
- {WL_SHM_FORMAT_ABGR8888, "RGBA"},
+// wl_shm_format describes little-endian formats, libpng uses big-endian
+// formats (so Wayland's ABGR is libpng's RGBA).
+static const struct format formats[] = {
+ {WL_SHM_FORMAT_XRGB8888, true},
+ {WL_SHM_FORMAT_ARGB8888, true},
+ {WL_SHM_FORMAT_XBGR8888, false},
+ {WL_SHM_FORMAT_ABGR8888, false},
};
static int backingfile(off_t size) {
@@ -156,8 +159,8 @@ static void handle_global(void *data, struct wl_registry *registry,
output = wl_registry_bind(registry, name, &wl_output_interface, 1);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
- } else if (strcmp(interface, zwlr_screencopy_manager_v1_interface.name)
- == 0) {
+ } else if (strcmp(interface,
+ zwlr_screencopy_manager_v1_interface.name) == 0) {
screencopy_manager = wl_registry_bind(registry, name,
&zwlr_screencopy_manager_v1_interface, 1);
}
@@ -174,64 +177,56 @@ static const struct wl_registry_listener registry_listener = {
};
static void write_image(char *filename, enum wl_shm_format wl_fmt, int width,
- int height, int stride, bool y_invert, void *data) {
- char size[10 + 1 + 10 + 2 + 1]; // int32_t are max 10 digits
- sprintf(size, "%dx%d+0", width, height);
-
- const char *fmt_str = NULL;
+ int height, int stride, bool y_invert, png_bytep data) {
+ const struct format *fmt = NULL;
for (size_t i = 0; i < sizeof(formats) / sizeof(formats[0]); ++i) {
if (formats[i].wl_format == wl_fmt) {
- fmt_str = formats[i].str_format;
+ fmt = &formats[i];
break;
}
}
- if (fmt_str == NULL) {
+ if (fmt == NULL) {
fprintf(stderr, "unsupported format %"PRIu32"\n", wl_fmt);
exit(EXIT_FAILURE);
}
- char convert[strlen(fmt_str) + 3];
- memcpy(convert, fmt_str, strlen(fmt_str) + 1);
- strcat(convert, ":-");
- int fd[2];
- if (pipe(fd) != 0) {
- fprintf(stderr, "cannot create pipe: %s\n", strerror(errno));
+ FILE *f = fopen(filename, "wb");
+ if (f == NULL) {
+ fprintf(stderr, "failed to open output file\n");
exit(EXIT_FAILURE);
}
- pid_t child = fork();
- if (child < 0) {
- fprintf(stderr, "fork() failed\n");
- exit(EXIT_FAILURE);
- } else if (child != 0) {
- close(fd[0]);
- if (write(fd[1], data, stride * height) < 0) {
- fprintf(stderr, "write() failed: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- waitpid(child, NULL, 0);
- } else {
- close(fd[1]);
- if (dup2(fd[0], 0) != 0) {
- fprintf(stderr, "cannot dup the pipe\n");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
+ png_structp png =
+ png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ png_infop info = png_create_info_struct(png);
+
+ png_init_io(png, f);
- char *argv[11] = {"convert", "-depth", "8", "-size", size, convert,
- "-alpha", "opaque", filename, NULL};
+ png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGBA,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ if (fmt->is_bgr) {
+ png_set_bgr(png);
+ }
+
+ png_write_info(png, info);
+
+ for (size_t i = 0; i < (size_t)height; ++i) {
+ png_bytep row;
if (y_invert) {
- argv[8] = "-flip";
- argv[9] = filename;
- argv[10] = NULL;
+ row = data + (height - i - 1) * stride;
+ } else {
+ row = data + i * stride;
}
+ png_write_row(png, row);
+ }
- execvp("convert", argv);
+ png_write_end(png, NULL);
- fprintf(stderr, "cannot execute convert\n");
- exit(EXIT_FAILURE);
- }
+ png_destroy_write_struct(&png, &info);
+
+ fclose(f);
}
int main(int argc, char *argv[]) {