Added Save Screenshot

Pressing the MOD + Q key will save a screenshot the next time the screen is rendered.

It saves a PNG file with a date time stamp filename.

It uses lodepng to encode the file.  Thanks Lode Vandevenne (https://github.com/lvandeve/lodepng)

The save_screenshot function has been modified from user1902824 (https://stackoverflow.com/questions/34255820/save-sdl-texture-to-file)

Limitations.

If 2 screenshots are taken within the same second, the file name will be the same and the first file will be overwritten

Does not handle client side screen rotation.
This commit is contained in:
Aaron Keith 2021-01-16 19:57:18 +13:00
parent 037be4af21
commit 75ebbc5be4
6 changed files with 8546 additions and 0 deletions

View file

@ -20,6 +20,7 @@ src = [
'src/stream.c',
'src/tiny_xpm.c',
'src/video_buffer.c',
'src/lodepng.c',
'src/util/net.c',
'src/util/process.c',
'src/util/str_util.c'

View file

@ -456,6 +456,11 @@ input_manager_process_key(struct input_manager *im,
screen_switch_fullscreen(im->screen);
}
return;
case SDLK_q:
if (!shift && !repeat && down) {
im->screen->save_screenshot = true;
}
return;
case SDLK_w:
if (!shift && !repeat && down) {
screen_resize_to_fit(im->screen);

6464
app/src/lodepng.c Normal file

File diff suppressed because it is too large Load diff

1977
app/src/lodepng.h Normal file

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
#include <assert.h>
#include <string.h>
#include <time.h>
#include <SDL2/SDL.h>
#include "config.h"
@ -11,6 +12,7 @@
#include "scrcpy.h"
#include "tiny_xpm.h"
#include "video_buffer.h"
#include "lodepng.h"
#include "util/lock.h"
#include "util/log.h"
@ -471,12 +473,107 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
return true;
}
void
save_screenshot(struct screen *screen) {
char filename[40];
struct tm *timenow;
SDL_Texture *ren_tex;
SDL_Surface *surf;
int st;
int w;
int h;
int format;
void *pixels;
pixels = NULL;
surf = NULL;
ren_tex = NULL;
format = SDL_PIXELFORMAT_RGBA32;
//Create filename
time_t now = time(NULL);
timenow = localtime(&now);
strftime(filename, sizeof(filename), "screenshot_%Y%m%d%H%M%S.png", timenow);
// Get information about texture we want to save
st = SDL_QueryTexture(screen->texture, NULL, NULL, &w, &h);
if (st != 0) {
LOGE("Failed querying texture: %s\n", SDL_GetError());
goto cleanup;
}
ren_tex = SDL_CreateTexture(screen->renderer, format, SDL_TEXTUREACCESS_TARGET, w, h);
if (!ren_tex) {
LOGE("Failed creating render texture: %s\n", SDL_GetError());
goto cleanup;
}
// Initialize our canvas, then copy texture to a target whose pixel data we
// can access
st = SDL_SetRenderTarget(screen->renderer, ren_tex);
if (st != 0) {
LOGE("Failed setting render target: %s\n", SDL_GetError());
goto cleanup;
}
SDL_SetRenderDrawColor(screen->renderer, 0x00, 0x00, 0x00, 0x00);
SDL_RenderClear(screen->renderer);
st = SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL);
if (st != 0) {
LOGE("Failed copying texture data: %s\n", SDL_GetError());
goto cleanup;
}
// Create buffer to hold texture data and load it
pixels = malloc(w * h * SDL_BYTESPERPIXEL(format));
if (!pixels) {
LOGE("Failed allocating memory\n");
goto cleanup;
}
st = SDL_RenderReadPixels(screen->renderer, NULL, format, pixels, w * SDL_BYTESPERPIXEL(format));
if (st != 0) {
LOGE("Failed reading pixel data: %s\n", SDL_GetError());
goto cleanup;
}
// Copy pixel data over to surface
surf = SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, SDL_BITSPERPIXEL(format), w * SDL_BYTESPERPIXEL(format), format);
if (!surf) {
LOGE("Failed creating new surface: %s\n", SDL_GetError());
goto cleanup;
}
// Save result to an image
st = lodepng_encode_file(filename, surf->pixels, w, h, LCT_RGBA, 8);
if (st != 0) {
LOGE("Failed saving image: %s\n", SDL_GetError());
goto cleanup;
}
LOGI("Saved screenshot to \"%s\"\n", filename);
cleanup:
SDL_FreeSurface(surf);
free(pixels);
SDL_DestroyTexture(ren_tex);
}
void
screen_render(struct screen *screen, bool update_content_rect) {
if (update_content_rect) {
screen_update_content_rect(screen);
}
if (screen->save_screenshot) {
screen->save_screenshot = false;
save_screenshot(screen);
}
SDL_RenderClear(screen->renderer);
if (screen->rotation == 0) {
SDL_RenderCopy(screen->renderer, screen->texture, NULL, &screen->rect);

View file

@ -34,6 +34,7 @@ struct screen {
bool maximized;
bool no_window;
bool mipmaps;
bool save_screenshot;
};
#define SCREEN_INITIALIZER { \
@ -67,6 +68,7 @@ struct screen {
.maximized = false, \
.no_window = false, \
.mipmaps = false, \
.save_screenshot = false,\
}
// initialize default values