Files
mtgodot-poc/tests/port/port_screenshot_test.cpp
T
shenleiandClaude Opus 5.5 bda85eea50 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>
2026-09-30 12:43:03 +09:00

79 lines
2.9 KiB
C++

// grp.SaveScreenShot: CPythonGraphic::SaveScreenShot queues a host frame request (ScreenShotHost.h) and
// ScreenShotHost::WriteScreenShot runs the rest of 40250's SaveScreenShot on the frame: X8R8G8B8 rows ->
// RGB -> SaveJPEG (jpeg_save, quality 100).
#include "EterPythonLib/StdAfx.h"
#include "EterPythonLib/PythonGraphic.h"
#include "../../src/platform/EterPythonLib/ScreenShotHost.h"
#include <cstdio>
#include <cstdlib>
#include <string>
#include <unistd.h>
#include <vector>
static int g_failures = 0;
#define CHECK(cond) \
do { \
if (!(cond)) { \
std::fprintf(stderr, "%s:%d: CHECK(%s)\n", __FILE__, __LINE__, #cond); \
++g_failures; \
} \
} while (0)
static std::vector<unsigned char> ReadFile(const std::string& path)
{
std::vector<unsigned char> data;
if (FILE* f = std::fopen(path.c_str(), "rb")) {
int c;
while ((c = std::fgetc(f)) != EOF)
data.push_back(static_cast<unsigned char>(c));
std::fclose(f);
}
return data;
}
int main()
{
CPythonGraphic graphic;
// No host: 40250's GetBackBuffer failure path.
ScreenShotHost::SetRequest(nullptr);
CHECK(!graphic.SaveScreenShot("unused.jpg"));
char dir[] = "/tmp/mt_screenshot_XXXXXX";
CHECK(mkdtemp(dir) != nullptr);
const std::string path = std::string(dir) + "/shot.jpg";
std::vector<std::string> requested;
ScreenShotHost::SetRequest([&](const std::string& p) { requested.push_back(p); return true; });
CHECK(graphic.SaveScreenShot(path.c_str()));
CHECK(requested.size() == 1 && requested[0] == path);
CHECK(ReadFile(path).empty()); // written when the frame arrives, not by the call
// 8x4 frame with a padded pitch; the padding bytes must not reach the image.
const unsigned w = 8, h = 4, pitch = w * 4 + 16;
std::vector<std::uint8_t> frame(pitch * h, 0xAB);
for (unsigned y = 0; y < h; ++y)
for (unsigned x = 0; x < w; ++x) {
std::uint8_t* px = &frame[y * pitch + x * 4];
px[0] = 0x20; px[1] = 0x80; px[2] = 0xE0; px[3] = 0xFF; // B, G, R, X
}
CHECK(ScreenShotHost::WriteScreenShot(requested[0].c_str(), frame.data(), w, h, pitch));
const std::vector<unsigned char> jpeg = ReadFile(path);
CHECK(jpeg.size() > 4);
CHECK(jpeg.size() > 4 && jpeg[0] == 0xFF && jpeg[1] == 0xD8);
CHECK(jpeg.size() > 4 && jpeg[jpeg.size() - 2] == 0xFF && jpeg[jpeg.size() - 1] == 0xD9);
// An unwritable path is SaveJPEG's failure.
CHECK(!ScreenShotHost::WriteScreenShot((std::string(dir) + "/missing/shot.jpg").c_str(), frame.data(), w, h, pitch));
ScreenShotHost::SetRequest(nullptr);
std::remove(path.c_str());
rmdir(dir);
if (g_failures)
std::fprintf(stderr, "port_screenshot_test: %d failure(s)\n", g_failures);
else
std::puts("port_screenshot_test: ok");
return g_failures ? 1 : 0;
}