port: grp.SaveScreenShot via next-frame swapchain readback + JPEG

CPythonGraphic::SaveScreenShot queues a readback of the next presented
frame (ScreenShotHost -> VulkanWindow::request_frame); WriteScreenShot runs
the rest of 40250's function verbatim (X8R8G8B8 rows, SaveJPEG, EXIF tag).
jpeg_save is encoded with stb_image_write. SHGetSpecialFolderPath returns
$HOME/Documents (else cwd); CreateDirectory/_access/jpeg_save accept '\\'.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
shenlei
2026-09-30 12:43:03 +09:00
co-authored by Claude Opus 5.5
parent c21e012965
commit bda85eea50
17 changed files with 2211 additions and 12 deletions
+24 -2
View File
@@ -2,11 +2,33 @@
// Win32 shell-folder API used only by the screenshot command in grp.
#include <windows.h>
#include <cstdio>
#include <cstdlib>
#include <sys/stat.h>
#include <unistd.h>
#define CSIDL_PERSONAL 0x0005
// CSIDL_PERSONAL ("My Documents"): $HOME/Documents where it exists (desktop), otherwise the working
// directory, which is the writable Client directory on Android. grp.SaveScreenShot appends
// "\\METIN2\\"; CreateDirectory and jpeg_save take '\\' as a separator like Win32 does.
inline BOOL SHGetSpecialFolderPath(void*, char* path, int, BOOL)
{
if (path)
if (!path)
return FALSE;
path[0] = '\0';
struct stat st;
const char* home = std::getenv("HOME");
if (home && home[0])
{
std::snprintf(path, MAX_PATH, "%s/Documents", home);
if (::stat(path, &st) == 0 && S_ISDIR(st.st_mode))
return TRUE;
}
if (!::getcwd(path, MAX_PATH))
{
path[0] = '\0';
return FALSE;
return FALSE;
}
return TRUE;
}