February 24, 2021 at 3:09 PM by Dr. Drang
Last night, I made some long-overdue updates to my Keyboard Maestro screenshot macro, SnapClip.
Running SnapClip (through ⌃⌥⌘4) starts out like taking a screenshot with ⇧⌘4. You can choose a rectangular portion of the screen or a particular window. It then asks if you want to save the file to the Desktop or put a border around the image (which improves the look of full-window screenshots).
Whatever you choose, it puts the image on the clipboard, which is convenient if the reason you took the screenshot was to paste it into an application.
The biggest change is switching from Python 2, the only version of Python that came with OS X/macOS until Catalina, to Python 3. That meant installing the Pillow module for Python 3, which I did from the command line via
sudo /usr/bin/python3 -m pip install --upgrade Pillow
With that done, I edited the Python script that makes up the single step of my SnapClip macro:
1: #!/usr/bin/python3 2: 3: import Pashua 4: import tempfile 5: from PIL import Image 6: import sys, os 7: import subprocess 8: import shutil 9: from datetime import datetime 10: 11: # Local parameters 12: type = "png" 13: localdir = os.environ['HOME'] + "/Pictures/Screenshots" 14: tf, tfname = tempfile.mkstemp(suffix='.'+type, dir=localdir) 15: bgcolor = (85, 111, 137) 16: border = 16 17: desktop = os.environ['HOME'] + "/Desktop/" 18: fname = desktop + datetime.now().strftime("%Y%m%d-%H%M%S." + type) 19: impbcopy = os.environ['HOME'] + '/Dropbox/bin/impbcopy' 20: optipng = '/opt/homebrew/bin/optipng' 21: 22: # Dialog box configuration 23: conf = b''' 24: # Window properties 25: *.title = Snapshot 26: 27: # Border checkbox properties 28: bd.type = checkbox 29: bd.label = Add background 30: bd.x = 10 31: bd.y = 60 32: 33: # Save file checkbox properties 34: sf.type = checkbox 35: sf.label = Save file to Desktop 36: sf.x = 10 37: sf.y = 35 38: 39: # Default button 40: db.type = defaultbutton 41: db.label = Clipboard 42: 43: # Cancel button 44: cb.type = cancelbutton 45: ''' 46: 47: # Capture a portion of the screen and save it to a temporary file. 48: status = subprocess.call(["screencapture", "-io", "-t", type, tfname]) 49: 50: # Exit if the user canceled the screencapture. 51: if not status == 0: 52: os.remove(tfname) 53: sys.exit() 54: 55: # Open the dialog box and get the input. 56: dialog = Pashua.run(conf) 57: if dialog['cb'] == '1': 58: os.remove(tfname) 59: sys.exit() 60: 61: # Add a desktop background border if asked for. 62: snap = Image.open(tfname) 63: if dialog['bd'] == '1': 64: # Make a solid-colored background bigger than the screenshot. 65: snapsize = tuple([ x + 2*border for x in snap.size ]) 66: bg = Image.new('RGBA', snapsize, bgcolor) 67: bg.alpha_composite(snap, dest=(border, border)) 68: bg.save(tfname) 69: 70: # Optimize the file. 71: subprocess.call([optipng, '-quiet', tfname]) 72: 73: # Put the image on the clipboard. 74: subprocess.call([impbcopy, tfname]) 75: 76: # Save to Desktop if asked for. 77: if dialog['sf'] == '1': 78: shutil.copyfile(tfname, fname) 79: 80: # Delete the temporary file 81: os.remove(tfname)
There are five changes to the script:
- The obvious change is the switch to Python 3 in the shebang line.
- Because I revamped my Homebrew setup, the location of the OptiPNG binary has changed from
/opt/homebrew/bin/. That change is reflected in Line 20.
- Big Sur eliminated Solid Aqua Blue from its list of standard Desktop colors, so I made a small change to the color of my Desktop, and I wanted that change reflected in the background color SnapClip uses when creating a full-window screenshot. The new background color is set in Line 15.
- I changed the wording of one of the labels in the dialog box that appears after the screenshot is taken. That change is in Line 29.
Recent versions of macOS have rounded the corners of windows, and SnapClip didn’t handle that properly in full-window screenshots. It used to use the Pillow
pastefunction to overlay the window image onto the Desktop color. There was no accounting for transparency. That worked fine when Mac windows had square corners, but not with rounded corners, as you can see here:
The solution was to change the solid-color background image’s mode from RGB to RGBA (RGB with an alpha channel) in Line 66 and overlay the window image on Line 67 with the
alpha_compositefunction instead of
paste. That got rid of the little black triangles at every corner.
It’s been about four years since I last tweaked SnapClip. With luck, I’ll get the same amount of time out of this update.