mirror of
https://github.com/Genymobile/scrcpy.git
synced 2025-04-21 03:55:05 +00:00
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:
parent
037be4af21
commit
75ebbc5be4
6 changed files with 8546 additions and 0 deletions
|
@ -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'
|
||||
|
|
|
@ -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
6464
app/src/lodepng.c
Normal file
File diff suppressed because it is too large
Load diff
1977
app/src/lodepng.h
Normal file
1977
app/src/lodepng.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue