2018-08-05 22:37:14 +02:00
|
|
|
#!/usr/bin/env python3
|
2012-07-06 14:19:54 +02:00
|
|
|
|
|
|
|
# Build a multi screen wallpaper
|
|
|
|
|
|
|
|
# First argument is the directory where the wallpapers can be
|
|
|
|
# found. We use xinerama to know the dimension of each screen.
|
|
|
|
|
2018-08-05 22:37:14 +02:00
|
|
|
from __future__ import print_function, unicode_literals, division
|
|
|
|
|
2012-07-06 14:19:54 +02:00
|
|
|
import os
|
|
|
|
import random
|
|
|
|
import optparse
|
2015-02-05 09:26:17 +01:00
|
|
|
import tempfile
|
2012-07-06 14:19:54 +02:00
|
|
|
|
2020-02-06 21:59:29 +01:00
|
|
|
from Xlib import display
|
2018-08-05 22:37:14 +02:00
|
|
|
from Xlib.ext import randr
|
2012-07-06 14:19:54 +02:00
|
|
|
|
2018-08-05 22:37:14 +02:00
|
|
|
from PIL import Image
|
2012-07-06 14:19:54 +02:00
|
|
|
|
|
|
|
parser = optparse.OptionParser()
|
|
|
|
parser.add_option("-d", "--directory", dest="directory", default=".",
|
2016-04-17 19:17:53 +02:00
|
|
|
help="search for images in DIRECTORY", metavar="DIRECTORY")
|
2020-02-06 22:00:58 +01:00
|
|
|
parser.add_option("-t", "--target", dest="target", default="background.png",
|
2016-04-17 19:17:53 +02:00
|
|
|
help="write background to FILE", metavar="FILE")
|
2012-07-06 14:19:54 +02:00
|
|
|
parser.add_option("-c", "--crop", dest="crop", action="store_true",
|
|
|
|
help="crop image instead of centering them")
|
2020-02-06 22:02:35 +01:00
|
|
|
parser.add_option("--compression", default=0, type=int,
|
|
|
|
help="compression level when saving")
|
2012-07-06 14:19:54 +02:00
|
|
|
options, args = parser.parse_args()
|
|
|
|
|
|
|
|
assert not args, "No additional arguments are accepted"
|
|
|
|
|
|
|
|
background = None
|
|
|
|
|
|
|
|
# Get display size
|
2018-08-05 22:37:14 +02:00
|
|
|
d = display.Display()
|
|
|
|
screen = d.screen()
|
|
|
|
window = screen.root.create_window(0, 0, 1, 1, 1, screen.root_depth)
|
|
|
|
background = Image.new('RGB', (screen.width_in_pixels, screen.height_in_pixels))
|
|
|
|
|
|
|
|
# Query randr extension
|
|
|
|
screens = []
|
|
|
|
screen_resources = randr.get_screen_resources(window)
|
|
|
|
for output in screen_resources.outputs:
|
|
|
|
output_info = randr.get_output_info(window, output,
|
|
|
|
screen_resources.timestamp)
|
|
|
|
if output_info.crtc == 0:
|
|
|
|
continue
|
|
|
|
crtc_info = randr.get_crtc_info(window, output_info.crtc,
|
|
|
|
output_info.timestamp)
|
|
|
|
screens.append((crtc_info.width, crtc_info.height,
|
|
|
|
crtc_info.x, crtc_info.y))
|
|
|
|
if not screens:
|
2012-07-06 14:19:54 +02:00
|
|
|
screens = [(background.size[0], background.size[1], 0, 0)]
|
|
|
|
screens.sort(key=lambda screen: -screen[0]*screen[1])
|
|
|
|
|
|
|
|
# Get as many random image as we have screens
|
|
|
|
images = []
|
2018-08-01 14:24:53 +02:00
|
|
|
for base, _, files in os.walk(os.path.join(options.directory)):
|
2012-07-06 14:19:54 +02:00
|
|
|
for i in files:
|
2018-08-05 22:37:14 +02:00
|
|
|
if os.path.splitext(i)[1].lower() in ('.jpg',
|
|
|
|
'.jpeg',
|
|
|
|
'.png'):
|
2018-08-01 14:24:53 +02:00
|
|
|
images.append(os.path.join(base, i))
|
2018-08-28 09:51:58 +02:00
|
|
|
images = random.sample(images, len(screens))
|
2015-02-05 09:27:27 +01:00
|
|
|
images = [Image.open(image) for image in images]
|
2018-08-01 14:28:44 +02:00
|
|
|
images.sort(key=lambda im: -im.size[0]*im.size[1])
|
|
|
|
images = images[:len(screens)]
|
2018-08-01 14:24:53 +02:00
|
|
|
|
|
|
|
# If more than one screen and one image has the right aspect ratio,
|
|
|
|
# use it.
|
|
|
|
if len(screens) > 1:
|
2018-08-05 22:37:14 +02:00
|
|
|
target = screen.width_in_pixels * 100 / screen.height_in_pixels
|
2018-08-01 14:24:53 +02:00
|
|
|
ratios = [image.size[0] * 100 / image.size[1] for image in images]
|
|
|
|
try:
|
|
|
|
index = ratios.index(target)
|
|
|
|
images = [images[index]]
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
2016-04-17 19:17:53 +02:00
|
|
|
print("wallpaper: {}".format(" + ".join(
|
|
|
|
["`%s`" % x.filename[(len(options.directory) + 1):]
|
|
|
|
for x in images])))
|
|
|
|
|
2018-08-01 14:24:53 +02:00
|
|
|
if len(screens) > 1 and len(images) == 1:
|
|
|
|
# Wide wallpaper
|
2020-02-06 22:06:24 +01:00
|
|
|
image = images[0]
|
2018-08-05 22:37:14 +02:00
|
|
|
if image.size != (screen.width_in_pixels, screen.height_in_pixels):
|
|
|
|
image = image.resize((screen.width_in_pixels, screen.height_in_pixels),
|
2018-08-01 14:24:53 +02:00
|
|
|
Image.CUBIC)
|
|
|
|
background.paste(image, (0, 0))
|
|
|
|
else:
|
|
|
|
for index in range(len(screens)):
|
|
|
|
x, y, offsetx, offsety = screens[index]
|
|
|
|
image = images[index]
|
|
|
|
|
|
|
|
# Find the right size for the screen
|
2018-08-05 22:37:14 +02:00
|
|
|
imx, imy = x, image.size[1]*x//image.size[0]
|
2018-08-01 14:24:53 +02:00
|
|
|
if (options.crop and imy < y) or (not options.crop and imy > y):
|
2018-08-05 22:37:14 +02:00
|
|
|
imx, imy = image.size[0]*y//image.size[1], y
|
2018-08-01 14:24:53 +02:00
|
|
|
if image.size != (imx, imy):
|
|
|
|
image = image.resize((imx, imy), Image.CUBIC)
|
|
|
|
if options.crop:
|
|
|
|
image = image.crop(((imx-x)/2, (imy-y)/2,
|
|
|
|
imx-(imx-x)/2, imy-(imy-y)/2))
|
|
|
|
background.paste(image, (offsetx, offsety))
|
|
|
|
else:
|
|
|
|
background.paste(image, ((x-imx)/2 + offsetx,
|
|
|
|
(y-imy)/2 + offsety))
|
2012-07-06 14:19:54 +02:00
|
|
|
|
|
|
|
# Save
|
|
|
|
assert background, "Don't know the size of the display area"
|
2016-04-17 19:17:53 +02:00
|
|
|
with tempfile.NamedTemporaryFile(
|
|
|
|
delete=False,
|
2015-02-05 09:26:17 +01:00
|
|
|
dir=os.path.dirname(os.path.realpath(options.target))) as tmp:
|
2020-02-06 22:02:35 +01:00
|
|
|
background.save(tmp, "png", compress_level=options.compression)
|
2015-02-05 09:26:17 +01:00
|
|
|
os.rename(tmp.name, options.target)
|