From f79fa59d8e004dd7e12163110ae3052e8ef98eaf Mon Sep 17 00:00:00 2001 From: Greg Darke Date: Sun, 24 Feb 2008 23:23:27 +1100 Subject: [PATCH] Import initial windows version --- bin/ChangeWallpaper.pyw | 196 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 bin/ChangeWallpaper.pyw diff --git a/bin/ChangeWallpaper.pyw b/bin/ChangeWallpaper.pyw new file mode 100644 index 0000000..7d1fbc4 --- /dev/null +++ b/bin/ChangeWallpaper.pyw @@ -0,0 +1,196 @@ +# Python program to change the background under windows (tested on windows XP) + +from __future__ import division + +import sys, os +from PIL import Image + +import ctypes +# Kinda like 'from ctypes.windll import user32' +user32 = ctypes.windll.user32 + +###sys.stdout = file(os.path.join(os.environ['USERPROFILE'], 'Desktop', 'Output.txt'), 'w') +###sys.stderr = sys.stdout + +def getUnicodeArgs(): + LocalFree = ctypes.windll.kernel32.LocalFree + + # Defining the GetCommandLineW function + GetCommandLineW = ctypes.windll.kernel32.GetCommandLineW + GetCommandLineW.restype = ctypes.c_wchar_p + + # Defining the CommandLineToArgvW function + CommandLineToArgvW = ctypes.windll.shell32.CommandLineToArgvW + CommandLineToArgvW.argtypes = (ctypes.c_wchar_p, ctypes.c_void_p) + CommandLineToArgvW.restype = ctypes.c_void_p + + args = GetCommandLineW() + # if args != NULL + if args: + try: + numArgs = ctypes.c_int() + argv_address = CommandLineToArgvW(args, ctypes.byref(numArgs)) + + # if argv_address != NULL + if argv_address: + try: + argvArrayType = ctypes.c_wchar_p * numArgs.value + argvArray = argvArrayType.from_address(argv_address) + argv = tuple(unicode(arg) for arg in argvArray) + finally: + # Free the memory in argv_address + LocalFree(argv_address) + finally: + # Free this memory since it isn't needed + LocalFree(args) + + + # Drop the first argument (since this the call to the python interperator + return argv[1:] + +sys.unicode_argv = getUnicodeArgs() + + +# Taken from the Platform SDK +SPI_SETDESKWALLPAPER = 20 +SPIF_SENDWININICHANGE = 2 + +# Resize an image (returns a new image) +def resize(image, (outputWidth, outputHeight), + fillBoundingBox = False, + cropImage = True, + method = Image.BICUBIC): + + imgWidth, imgHeight = image.size + + if (imgHeight == outputHeight) and (imgWidth == outputWidth): + return image + + aspectRatio = imgHeight / imgWidth + outputAspectRatio = outputHeight / outputWidth + + if fillBoundingBox: + if aspectRatio < outputAspectRatio: + newHeight = outputHeight + newWidth = int(outputHeight / aspectRatio) + # (left, upper, right, lower) + offset = (newWidth - outputWidth) // 2 + outputBox = (offset, 0, offset + outputWidth, outputHeight) + else: + newWidth = outputWidth + newHeight = int(outputWidth * aspectRatio) + # (left, upper, right, lower) + offset = (newHeight - outputHeight) // 2 + outputBox = (0, offset, newWidth, offset + outputHeight) + + print >>sys.stderr, "Aspects: ", aspectRatio, outputAspectRatio + print >>sys.stderr, "Output: ", outputWidth, outputHeight + print >>sys.stderr, "Img: ", imgWidth, imgHeight + print >>sys.stderr, "new:", newWidth, newHeight + print >>sys.stderr, "CropBox: ", outputBox + + image = image.resize( (newWidth, newHeight), method) + if cropImage and not\ + ((newHeight == outputHeight) and (newWidth == outputWidth)): + image = image.crop( outputBox ) + else: + raise NotImplementedError + + return image + +# Converts the input image to a bitmap (with optional resizing) +def convertImage(pathToImage, boundingBox = None): + TEMP_FILE = 'pywallpaper.bmp' + newPath = os.path.join(os.getcwd(), TEMP_FILE) + + bmpImg = Image.open(pathToImage) + + if boundingBox is not None: + bmpImg = resize(bmpImg, boundingBox, fillBoundingBox = True) + + # Check the colour space it is in (we only want RGB) + if bmpImg.mode == 'RGBA': + bmpImg = bmpImg.convert('RGB') + + # Save it as a bitmap + bmpImg.save(newPath, "BMP") + + return newPath + +# Actually sets the wallpaper +def updateWall(pathToBMP): + # Parameters for SystemParametersInfoA are: + # (UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni) + user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, + 0, + pathToBMP, + SPIF_SENDWININICHANGE) + +### +# Code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/460509 +# Gets the size of all monitors attached to this computer) +### +class RECT(ctypes.Structure): + _fields_ = [ + ('left', ctypes.c_long), + ('top', ctypes.c_long), + ('right', ctypes.c_long), + ('bottom', ctypes.c_long) + ] + def dump(self): + return map(int, (self.left, self.top, self.right, self.bottom)) + +class MONITORINFO(ctypes.Structure): + _fields_ = [ + ('cbSize', ctypes.c_ulong), + ('rcMonitor', RECT), + ('rcWork', RECT), + ('dwFlags', ctypes.c_ulong) + ] + +def get_monitors(): + retval = [] + CBFUNC = ctypes.WINFUNCTYPE(ctypes.c_int, ctypes.c_ulong, ctypes.c_ulong, ctypes.POINTER(RECT), ctypes.c_double) + def cb(hMonitor, hdcMonitor, lprcMonitor, dwData): + r = lprcMonitor.contents + #print "cb: %s %s %s %s %s %s %s %s" % (hMonitor, type(hMonitor), hdcMonitor, type(hdcMonitor), lprcMonitor, type(lprcMonitor), dwData, type(dwData)) + data = [hMonitor] + data.append(r.dump()) + retval.append(data) + return 1 + cbfunc = CBFUNC(cb) + temp = user32.EnumDisplayMonitors(0, 0, cbfunc, 0) + #print temp + return retval + +def monitor_areas(): + retval = [] + monitors = get_monitors() + for hMonitor, extents in monitors: + data = [hMonitor] + mi = MONITORINFO() + mi.cbSize = ctypes.sizeof(MONITORINFO) + mi.rcMonitor = RECT() + mi.rcWork = RECT() + res = user32.GetMonitorInfoA(hMonitor, ctypes.byref(mi)) + data.append(mi.rcMonitor.dump()) + data.append(mi.rcWork.dump()) + retval.append(data) + return retval + +### +# End code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/460509 +### + +def main(): + def getPrimarySize(): + monitors = monitor_areas() + monitorID, size, workingSize = monitors[0] + sizeLeft, sizeTop, sizeRight, sizeBottom = size + return (sizeRight - sizeLeft, sizeBottom - sizeTop) + + pathToBMP = convertImage(sys.unicode_argv[1], getPrimarySize()) + updateWall(pathToBMP) + +if __name__ == '__main__': + main() -- 2.39.2