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
+37
View File
@@ -0,0 +1,37 @@
// Platform implementation of EterLib/JpegFile.h. 40250 writes it with libjpeg-9a (JpegFile.cpp: a stdio
// destination manager, JCS_RGB, jpeg_set_defaults + jpeg_set_quality); here stb_image_write encodes the
// same input (top-down RGB rows, 3 bytes per pixel) at the same quality into a baseline JFIF file.
//
// Only jpeg_save has a caller in 40250 (CPythonGraphic::SaveJPEG, the screenshot key); the other
// declarations of JpegFile.h stay undefined.
#include "EterLib/StdAfx.h"
#include "EterLib/JpegFile.h"
#include <algorithm>
#include <string>
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_WRITE_STATIC
#define STBI_WRITE_NO_STDIO
#include "../third_party/stb_image_write.h"
namespace
{
void write_to_file(void* context, void* data, int size)
{
fwrite(data, 1, size_t(size), static_cast<FILE*>(context));
}
}
int jpeg_save(unsigned char*data_d, int width, int height, int quality, const char*filename)
{
// The Win32 CRT takes '\\' as a separator (grp.SaveScreenShot builds "<Documents>\\METIN2\\<time>.jpg").
std::string path(filename);
std::replace(path.begin(), path.end(), '\\', '/');
FILE* fi = fopen(path.c_str(), "wb");
if (fi == NULL)
return 0;
const int ok = stbi_write_jpg_to_func(write_to_file, fi, width, height, 3, data_d, quality);
const bool closed = fclose(fi) == 0;
return ok && closed ? 1 : 0;
}