diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index 579c0fa..e4e0c5f 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -34,9 +34,11 @@ # undef DEBUG #endif -#if defined(HAVE_LIBLO) && defined(HEADLESS) -# include -# include "extra/Thread.hpp" +#ifdef HAVE_LIBLO +# ifdef HEADLESS +# include +# include "extra/Thread.hpp" +# endif # include "CardinalCommon.hpp" #endif @@ -815,7 +817,7 @@ protected: if (std::strcmp(key, "screenshot") == 0) { fStateScreenshot = value; - #if defined(HAVE_LIBLO) && defined(HEADLESS) + #if defined(HAVE_LIBLO) && !defined(HEADLESS) patchUtils::sendScreenshotToRemote(value); #endif return; diff --git a/src/override/Scene.cpp b/src/override/Scene.cpp index c2c5c0d..5bb28ff 100644 --- a/src/override/Scene.cpp +++ b/src/override/Scene.cpp @@ -51,6 +51,7 @@ #endif #include "../CardinalCommon.hpp" +#include "extra/Base64.hpp" #include "DistrhoUtils.hpp" @@ -549,7 +550,13 @@ void sendScreenshotToRemote(const char* const screenshot) { const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); - lo_send(addr, "/screenshot", "s", screenshot); + std::vector data(d_getChunkFromBase64String(screenshot)); + + if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { + lo_send(addr, "/screenshot", "b", blob); + lo_blob_free(blob); + } + lo_address_free(addr); #endif } diff --git a/src/override/Window.cpp b/src/override/Window.cpp index a9b0bd1..7520382 100644 --- a/src/override/Window.cpp +++ b/src/override/Window.cpp @@ -362,24 +362,55 @@ void Window::run() { } -static void Window__flipBitmap(uint8_t* pixels, int width, int height, int depth) { +static void Window__flipBitmap(uint8_t* pixels, const int width, const int height, const int depth) { for (int y = 0; y < height / 2; y++) { const int flipY = height - y - 1; uint8_t tmp[width * depth]; std::memcpy(tmp, &pixels[y * width * depth], width * depth); - std::memcpy(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); + std::memmove(&pixels[y * width * depth], &pixels[flipY * width * depth], width * depth); std::memcpy(&pixels[flipY * width * depth], tmp, width * depth); } } +#ifdef STBI_WRITE_NO_STDIO +static void Window__downscaleBitmap(uint8_t* pixels, int& width, int& height) { + int targetWidth = width; + int targetHeight = height; + double scale = 1.0; + + if (targetWidth > 300) { + scale = width / 300.0; + targetWidth = 300; + targetHeight = height / scale; + } + if (targetHeight > 200) { + scale = height / 200.0; + targetHeight = 200; + targetWidth = width / scale; + } + DISTRHO_SAFE_ASSERT_INT_RETURN(targetWidth <= 300, targetWidth,); + DISTRHO_SAFE_ASSERT_INT_RETURN(targetHeight <= 200, targetHeight,); + + // FIXME worst possible quality :/ + for (int y = 0; y < targetHeight; ++y) { + const int ys = static_cast(y * scale); + for (int x = 0; x < targetWidth; ++x) { + const int xs = static_cast(x * scale); + std::memmove(pixels + (width * y + x) * 3, pixels + (width * ys + xs) * 3, 3); + } + } + + width = targetWidth; + height = targetHeight; +} + static void Window__writeImagePNG(void* context, void* data, int size) { USE_NAMESPACE_DISTRHO UI* const ui = static_cast(context); - String encodedPNG("data:image/png;base64,"); - encodedPNG += String::asBase64(data, size); - ui->setState("screenshot", encodedPNG.buffer()); + ui->setState("screenshot", String::asBase64(data, size).buffer()); } +#endif void Window::step() { @@ -470,28 +501,33 @@ void Window::step() { ++internal->generateScreenshotStep; int y = 0; -#ifndef CARDINAL_TRANSPARENT_SCREENSHOTS +#ifdef CARDINAL_TRANSPARENT_SCREENSHOTS + constexpr const int depth = 4; +#else y = APP->scene->menuBar->box.size.y * newPixelRatio; + constexpr const int depth = 3; #endif // Allocate pixel color buffer - uint8_t* const pixels = new uint8_t[winHeight * winWidth * 4]; + uint8_t* const pixels = new uint8_t[winHeight * winWidth * depth]; // glReadPixels defaults to GL_BACK, but the back-buffer is unstable, so use the front buffer (what the user sees) glReadBuffer(GL_FRONT); - glReadPixels(0, 0, winWidth, winHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glReadPixels(0, 0, winWidth, winHeight, depth == 3 ? GL_RGB : GL_RGBA, GL_UNSIGNED_BYTE, pixels); if (internal->generateScreenshotStep == kScreenshotStepSaving) { // Write pixels to PNG - const int stride = winWidth * 4; - const uint8_t* const pixelsWithOffset = pixels + (stride * y); - Window__flipBitmap(pixels, winWidth, winHeight, 4); + const int stride = winWidth * depth; + uint8_t* const pixelsWithOffset = pixels + (stride * y); + Window__flipBitmap(pixels, winWidth, winHeight, depth); + winHeight -= y; #ifdef STBI_WRITE_NO_STDIO + Window__downscaleBitmap(pixelsWithOffset, winWidth, winHeight); stbi_write_png_to_func(Window__writeImagePNG, internal->ui, - winWidth, winHeight - y, 4, pixelsWithOffset, stride); + winWidth, winHeight, depth, pixelsWithOffset, stride); #else - stbi_write_png("screenshot.png", winWidth, winHeight - y, 4, pixelsWithOffset, stride); + stbi_write_png("screenshot.png", winWidth, winHeight, depth, pixelsWithOffset, stride); #endif internal->generateScreenshotStep = kScreenshotStepNone;