def readBool(text): reply = wireutils.color_input(text + ' (y/n): ') if reply == 'y': return True elif reply == 'n': return False else: print wireutils.color_print("Invalid option. Please answer y or n for yes or no.\n", color = wireutils.ansi_colors.RED) return readBool(text)
def checkModule(name): installed = hasModule(name) if installed: if not args.get("quiet") and args.get("clean"): print wireutils.format("m {name}: y", name = name) elif not args.get("quiet"): wireutils.color_print("Module {name} installed.", name = name, color = wireutils.ansi_colors.GREEN) else: if args.get("clean"): print wireutils.format("m {name}: n", name = name) else: wireutils.color_print("Module {name} not installed.", name = name, color = wireutils.ansi_colors.RED) return installed
def checkApplication(name, friendlyName, tutorial): installed = spawn.find_executable(name) != None if installed: if not args.get("quiet") and args.get("clean"): print wireutils.format("a {name}: y", name = name) elif not args.get("quiet"): wireutils.color_print("Executable {name} ({readable}) found.", name = name, readable = friendlyName, color=wireutils.ansi_colors.GREEN) else: if args.get("clean"): print wireutils.format("a {name}: n", name = name) else: wireutils.color_print("Executable {name} ({readable}) not found.", name = name, readable = friendlyName, color=wireutils.ansi_colors.RED) if not installed and not args.get("dry"): manualInstallNotify(friendlyName, tutorial)
ICON = os.path.join(dirname, os.path.pardir, "icon_glow.png") LOGO = os.path.join(dirname, os.path.pardir, "icon_plain.png") VERSION = 'Perdyshot ' + open(os.path.join(dirname, os.path.pardir, '.version'), 'r').read() URL = "https://github.com/Locercus/Perdyshot" DATE = os.path.getmtime(os.path.join(dirname, os.path.pardir, ".version")) DATE = datetime.fromtimestamp(DATE).strftime(locale.nl_langinfo(locale.D_T_FMT)) if Notify: Notify.init("Perdyshot") config = ConfigObj(os.path.join(dirname, os.path.pardir, 'perdyshot.conf'), encoding = 'UTF8', configspec = os.path.join(dirname, os.path.pardir, 'perdyshot.conf.spec')) validator = Validator() if not config.validate(validator): wireutils.color_print("Invalid configuration file", color = wireutils.ansi_colors.DARKRED) sys.exit(1) settings = {} settings['modes'] = config['GUI']['CaptureModes'] app = QtGui.QApplication(sys.argv) # Create about dialog class AboutDialog(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.setFixedSize(450, 240) self.setWindowTitle("About Perdyshot")
def main(argSource): cwd = os.getcwd() app = QtGui.QApplication(sys.argv) version = 'Perdyshot ' + open(os.path.join(dirname, os.path.pardir, '.version'), 'r').read() parser = argparse.ArgumentParser(description = 'Takes a perdy screenshot of an area selection.') parser.add_argument('-f', '--file', help = 'overrides setting in perdyshot.conf', default = None) parser.add_argument('-v', '--version', action = 'version', version = version) args = vars(parser.parse_args(argSource)) config = ConfigObj(os.path.join(dirname, os.path.pardir, 'perdyshot.conf'), encoding = 'UTF8', configspec = os.path.join(dirname, os.path.pardir, 'perdyshot.conf.spec')) validator = Validator() if not config.validate(validator): wireutils.color_print("Invalid configuration file", color = wireutils.ansi_colors.DARKRED) sys.exit(1) settings = {} settings['filename'] = config['Settings']['filename'] PressMode = Enum('PressMode', 'Dragging KeyDragging CreateResizeCenter Creating ResizeLeft ResizeTop ResizeRight ResizeBottom ResizeTopLeft ResizeTopRight ResizeBottomRight ResizeBottomLeft') # Create area screenshot selection window class AreaWindow(QtGui.QWidget): def __init__(self, width, height): QtGui.QWidget.__init__(self) self.setContentsMargins(-1, -1, -1, -1) # Hacky af but it works self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) self.setCursor(Qt.CrossCursor) self.scene = QtGui.QGraphicsScene() self.view = QtGui.QGraphicsView(self.scene) self.view.setFocusPolicy(Qt.NoFocus) self.view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.view.setMouseTracking(True) self.view.mouseMoveEvent = self.mouseMoveEvent self.view.mousePressEvent = self.mousePressEvent self.view.mouseReleaseEvent = self.mouseReleaseEvent self.layout = QtGui.QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.layout.addWidget(self.view) self.setLayout(self.layout) self.background = QtGui.QGraphicsPixmapItem(QtGui.QPixmap(os.path.join(tempfile.gettempdir(), 'perdyselection.png'))) self.scene.addItem(self.background) coverBrush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 128)) coverPen = QtGui.QPen(QtGui.QColor(0, 0, 0, 0)) self.coverLeft = QtGui.QGraphicsRectItem(0, 0, width, height) self.coverLeft.setBrush(coverBrush) self.coverLeft.setPen(coverPen) self.scene.addItem(self.coverLeft) self.coverRight = QtGui.QGraphicsRectItem(0, 0, 0, 0) self.coverRight.setBrush(coverBrush) self.coverRight.setPen(coverPen) self.scene.addItem(self.coverRight) self.coverTop = QtGui.QGraphicsRectItem(0, 0, 0, 0) self.coverTop.setBrush(coverBrush) self.coverTop.setPen(coverPen) self.scene.addItem(self.coverTop) self.coverBottom = QtGui.QGraphicsRectItem(0, 0, 0, 0) self.coverBottom.setBrush(coverBrush) self.coverBottom.setPen(coverPen) self.scene.addItem(self.coverBottom) self.selection = QtGui.QGraphicsRectItem(0, 0, 0, 0) selectionPen = QtGui.QPen(QtGui.QColor(0xffffff)) selectionPen.setStyle(Qt.DashLine) self.selection.setPen(selectionPen) self.scene.addItem(self.selection) self.leftPressed = False self.pressMode = None self.selPos = (0, 0, 0, 0) self.selDims = (0, 0, 0, 0) self.curPos = (0, 0) def mousePressEvent(self, event): x, y = event.x(), event.y() dx, dy, dw, dh = self.selDims button = event.button() if button == Qt.LeftButton: self.leftPressed = True self.pressMode = self.getPositionPressMode(x, y) if self.pressMode == PressMode.Creating: self.selPos = (x, y, 0, 0) self.selDims = (0, 0, 0, 0) self.selection.setRect(x, y, 0, 0) self.coverLeft.setRect(0, 0, self.width(), self.height()) self.coverRight.setRect(0, 0, 0, 0) self.coverTop.setRect(0, 0, 0, 0) self.coverBottom.setRect(0, 0, 0, 0) elif button == Qt.RightButton: self.pressMode = None self.selPos = (0, 0, 0, 0) self.selDims = (0, 0, 0, 0) self.selection.setRect(0, 0, 0, 0) self.coverLeft.setRect(0, 0, self.width(), self.height()) self.coverRight.setRect(0, 0, 0, 0) self.coverTop.setRect(0, 0, 0, 0) self.coverBottom.setRect(0, 0, 0, 0) self.updateCursor() def mouseReleaseEvent(self, event): if event.button() == Qt.LeftButton: self.leftPressed = False self.pressMode = None # Fix mirrored selections self.selPos = self.selDims self.updateCursor() def mouseMoveEvent(self, event): if self.leftPressed: tw, th = self.width(), self.height() x, y, w, h = self.selPos dx, dy, dw, dh = self.selDims mx, my = event.x(), event.y() mxo, myo = self.curPos xDiff = mx - mxo yDiff = my - myo if self.pressMode in [PressMode.Dragging, PressMode.KeyDragging]: x += xDiff y += yDiff elif self.pressMode == PressMode.CreateResizeCenter: x -= xDiff y -= yDiff w += xDiff * 2 h += yDiff * 2 elif self.pressMode == PressMode.Creating: w = event.x() - x h = event.y() - y elif self.pressMode == PressMode.ResizeLeft: x += xDiff w -= xDiff elif self.pressMode == PressMode.ResizeTop: y += yDiff h -= yDiff elif self.pressMode == PressMode.ResizeRight: w += xDiff elif self.pressMode == PressMode.ResizeBottom: h += yDiff elif self.pressMode == PressMode.ResizeTopLeft: x += xDiff y += yDiff w -= xDiff h -= yDiff elif self.pressMode == PressMode.ResizeTopRight: w += xDiff y += yDiff h -= yDiff elif self.pressMode == PressMode.ResizeBottomRight: w += xDiff h += yDiff elif self.pressMode == PressMode.ResizeBottomLeft: x += xDiff w -= xDiff h += yDiff self.selPos = (x, y, w, h) if w < 0: x, w = x + w, -w if h < 0: y, h = y + h, -h self.selDims = (x, y, w, h) self.selection.setRect(x, y, w, h) self.coverLeft.setRect(0, 0, x, th) self.coverRight.setRect(x + w, 0, tw, th) self.coverTop.setRect(x, 0, w, y) self.coverBottom.setRect(x, y + h, w, th - y - h) self.curPos = (event.x(), event.y()) self.updateCursor() def keyPressEvent(self, event): key = event.key() tw, th = self.width(), self.height() x, y, w, h = self.selPos dx, dy, dw, dh = self.selDims if key == Qt.Key_Escape: if __name__ == '__main__': sys.exit() else: self.hide() elif key in [Qt.Key_Enter, Qt.Key_Return]: self.capture(dx, dy, dw, dh) elif key == Qt.Key_Space: if self.pressMode == PressMode.Creating: self.pressMode = PressMode.KeyDragging elif key == Qt.Key_Alt: if self.pressMode == PressMode.Creating: self.pressMode = PressMode.CreateResizeCenter elif key in [Qt.Key_Left, Qt.Key_Up, Qt.Key_Right, Qt.Key_Down]: if self.pressMode is None: diffx = 0 diffy = 0 if key == Qt.Key_Left: diffx = -1 elif key == Qt.Key_Up: diffy = -1 elif key == Qt.Key_Right: diffx = 1 elif key == Qt.Key_Down: diffy = 1 if event.modifiers() & Qt.ShiftModifier: diffx *= 4 diffy *= 4 x += diffx dx += diffx y += diffy dy += diffy self.selPos = (x, y, w, h) self.selDims = (dx, dy, dw, dh) self.selection.setRect(dx, dy, dw, dh) self.coverLeft.setRect(0, 0, x, th) self.coverRight.setRect(x + w, 0, tw, th) self.coverTop.setRect(x, 0, w, y) self.coverBottom.setRect(x, y + h, w, th - y - h) self.updateCursor() def keyReleaseEvent(self, event): key = event.key() if key == Qt.Key_Space: if self.pressMode == PressMode.KeyDragging: self.pressMode = PressMode.Creating elif key == Qt.Key_Alt: if self.pressMode == PressMode.CreateResizeCenter: self.pressMode = PressMode.Creating def getPositionPressMode(self, x, y): dx, dy, dw, dh = self.selDims if x in xrange(dx + 8, dx + dw - 8) and y in xrange(dy + 8, dy + dh - 8): return PressMode.Dragging elif x in xrange(dx - 8, dx + 8) and y in xrange(dy + 8, dy + dh - 8): return PressMode.ResizeLeft elif x in xrange(dx + 8, dx + dw - 8) and y in xrange(dy - 8, dy + 8): return PressMode.ResizeTop elif x in xrange(dx + dw - 8, dx + dw + 8) and y in xrange(dy + 8, dy + dh - 8): return PressMode.ResizeRight elif x in xrange(dx + 8, dx + dw - 8) and y in xrange(dy + dh - 8, dy + dh + 8): return PressMode.ResizeBottom elif x in xrange(dx - 8, dx + 8) and y in xrange(dy - 8, dy + 8): return PressMode.ResizeTopLeft elif x in xrange(dx + dw - 8, dx + dw + 8) and y in xrange(dy - 8, dy + 8): return PressMode.ResizeTopRight elif x in xrange(dx + dw - 8, dx + dw + 8) and y in xrange(dy + dh - 8, dy + dh + 8): return PressMode.ResizeBottomRight elif x in xrange(dx - 8, dx + 8) and y in xrange(dy + dh - 8, dy + dh + 8): return PressMode.ResizeBottomLeft else: return PressMode.Creating # Set the cursor according to its position def updateCursor(self): x, y = self.curPos rx, ry, rw, rh = self.selDims rx2, ry2 = rx + rw, ry + rh mode = self.getPositionPressMode(x, y) if self.pressMode == PressMode.KeyDragging: self.setCursor(Qt.ClosedHandCursor) elif self.pressMode == PressMode.CreateResizeCenter: self.setCursor(Qt.SizeAllCursor) elif self.pressMode == PressMode.Creating or mode == PressMode.Creating: self.setCursor(Qt.CrossCursor) elif mode == PressMode.Dragging: if self.leftPressed: self.setCursor(Qt.ClosedHandCursor) else: self.setCursor(Qt.OpenHandCursor) elif mode in [PressMode.ResizeLeft, PressMode.ResizeRight]: self.setCursor(Qt.SizeHorCursor) elif mode in [PressMode.ResizeTop, PressMode.ResizeBottom]: self.setCursor(Qt.SizeVerCursor) elif mode in [PressMode.ResizeBottomLeft, PressMode.ResizeTopRight]: self.setCursor(Qt.SizeBDiagCursor) elif mode in [PressMode.ResizeTopLeft, PressMode.ResizeBottomRight]: self.setCursor(Qt.SizeFDiagCursor) # Captures the screenshot def capture(self, x, y, w, h): self.hide() filename = args['file'] if args['file'] != None else settings['filename'] filename = time.strftime(filename) image = Image.open(os.path.join(tempfile.gettempdir(), 'perdyselection.png')) image = image.crop((x, y, x + w, y + h)) image.save(filename, 'png') if __name__ == '__main__': sys.exit() areaWindow = None def activate(): screen = gdk.screen_get_default() screenWidth = screen.get_width() screenHeight = screen.get_height() pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, True, 8, screenWidth, screenHeight) screenshot = gdk.Pixbuf.get_from_drawable(pixbuf, gdk.get_default_root_window(), gdk.colormap_get_system(), 0, 0, 0, 0, screenWidth, screenHeight) screenshot.save(os.path.join(tempfile.gettempdir(), 'perdyselection.png'), 'png') areaWindow = AreaWindow(screenWidth, screenHeight) areaWindow.move(0, 0) areaWindow.setFixedSize(screenWidth, screenHeight) areaWindow.show() if __name__ == '__main__': activate() app.exec_()
if __name__ == "__main__": try: try: import argparse parser = argparse.ArgumentParser(description = 'Checks the Perdyshot dependencies.', usage="%(prog)s [options]") parser.add_argument('-o', '--omit', help="Omit an update step", default="", choices=["module", "app", "m", "a"], dest="omit") parser.add_argument('--dry-run', help="Don't actually do anything", action = 'store_true', dest="dry") parser.add_argument('-q', '--quiet', help="Supress most output", action = 'store_true', dest="quiet") parser.add_argument('--porcelain', help="Machine-readable output (implies --dry-run)", action = 'store_true', dest="clean") args = vars(parser.parse_args()) except Exception: wireutils.color_print("Argparse library missing. Will not be able to parse cli arguments.\n", color=wireutils.ansi_colors.DARKRED) args = {} if not args.get("quiet") and not args.get("clean"): wireutils.color_print("""Perdyshot Dependency Checker {bold}============================{endc} """, strip = True) ROOT = os.geteuid() == 0 if not args.get("dry") and not args.get("clean"): if not ROOT: if not readBool("You aren't root.\nInstalling missing packages will not be supported.\nDo you wish to continue?"): sys.exit() print
def main(argSource): cwd = os.getcwd() version = 'Perdyshot ' + open(os.path.join(dirname, os.path.pardir, '.version'), 'r').read() parser = argparse.ArgumentParser(description = 'Takes a perdy screenshot of the active window.') parser.add_argument('-b', '--background', help = 'overrides setting in perdyshot.conf', default = '') parser.add_argument('--delay', help = 'the delay in seconds before capturing the active window (default: 1)', default = 1, type = float) parser.add_argument('-f', '--file', help = 'overrides setting in perdyshot.conf', default = None) parser.add_argument('--round-top', help = "overrides setting in perdyshot.conf", default = None, action = 'store_true') parser.add_argument('--no-round-top', help = "overrides setting in perdyshot.conf", dest = 'round_top', action = 'store_false') parser.add_argument('--round-bottom', help = "overrides setting in perdyshot.conf", type = int, choices = [0, 1, 2], default = None) parser.add_argument('--shadow', help = "overrides setting in perdyshot.conf", default = None) parser.add_argument('--size-bugged', help = "overrides setting in perdyshot.conf", type = int, default = None, choices = [0, 1, 2]) parser.add_argument('-v', '--version', action = 'version', version = version) args = vars(parser.parse_args(argSource)) config = ConfigObj(os.path.join(dirname, os.path.pardir, 'perdyshot.conf'), encoding = 'UTF8', configspec = os.path.join(dirname, os.path.pardir, 'perdyshot.conf.spec')) validator = Validator() if not config.validate(validator): wireutils.color_print("Invalid configuration file", color = wireutils.ansi_colors.DARKRED) sys.exit(1) wireutils.color_print("Please select the window to be captured\n") time.sleep(args['delay']) startTime = time.time() # https://gist.github.com/mozbugbox/10cd35b2872628246140 def pixbuf2image(pix): """Convert gdkpixbuf to PIL image""" data = pix.get_pixels() w = pix.props.width h = pix.props.height stride = pix.props.rowstride mode = "RGB" if pix.props.has_alpha == True: mode = "RGBA" im = Image.frombytes(mode, (w, h), data, "raw", mode, stride) return im # Get the root window root = gdk.screen_get_default() # And its size screenSize = (root.get_width(), root.get_height()) # Get the active window window = root.get_active_window() if window == None: wireutils.color_print("Failed to capture window, exiting.", color = wireutils.ansi_colors.DARKRED) sys.exit(1) # And its geometry x, y = window.get_origin() x -= 1 y -= 1 width, height = window.get_size() # Fix something that may just be specific to my f****d up left monitor if x < 0: x = 0 window.move(x, y) time.sleep(.5) # Get the position of the window decorations decoX, decoY = window.get_root_origin() decoY += 1 # Check if the window has a custom titlebar hascustomtitlebar = (y + 2 == decoY) # Add the dimensions of the decorations to window dimensions width += x - decoX + 1 height += y - decoY - 1 windowType = window.get_type_hint() # Get its WM_CLASS WM_CLASS = window.property_get('WM_CLASS')[2].split('\x00')[0] # Read the config file and figure out the settings settings = {} if config['Settings']['background'] == "False": settings['background'] = False else: settings['background'] = config['Settings']['background'] settings['shadow'] = config['Settings']['shadowColour'] settings['filename'] = config['Settings']['filename'] if config['Settings']['cornerImage'] == '': settings['cornerImage'] = None else: settings['cornerImage'] = Image.open(os.path.join(dirname, config['Settings']['cornerImage'])) if config['Settings']['cornerImageDM'] == '': settings['cornerImageDM'] = None else: settings['cornerImageDM'] = Image.open(os.path.join(dirname, config['Settings']['cornerImageDM'])) if config['Settings']['borderImage'] == '': settings['borderImage'] = None else: settings['borderImage'] = Image.open(os.path.join(dirname, config['Settings']['borderImage'])) if config['Settings']['borderImageDM'] == '': settings['borderImageDM'] = None else: settings['borderImageDM'] = Image.open(os.path.join(dirname, config['Settings']['borderImageDM'])) if WM_CLASS in config['Applications']: app = config['Applications'][WM_CLASS] settings['sizeBugged'] = app['sizeBugged'] settings['roundTop'] = app['roundTop'] if settings['roundTop'] == None: settings['roundTop'] = not hascustomtitlebar settings['roundBottom'] = app['roundBottom'] if settings['roundBottom'] == None: if hascustomtitlebar: settings['roundBottom'] = 0 else: settings['roundBottom'] = 2 else: settings['sizeBugged'] = False settings['roundTop'] = not hascustomtitlebar if hascustomtitlebar: settings['roundBottom'] = 0 else: settings['roundBottom'] = 2 # Add the border size width += settings['borderImage'].size[0] height += settings['borderImage'].size[1] # Get pixbuf pixbuf = gdk.Pixbuf(gdk.COLORSPACE_RGB, True, 8, width, height) # Screenshot the window (and its decorations) screenshot = gdk.Pixbuf.get_from_drawable(pixbuf, gdk.get_default_root_window(), gdk.colormap_get_system(), decoX, decoY, 0, 0, width, height) # Convert it to a PIL image image = pixbuf2image(screenshot) # Find out how long it took partialTime = time.time() # Get the geometry of the window's monitor monitorid = root.get_monitor_at_window(window) monitor = root.get_monitor_geometry(monitorid) geometry = window.get_geometry() bounds = window.get_frame_extents() # This is an estimate by a long-shot, but it's usually about right # At least on Pantheon, the gtk.gdk.WINDOW_STATE_MAXIMIZED state isn't set, so we resort to this maximized = height + 31 >= monitor.height and bounds.y - monitor.y + bounds.height == monitor.height sizeBugged = args['size_bugged'] if args['size_bugged'] != None else settings['sizeBugged'] if sizeBugged == 1 or (sizeBugged == 2 and not(windowType & gdk.WINDOW_TYPE_HINT_DIALOG)): if not maximized: if windowType & gdk.WINDOW_TYPE_HINT_DIALOG: image = image.crop((37, 27, width - 38, height - 48)) width -= 38 + 37 height -= 48 + 27 else: image = image.crop((50, 38, width - 51, height - 62)) width -= 51 + 50 height -= 62 + 38 # Fix borders pixels = image.load() roundTop = args['round_top'] if args['round_top'] != None else settings['roundTop'] roundBottom = args['round_bottom'] if args['round_bottom'] != None else settings['roundBottom'] roundBottom = (roundBottom == 1 or (roundBottom == 2 and (maximized or windowType & gdk.WINDOW_TYPE_HINT_DIALOG))) # Apply deletion maps cornerDeleteMapSize = (0, 0) if settings['cornerImageDM'] != None: cornerDeleteMap = settings['cornerImageDM'].load() cornerDeleteMapSize = settings['cornerImageDM'].size for deleteColumn in xrange(0, cornerDeleteMapSize[0]): for deleteRow in xrange(0, cornerDeleteMapSize[1]): if cornerDeleteMap[deleteColumn, deleteRow][3] > 0: if roundTop: # Top left pixels[deleteColumn, deleteRow] = (0, 0, 0, 0) # Top right pixels[width - deleteColumn - 1, deleteRow] = (0, 0, 0, 0) if roundBottom: # Bottom left pixels[deleteColumn, height - deleteRow - 1] = (0, 0, 0, 0) # Bottom right pixels[width - deleteColumn - 1, height - deleteRow - 1] = (0, 0, 0, 0) if settings['borderImageDM'] != None: borderDeleteMap = settings['borderImageDM'].load() borderDeleteMapSize = settings['borderImageDM'].size for imx in xrange(0, width, borderDeleteMapSize[0]): for deleteColumn in xrange(0, borderDeleteMapSize[0]): for deleteRow in xrange(0, borderDeleteMapSize[1]): if borderDeleteMap[deleteColumn, deleteRow][3] > 0: # Top if not (roundTop and imx in xrange(cornerDeleteMapSize[0] - 1, width - cornerDeleteMapSize[0] - 1)): pixels[imx + deleteColumn, deleteRow] = (0, 0, 0, 0) # Bottom if not (roundBottom and imx in xrange(cornerDeleteMapSize[0] - 1, width - cornerDeleteMapSize[0] - 1)): pixels[imx + deleteColumn, height - deleteRow - 1] = (0, 0, 0, 0) for imy in xrange(0, height, borderDeleteMapSize[1]): # TODO: Rotate the image for deleteColumn in xrange(0, borderDeleteMapSize[0]): for deleteRow in xrange(0, borderDeleteMapSize[1]): if borderDeleteMap[deleteColumn, deleteRow][3] > 0: # Left if not ((roundTop and imy < cornerDeleteMapSize[1] - 1) or (roundBottom and imy > height - cornerDeleteMapSize[1] - 1)): pixels[deleteColumn, imy + deleteRow] = (0, 0, 0, 0) # Right if not ((roundTop and imy < cornerDeleteMapSize[1] - 1) or (roundBottom and imy > height - cornerDeleteMapSize[1] - 1)): pixels[width - deleteColumn - 1, imy + deleteRow] = (0, 0, 0, 0) # Apply overlay images cornerImageSize = (0, 0) if settings['cornerImage'] != None: cornerImage = settings['cornerImage'] cornerImageSize = cornerImage.size if roundTop: imageTopLeft = cornerImage.copy() image.paste(imageTopLeft, (0, 0), imageTopLeft) imageTopRight = ImageOps.mirror(cornerImage) image.paste(imageTopRight, (width - cornerImageSize[0], 0), imageTopRight) if roundBottom: imageBottomLeft = ImageOps.flip(cornerImage) image.paste(imageBottomLeft, (0, height - cornerImageSize[1]), imageBottomLeft) imageBottomRight = ImageOps.flip(ImageOps.mirror(cornerImage)) image.paste(imageBottomRight, (width - cornerImageSize[0], height - cornerImageSize[1]), imageBottomRight) if settings['borderImage'] != None: borderImage = settings['borderImage'] borderImageSize = borderImage.size for imx in xrange(1, width, borderImageSize[0]): # Top if not roundTop or imx in xrange(cornerImageSize[0], width - cornerImageSize[0]): borderImageCopy = borderImage.copy() image.paste(borderImageCopy, (imx, 0), borderImageCopy) # Bottom if not roundBottom or imx in xrange(cornerImageSize[0], width - cornerImageSize[0]): borderImageCopy = ImageOps.flip(borderImage) image.paste(borderImageCopy, (imx, height - 1), borderImageCopy) rangeStartY = 1 if roundTop: rangeStartY = cornerImageSize[1] - 1 rangeEndY = height - 1 if roundBottom: rangeEndY = height - cornerImageSize[1] for imy in xrange(rangeStartY, rangeEndY, borderImageSize[0]): # Left borderImageCopy = borderImage.rotate(90) image.paste(borderImageCopy, (0, imy), borderImageCopy) # Right borderImageCopy = borderImage.rotate(270) image.paste(borderImageCopy, (width - 1, imy), borderImageCopy) # Save the image with PIL for modification with ImageMagick image.save(os.path.join(tempfile.gettempdir(), 'perdywindow.png'), 'png') # Apply a shadow shadowColour = args['shadow'] if args['shadow'] != None else settings['shadow'] command = "convert " + os.path.join(tempfile.gettempdir(), 'perdywindow.png') + " -bordercolor none -border 64x64 -repage +48+48 \( +clone -background \"" + shadowColour + "\" -shadow 100x24+0+32 \) +swap -background none -mosaic" # Change the background if necessary background = args['background'] if args['background'] != '' else settings['background'] if background != '' and background != False: command += " -background \"" + background + "\" -alpha remove" # Apply our magick to our image and save it to a file filename = args['file'] if args['file'] != None else settings['filename'] filename = time.strftime(filename) subprocess.check_output(command + " " + filename, shell = True) totalTime = time.time() print # An empty line. wireutils.color_print("Screenshot time: %.2f seconds" % (partialTime - startTime)) wireutils.color_print("Post-processing time: %.2f seconds" % (totalTime - partialTime)) wireutils.color_print("Total time: %.2f seconds" % (totalTime - startTime)) print wireutils.color_print("Saved as {name}.", name = filename)