Big companies tend to use a variety of webapps to show their news, stats, and announcements. Some locations in the company—usually, the tearoom—might contain displays showing some of that material. A clean way to automate these displays might be to use a relevant API or script for each webapp. However, this assumes two things: the site has an API, and you have enough time to use it.

Another approach is to automatically take screenshots of the webapp. A little dirtier, but much easier to implement and much more amenable to change. Here, I’ve written up that approach.

IECapt

Corporate websites tend to be designed for Internet Explorer (IE). They also tend to have bizarre authentication, redirects, and security certificates. Most website screenshot applications can have difficulty dealing with that. With that in mind, I followed one principle:

The application must behave as if I opened a link in IE, took a screenshot, cropped just the website, and saved the result

IECapt ticked those boxes. It also had the added benefit of being dependency free (C++, only uses windows 7+ libraries). Further, it is open-source and entirely contained in one C++ file, so it was easy to tweak and bugfix (my tweaks).

Scripting

Scripting involved giving IECapt its source data and setting up cronjobs. This process would likely be running unsupervised by me, so it’s important that non-developers could edit the system. To facilitate that, I created a simple .csv file containing the sites of interest:

$ cat webpages-to-screenshot.csv

URL,Output Filename,Minimum Width (pixels),Wait Before Taking Screenshot (ms)
https://corporate-homepage.com,corporate-homepage.png,1200,5000
https://corporate-share-price.com,share-price.png,1200,5000
https://safety-stats.com,safety-stats.png,1200,30000

.csvs can be edited in common software such as excel, so non-programmers can add more sites without having to edit code. The next stage was to write a basic ruby script that iterates through the csv and runs IECapt:

# $ cat generate_webpage_screenshots.rb

require'csv'

sources_to_image =
  CSV.
  read('webpages-to-screenshot.csv').
  drop(1) # header

sources_to_image.each do |url, filename, min_width, capture_delay|
  
  arguments = [
    "--url=\"#{url}\"",
    "--out=out\\#{filename}",
    "--min-width=#{min_width}",
    "--silent",
    "--delay=#{capture_delay}",
    "--min-height=1500"
  ].join(' ')

  # Take the screenshots
  `IECapt.exe #{arguments}`
end

The final convenience step is to batchify the script so that users can click it to run a screengrab session:

$ cat generate-website-screenshots.bat

ruby generate_webpage_screenshots.rb

Automation can be configured by setting up a Windows task to run the batch file every so often (say, once an hour).

The Slideshow

To start the slideshow, users open an image in the output folder (out/) in Windows’ native photo viewer followed by turning on slideshow mode. Slideshow mode then iterates through images in the folder. This exploits the fact that the Windows photo viewer lazily loads the next file in a directory. Lazy-loading means that, even if new images are added to the output folder, the photo viewer iterates through all current images in the folder.

The main shortfall of the slideshow is that the Windows photo viewer does not allow you to run multiple instances of slideshow mode. Some of our presentation computers are multi-screen, so it’s imperative to get around that. However, I’m yet to come across software that supports multiple instances and multiple monitors, and lazy loading.

Conclusions

Overall, this setup lets us:

Reflecting on this micro-project, while it isn’t a super-sophisticated application that bespokely solves the problem perfectly, I believe it follows a few principles which are important for any application—big or small—to try and follow:

I’m trying to follow those principles in my bigger projects. It’s got nothing to do with code quality or complexity: it’s architecture. Architecture lets a non-developer open the project folder and take a pretty good guess at what’s going on. Which is exactly what they’ll need when it needs the occasional kick. Regardless of its size or complexity, well-architected software should try its hardest to present a coherent model of its “world” to the user.