Procházet zdrojové kódy

Added support for taking a screenshot after wallpaper's up (useful for pywal and other ricing rools)

Signed-off-by: Alexis Maiquez <almamu@almamu.com>
Alexis Maiquez před 3 roky
rodič
revize
087a0976ae
2 změnil soubory, kde provedl 104 přidání a 4 odebrání
  1. 15 0
      README.md
  2. 89 4
      main.cpp

+ 15 - 0
README.md

@@ -131,6 +131,21 @@ To reduce the performance hit to your system you can reduce (or increase) the FP
 ./linux-wallpaperengine --fps 30
 ./linux-wallpaperengine --fps 30
 ```
 ```
 
 
+## 5.6. Audio
+### 5.6.1. Disable audio
+It's possible to disable the audio of the background with the silent argument
+```
+./linux-wallpaperengine --silent
+```
+
+## 5.7. Taking a screenshot
+It is possible to take a screenshot of the screen's content at the moment a background is loaded up and rendered. Useful for usage with tools like pywal to further customize your environment:
+```
+./linux-wallpaperengine --screenshot /path/to/screenshot/name.png
+```
+
+PNG, BMP and JPEG are supported.
+
 ## 6. Example background
 ## 6. Example background
 This was the first background to even be compatible with the software. And It's not 100% compatible yet. Both textures and shaders are properly loaded, but there are still particles missing.
 This was the first background to even be compatible with the software. And It's not 100% compatible yet. Both textures and shaders are properly loaded, but there are still particles missing.
 
 

+ 89 - 4
main.cpp

@@ -29,9 +29,9 @@ int g_AudioVolume = 15;
 using namespace WallpaperEngine::Core::Types;
 using namespace WallpaperEngine::Core::Types;
 
 
 const char* assets_default_paths [] = {
 const char* assets_default_paths [] = {
-        ".steam/steam/steamapps/common/wallpaper_engine/assets",
-        ".local/share/Steam/steamapps/common/wallpaper_engine/assets",
-        nullptr
+    ".steam/steam/steamapps/common/wallpaper_engine/assets",
+    ".local/share/Steam/steamapps/common/wallpaper_engine/assets",
+    nullptr
 };
 };
 
 
 const char* backgrounds_default_paths [] = {
 const char* backgrounds_default_paths [] = {
@@ -53,7 +53,8 @@ void print_help (const char* route)
         << "  --volume <amount>\tSets the volume for all the sounds in the background" << std::endl
         << "  --volume <amount>\tSets the volume for all the sounds in the background" << std::endl
         << "  --screen-root <screen name>\tDisplay as screen's background" << std::endl
         << "  --screen-root <screen name>\tDisplay as screen's background" << std::endl
         << "  --fps <maximum-fps>\tLimits the FPS to the given number, useful to keep battery consumption low" << std::endl
         << "  --fps <maximum-fps>\tLimits the FPS to the given number, useful to keep battery consumption low" << std::endl
-        << "  --assets-dir <path>\tFolder where the assets are stored" << std::endl;
+        << "  --assets-dir <path>\tFolder where the assets are stored" << std::endl
+        << "  --screenshot\t\tTakes a screenshot of the background" << std::endl;
 }
 }
 
 
 std::string stringPathFixes(const std::string& s)
 std::string stringPathFixes(const std::string& s)
@@ -262,14 +263,65 @@ CVirtualContainer* buildVirtualContainer ()
     return container;
     return container;
 }
 }
 
 
+void takeScreenshot (WallpaperEngine::Render::CWallpaper* wp, const std::string& filename, FREE_IMAGE_FORMAT format)
+{
+    GLint width, height;
+
+    // bind texture and get the size
+    glBindFramebuffer (GL_FRAMEBUFFER, wp->getWallpaperFramebuffer ());
+    glBindTexture (GL_TEXTURE_2D, wp->getWallpaperTexture ());
+    glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+    glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+
+    // make room for storing the pixel data
+    uint8_t* buffer = new uint8_t [width * height * sizeof (uint8_t) * 3];
+    uint8_t* pixel = buffer;
+
+    // read the image into the buffer
+    glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
+
+    // build the output file with FreeImage
+    FIBITMAP* bitmap = FreeImage_Allocate (width, height, 24);
+    RGBQUAD color;
+
+    // now get access to the pixels
+    for (int y = height; y > 0; y --)
+    {
+        for (int x = 0; x < width; x ++)
+        {
+            color.rgbRed = *pixel ++;
+            color.rgbGreen = *pixel ++;
+            color.rgbBlue = *pixel ++;
+
+            // set the pixel in the destination
+            FreeImage_SetPixelColor (bitmap, x, y, &color);
+        }
+    }
+
+    // finally save the file
+    FreeImage_Save (format, bitmap, filename.c_str (), 0);
+
+    // free all the used memory
+    delete[] buffer;
+
+    FreeImage_Unload (bitmap);
+
+    // unbind the textures
+    glBindTexture (GL_TEXTURE_2D, GL_NONE);
+}
+
 int main (int argc, char* argv[])
 int main (int argc, char* argv[])
 {
 {
     std::vector <std::string> screens;
     std::vector <std::string> screens;
 
 
     int maximumFPS = 30;
     int maximumFPS = 30;
     bool shouldEnableAudio = true;
     bool shouldEnableAudio = true;
+    bool shouldTakeScreenshot = false;
+    FREE_IMAGE_FORMAT screenshotFormat = FIF_UNKNOWN;
     std::string path;
     std::string path;
     std::string assetsDir;
     std::string assetsDir;
+    std::string screenshotPath;
+
 
 
     static struct option long_options [] = {
     static struct option long_options [] = {
         {"screen-root", required_argument, 0, 'r'},
         {"screen-root", required_argument, 0, 'r'},
@@ -280,6 +332,7 @@ int main (int argc, char* argv[])
         {"help",        no_argument,       0, 'h'},
         {"help",        no_argument,       0, 'h'},
         {"fps",         required_argument, 0, 'f'},
         {"fps",         required_argument, 0, 'f'},
         {"assets-dir",  required_argument, 0, 'a'},
         {"assets-dir",  required_argument, 0, 'a'},
+        {"screenshot",  required_argument, 0, 'c'},
         {nullptr,                       0, 0,   0}
         {nullptr,                       0, 0,   0}
     };
     };
 
 
@@ -321,6 +374,11 @@ int main (int argc, char* argv[])
             case 'v':
             case 'v':
                 g_AudioVolume = atoi (optarg);
                 g_AudioVolume = atoi (optarg);
                 break;
                 break;
+
+            case 'c':
+                shouldTakeScreenshot = true;
+                screenshotPath = stringPathFixes (optarg);
+                break;
         }
         }
     }
     }
 
 
@@ -337,6 +395,22 @@ int main (int argc, char* argv[])
         }
         }
     }
     }
 
 
+    // validate screenshot file just to make sure
+    if (shouldTakeScreenshot == true)
+    {
+        // ensure the file is one of the supported formats
+        std::string extension = screenshotPath.substr (screenshotPath.find_last_of (".") + 1);
+
+        if (extension == "bmp")
+            screenshotFormat = FIF_BMP;
+        else if (extension == "png")
+            screenshotFormat = FIF_PNG;
+        else if (extension == "jpg" || extension == "jpeg")
+            screenshotFormat = FIF_JPEG;
+        else
+            throw std::runtime_error ("Unsupported screenshot format...");
+    }
+
     // attach signals so if a stop is requested the X11 resources are freed and the program shutsdown gracefully
     // attach signals so if a stop is requested the X11 resources are freed and the program shutsdown gracefully
     std::signal(SIGINT, signalhandler);
     std::signal(SIGINT, signalhandler);
     std::signal(SIGTERM, signalhandler);
     std::signal(SIGTERM, signalhandler);
@@ -504,6 +578,8 @@ int main (int argc, char* argv[])
 
 
     double startTime, endTime, minimumTime = 1.0 / maximumFPS;
     double startTime, endTime, minimumTime = 1.0 / maximumFPS;
 
 
+    uint32_t frameCounter = 0;
+
     while (glfwWindowShouldClose (window) == 0 && g_KeepRunning == true)
     while (glfwWindowShouldClose (window) == 0 && g_KeepRunning == true)
     {
     {
         // get the real framebuffer size
         // get the real framebuffer size
@@ -526,6 +602,15 @@ int main (int argc, char* argv[])
         // ensure the frame time is correct to not overrun FPS
         // ensure the frame time is correct to not overrun FPS
         if ((endTime - startTime) < minimumTime)
         if ((endTime - startTime) < minimumTime)
             usleep ((minimumTime - (endTime - startTime)) * CLOCKS_PER_SEC);
             usleep ((minimumTime - (endTime - startTime)) * CLOCKS_PER_SEC);
+
+        frameCounter ++;
+
+        if (frameCounter == 5 && shouldTakeScreenshot == true)
+        {
+            takeScreenshot (context->getWallpaper (), screenshotPath, screenshotFormat);
+            // disable screenshot just in case the counter overflows
+            shouldTakeScreenshot = false;
+        }
     }
     }
 
 
     // ensure this is updated as sometimes it might not come from a signal
     // ensure this is updated as sometimes it might not come from a signal