Improved Mac screenshot/upload utility
July 16, 2009 at 5:30 PM by Dr. Drang
I’ve made a couple of improvements to my screenshot/upload utility, snapftp
. Snapftp
is what I use in place of the Mac’s built-in ⌘⇧4 (Command-Shift-4) screenshot facility. The advantages of snapftp
are:
- It allows me to name the screenshot as I take it.
- It can resize the screenshot on the fly.
- It can create both a thumbnail and a full-sized version of the screenshot.
- It can automatically upload the image file(s) to my blog.
- It puts the URL(s) of the uploaded file(s) on my clipboard for later pasting in a blog post.
- It optimizes the images for reduced file size.
Using snapftp
Snapftp
has a simple but efficient GUI for setting the file name and size of the screenshot.
I invoke snapftp
through FastScripts using the ⌃⌥⌘4 (Control-Option-Command-4) keyboard shortcut, but it could also be invoked though Quicksilver or LaunchBar. After I set the file name and options and click the Snap button, the snapftp
window disappears and the cursor turns into a camera. Putting the camera over any window on the screen and clicking the mouse button takes the screenshot and does whatever resizing and uploading I requested. If I want a screenshot of some arbitrary rectangular area of the screen rather than a window, I push the spacebar to turn the camera cursor into a set of crosshairs and drag out the desired rectangle. (Snapftp
’s use of the camera and crosshairs cursor is basically the same as that of ⌘⇧4, only inverted. I made the camera the default because I’m more likely to take screenshots of windows than of arbitrary rectangles.)
The screenshot files appear on my Desktop and, unless I set the “Local files only” option, in the images
subdirectory here on my blog. The images are in PNG format; that’s the default for OS X since Tiger (10.4).
Building snapftp
Snapftp
is written in Python and uses three command-line utilities that come standard with OS X:
screencapture
for doing the screenshot itself;sips
for resizing the image; andpbcopy
for putting the URLs on the clipboard.
It also uses two programs that aren’t standard on the Mac:
These have to be downloaded and installed before running snapftp
.
Pashua comes in two parts: an application that you put in /Applications
, and a Python module, Pashua.py
, that you put in /Library/Python/2.5/site-packages
. As I said in my earlier snapftp
post, I think you should comment out Line 199 of Pashua.py
196 # Parse result
197 ResultDict = {}
198 for Line in Result:
199 # print Line
200 Parm, Value = Line.split('=')
201 ResultDict[Parm] = Value.rstrip()
because a library function that’s intended to read lines shouldn’t be printing anything.
OptiPNG needs to be compiled. Assuming you have the Developer Tools installed, download and extract the tarball and execute
./configure
make
sudo make install
from within the optipng-0.6.3
directory. The optipng
binary and man page will be put in /usr/local
.
Once Pashua and OptiPNG are installed, you’re ready for snapftp
. It consists of this single relatively short Python file:
1 #!/usr/bin/python
2
3 import Pashua
4 import sys, os, shutil
5 from subprocess import *
6 from ftplib import *
7
8 # FTP and local parameters
9 host = "leancrew.com"
10 baseurl = "http://www.leancrew.com/all-this/images"
11 extension = ".png"
12 user = "drdrang"
13 passwd = "blahblah" # no, not my real password
14 ftpdir = "public_html/all-this/images"
15 localdir = os.environ['HOME'] + "/Desktop"
16
17 # Dialog box configuration
18 conf = '''
19 # Window properties
20 *.title = Snapshot FTP
21
22 # File name text field properties
23 fn.type = textfield
24 fn.default = snap
25 fn.width = 264
26 fn.x = 94
27 fn.y = 130
28 fnl.type = text
29 fnl.default = File name:
30 fnl.x = 20
31 fnl.y = 132
32
33 # Radio button group properties
34 rb.type = radiobutton
35 rb.option = Original
36 rb.option = Resized
37 rb.option = Both
38 rb.default = Original
39 rb.x = 94
40 rb.y = 52
41 rbl.type = text
42 rbl.default = Capture:
43 rbl.x = 30
44 rbl.y = 92
45
46 # Resized width text field properties
47 rw.type = textfield
48 rw.default = 450
49 rw.height = 22
50 rw.width = 60
51 rw.x = 263
52 rw.y = 71
53 rwl.type = text
54 rwl.default = width:
55 rwl.width = 50
56 rwl.x = 215
57 rwl.y = 73
58
59 # Local files checkbox properties
60 lf.type = checkbox
61 lf.label = Local files only
62 lf.x = 32
63 lf.y = 5
64
65 # Default button
66 db.type = defaultbutton
67 db.label = Snap
68
69 # Cancel button
70 cb.type = cancelbutton
71 '''
72
73 # Open the dialog box and get the input.
74 dialog = Pashua.run(conf)
75 if dialog['cb'] == '1':
76 sys.exit()
77
78 # Go to the localdir.
79 os.chdir(localdir)
80
81 # Set the filenames and url.
82 fn = '%s.png' % dialog['fn']
83 fnt = '%s-t.png' % dialog['fn']
84 url = '%s/%s' % (baseurl, fn)
85
86 # Capture a portion of the screen and save it to the file.
87 Popen(["screencapture", "-iW", fn], stdout=PIPE).communicate()
88
89 # Resize the file or create a separate thumbnail if requested.
90 if dialog['rb'] == 'Resized':
91 Popen(['sips', '--resampleWidth', dialog['rw'], fn],
92 stdout=PIPE).communicate()
93 elif dialog['rb'] == 'Both':
94 shutil.copy(fn, fnt)
95 Popen(['sips', '--resampleWidth', dialog['rw'], fnt],
96 stdout=PIPE).communicate()
97 # Optimize the thumbnail.
98 Popen(['optipng', '-quiet', fnt], stdout=PIPE).communicate()
99
100 # Optimize the main file.
101 Popen(['optipng', '-quiet', fn], stdout=PIPE).communicate()
102
103 # Upload the file(s) and put the URL(s) on the clipboard unless told not to.
104 if dialog['lf'] != '1':
105 Popen('pbcopy', stdin=PIPE).communicate('%s/%s' % (baseurl, fn))
106 ftp = FTP(host, user, passwd)
107 ftp.cwd(ftpdir)
108 ftp.storbinary("STOR %s" % fn, open(fn, "rb"))
109 if dialog['rb'] == 'Both':
110 ftp.storbinary("STOR %s" % fnt, open(fnt, "rb"))
111 Popen('pbcopy', stdin=PIPE).communicate('%s/%s' % (baseurl, fnt))
112 ftp.quit()
Obviously, you’ll need to change the things in Lines 8–15 to fit your situation. You may also want to change the resize default width in Line 48. I use a 450-pixel width because that’s a good match to the content area of this blog.
I won’t repeat the description of the code given in my original post, but I will describe the changes between then and now. The most important change is the addition of image optimization. The images produced by screencapture
(Line 87) are a bit bloated. Lines 98 and 101 run the image files through optipng
before uploading. These lines change the files in place; the original is overwritten by the optimized version.
The only switch passed to optipng
is -quiet
to keep it from spitting out progress messages. If you look at the optipng
manual, you’ll see that it has many other options, mainly for controlling the optimization. At the moment, I don’t know much about these controls, so I’m just going with the defaults—that may change as I learn more. In my tests so far, the default optimization is reducing file sizes by 20–30%.
The other change from the original snapftp
is in its use of the clipboard. Line 105 puts the URL of the uploaded image file onto the clipboard. That was all the original snapftp
did. Now, if the user asks for a thumbnail as well (by clicking the “Both” radio button), Line 111 puts the URL for the thumbnail image file onto the clipboard. On most Macs, that would overwrite the first URL, but because I use Jumpcut, I get both URLs in my Clipboard history and can easily paste both of them into my blog posts. I’m pretty sure this will work for anyone using a Clipboard history utility—LaunchBar, iClip, Butler, etc.—but I’ve only tested it with Jumpcut.
Productivity and customization
If you like to edit and annotate your screenshots with comments and arrows and circles and things, you’ll probably be more productive with something like ImageWell. But if you take and upload lots of raw screenshots, snapftp
will save you lots of time, especially if you dig into the source code and customize it to your specific needs. For example:
- If you want your screenshots’ default names to include a time and date code, you can use Python’s
datetime
module to get a timestamp and use that instead of “snap” in Line 24. - If you prefer the default screenshot to be of a rectangular area instead of a window, you can change the
"-iW"
option in Line 87 to"-i"
. - If you’re more concerned with your images’ height than their width, you can change the
"--resampleWidth"
options in Lines 91 and 95 to"--resampleHeight"
. - If you want to restrict the size of the longest dimension, whether width or height, you can change Lines 91 and 95 to use
"--resampleHeightWidthMax"
. - If you don’t like your Desktop cluttered with screenshot files, you can change Line 15 to put them in some other folder.
These are just the simple customizations that come to mind. If you make your own version of snapftp
, I’d like to hear about it.