A SnapClip update

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).

SnapClip dialog box

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.

You can get an overview of SnapClip’s construction and the nonstandard utilities it uses—Pashua, Pillow, impbcopy, and OptiPNG—at the link. Here, I’m just going to talk about the changes.

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:

  1. The obvious change is the switch to Python 3 in the shebang line.
  2. Because I revamped my Homebrew setup, the location of the OptiPNG binary has changed from /usr/local/bin/ to /opt/homebrew/bin/. That change is reflected in Line 20.
  3. 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.
  4. 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.
  5. 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 paste function 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:

    Corner without transparency

    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_composite function 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.