Xfce Forum

Sub domains
 

You are not logged in.

#1 2010-09-16 00:55:53

Plasma
Member
Registered: 2010-09-15
Posts: 1

Reloading wallpaper images - an automated script for dualhead setups

Greetings!

A few days have passed since XFCE also made it on my main workstation. I have been using it for a while on my server and one of the laptops and was quite happy with it. Since KDE has raised its SL (sucking level) with every new release I tried in the past six months, it finally got thrown out this evening and was ultimately replaced by XFCE. I found out it does everything I want, should have given it a shot a few months earlier ... Okay, I'm drifting now.

After the setup of my new desktop, just one thing was missing today. I happen to have a huge collection of professionally created wallpaper images from a (in my opinion) great artist. I also happen to have a dualhead monitor setup, which since the death of KDE3 obliged me to manually split these wallpapers into halfs, then manually throw them at each desktop, then manually ... Well, whatever, it plain sucked. Sorry for my rudeness, but this really kept me shot.

This evening I stumbled upon this topic about automatically reloading xfdesktop and thought, this could be a starting point for ...

To keep a long story short, in the last two hours I wrote a small script, which you can put into your crontab, which takes an image randomly out of a directory and splits them onto both desktops.

Let's jump into it:

#!/usr/bin/php
<?php

//
// XFCE wallpaper switcher
// Free for use in the public domain
//

// ---------- Configuration

$wallpaperPath = "/home/username/Wallpapers/SomeCollection/"; // do not forget the trailing slashes!
$targetPath = "/home/username/Wallpapers/";

$leftImageTarget = $targetPath . ".xfce_left.png"; // leading dots, so that these files will be hidden
$rightImageTarget = $targetPath . ".xfce_right.png";

$acceptedFiles = array ("jpg", "png");

$statisticsDat = "/home/username/Wallpapers/.xfce_wallpaper_stats.json";


$screenWidth = 3360; // adjust these to your needs
$screenHeight = 1050;


// ---------- Test for needed extensions

if (! class_exists ("Imagick"))
{
    echo "Extension ImageMagick not found, aborting.\n";
    exit -1;
}


// ---------- Runtime variables

// should the viewing statistics be saved at the end?
$dirtyFlag = false;

// smallest number of image views
$minCount = PHP_INT_MAX;

// largtest number of image views
$maxCount = 0;

// the list of all available images
$imageList = array ();


// ---------- Scan wallpaper directory

$dirIterator = new DirectoryIterator ($wallpaperPath);

foreach ($dirIterator as $dirEntry)
{
    if ($dirEntry -> isDot () || ! $dirEntry -> isFile ())
        continue;

    $imgName = $dirEntry -> getFilename ();

    if (! in_array (strtolower (substr ($imgName, -3)), $acceptedFiles))
        continue;

    $imageList [$imgName] = 0;
}


// ---------- Load viewing statistics

if (file_exists ($statisticsDat))
{
    // Open and read the file
    $jsonFile = fopen ($statisticsDat, 'r', false);
    if ($jsonFile === false)
        die ("Error opening statistics file for reading.\n");

    $jsonData = fread ($jsonFile, filesize ($statisticsDat));
    if ($jsonData === false)
        die ("Error reading statistics file.\n");

    fclose ($jsonFile);

    // Process the contents
    $jsonArray = json_decode ($jsonData, true);
    if ($jsonArray === null)
        die ("Error parsing JSON statistics data.\n");

    foreach ($jsonArray as $json)
    {
        $jImgName = $json ["imgName"];
        if (array_key_exists ($jImgName, $imageList))
            $imageList [$jImgName] = intval ($json ["viewCount"]);
    }
}
else
    $dirtyFlag = true;


// ---------- Determine view counts

foreach ($imageList as $imgName => $viewCount)
{
    if ($viewCount < $minCount)
        $minCount = $viewCount;
    if ($viewCount > $maxCount)
        $maxCount = $viewCount;
}


// ---------- Main loop to choose a new image to display

$image = null;

while (true)
{
    // make a random choice over all remaining candidates
    $choosenImage = array_rand ($imageList, 1);

    if ($minCount != $maxCount && $imageList [$choosenImage] >= $maxCount)
        continue;  // got that one recently, chose another image

    // check if the chosen image fits the screen
    $image = new Imagick ($wallpaperPath . $choosenImage);

    if ($image -> getImageWidth () != $screenWidth || $image -> getImageHeight () != $screenHeight)
    {
        $imageList [$choosenImage] = PHP_INT_MAX;  // throw it out of the index
        echo "Image '" . $choosenImage . "' does not fit your screen.\n";  // notify user
        continue;  // another round
    }

    break; // Image has passed the screen-check, leave the loop
}


// ---------- Split chosen image

if ($image == null) // should never happen
    die ("An unfortunate schmelting accident has happened.\nPlease inform your system administrator.\n*BSOD*\n");

$leftImage = $image;
$rightImage = new Imagick ($wallpaperPath . $choosenImage); // clone() does not work, for unknown reasons

$screenHalf = round ($screenWidth / 2);

$leftImage -> cropImage ($screenHalf, $screenHeight, 0, 0);
$rightImage -> cropImage ($screenHalf, $screenHeight, $screenHalf, 0);


// ---------- Write the new images

function writeImage ($imagickObj, $targetFilename)
{
    $imagickObj -> setImageFormat ("png");
    $imagickObj -> setImageCompressionQuality (6);

    // As ImageMagick is too f**ing dumb to regard setFilename(), we have to open our own handle here
    $imgFile = fopen ($targetFilename, 'w', false);
    if ($imgFile === false)
        die ("Error opening image file for writing.\n");

    if (! $imagickObj -> writeImageFile ($imgFile))
        echo "Image '" . $targetFilename . "' write error!\n";

    if (! file_exists ($targetFilename))
        echo "Image '" . $targetFilename . "' not written!\n";

    fclose ($imgFile);
    $imagickObj -> destroy ();
}

writeImage ($leftImage, $leftImageTarget);
writeImage ($rightImage, $rightImageTarget);


// ---------- Reload XFCE desktop

$xfceOutput = array ();
$xfceResult = 0;
exec ("xfdesktop --reload", $xfceOutput, $xfceResult);

if ($xfceResult != 0)
    die ("XFCE xfdesktop reload error: " . print_r ($xfceOutput, true) . "\n");

// update statistics
$imageList [$choosenImage] += 1;
$dirtyFlag = true;


// ---------- Save viewing statistics

if ($dirtyFlag)
{
    $jsonArray = array ();

    foreach ($imageList as $imgName => $viewCount)
        $jsonArray &#91;] = array ("imgName" => $imgName, "viewCount" => $viewCount);

    $jsonData = json_encode ($jsonArray);
    if ($jsonArray === null)
        die ("Error creating JSON statistics data.\n");

    // Open and write the file
    $jsonFile = fopen ($statisticsDat, 'w', false);
    if ($jsonFile === false)
        die ("Error opening statistics file for writing.\n");

    if (fwrite ($jsonFile, $jsonData) === false)
        die ("Error writing statistics file.\n");

    fclose ($jsonFile);
}
?>

The prerequisites are:

  • PHP with command line interface (CLI) >= 5.2.0

  • ImageMagick >= 6.3.6

  • PECL Imagick extension

Short explanation of what the script does:

  • takes a path argument, scans the directory contents for useable image files and puts the found filenames into an array

  • choses one of the found images based on a vastly complicated, random algorithm

  • loads the chosen image into a (actually they're two) Imagick-object

  • splits the image into two separate new images

  • writes these images into two destined files

  • and finally calls "xfdesktop --reload", which hopefully should have the effect of you getting a new wallpaper

Explanation of what the script does additionally:

  • keeps a statistics file were all image "impressions" get counted

  • adjusts the random choice towards images that haven't been viewed recently

Steps to setup the script:

  • install all prerequisites, if you don't have them already

  • copy the script into some location where you will still find it half a year from now

  • adjust the configuration parameters, the variable names and comments should be quite self explanatory

  • make the script executable

  • setup your XFCE desktops to use single images, one for the correct location of ".xfce_left.png" and the other one for ".xfce_right.png", obviously. If you don't like the files to be hidden, just throw out the dots in the config parameters.

  • call the script on your terminal to see if it does the right thingTM

  • point your crontab to the script and enjoy!

0,30 * * * *    DISPLAY=:0.0 nice -+20 ~/.cron.d/xfce_wallpaper_changer.php

Final thoughts about it:

  • I just kept two hours hacking it together and it worksforme, but there's absolutely no guarantee that it will work on your setup. If you like it, say a few words of gratefulness. If it doesn't, please just be creative, look for the error by yourself, and post your suggestions for improvement into this thread. Please don't call me for support.

  • It is really, really a great dirty hack.

  • If you add new images to the scanned directory, they will be silently added to the statistics. But if you delete or rename files, the according counters will be lost.

  • It depends on PHP and ImageMagick, which are possibly the worst tools for this job. If someone likes to port it to Python or Perl, just go ahead and post your results into this thread.

  • There should be much more error checking and a more sophisticated way of logging those errors, rather than just echoing them out into the great wilderness.

  • Did I mention the dirtyness of the hack it is?

  • It's use is rather limited, improved versions could do the same thing for single screens or other multihead setups. Also some parameters (mostly screen size) shouldn't be manually configured, but instead queried from the window manager or detected by well known image dimensions (for example, user throws in a 3072x768 image, so this must be triplehead). I don't have the slightest clue how to query XDM for screen resolution from the console, and if at some point in the future I replace my monitors, there should be 20 seconds left for me to change these parameters in the script. Errm. Yes.

  • XFCE is a really cool thing, and I hope my little improvement will be of advantage for at least one or two other lifeforms.

Thanks for reading so far! I really should go to bed now ...

Plasma

Offline

Board footer

Powered by FluxBB