# 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()