iOS screenshots of overlays

When presenting choices to a user, iOS has overlays with rounded corners. An example is the overlay that appears when you want to delete an image from the Photos app.

Delete image from Photos app

Officially, these have a few names, depending on their exact look and how they’re used. For modal interaction, there are alerts and modal views; for non-modal (and some modal) interaction, there are popovers. Regardless of the name and the underlying code, they have a similar look, and I often like to include screenshots of them in my posts. I’ve recently come up with a way to do this without leaving a cluttered background in the image.

Immediately after taking a screenshot, it’s easy to crop the image down to nearly the right size, but virtually impossible to crop it down to exactly the right size, because you can’t zoom in with the iOS-supplied cropping tools.

Cropping immediately after screenshot

And even if you could crop precisely to the edges, the rectangular corners would still have wisps of background peeking out from beyond the rounded corners.

My solution is a two-step process:

  1. Use Pixelmator to crop precisely to the edges. This is a “by hand” operation that I just haven’t figured out how to automate.
  2. Use Shortcuts to mask out the rounded corners and, optionally, add a solid gray background. To me, white, or near-white overlays look better against the white background of the blog if they’re set against a darker background.

I typically do an approximate crop right after taking the screenshot, leaving me with something like this:

Approximately cropped screenshot

I then open the image in Pixelmator and crop it down to hit the edges precisely.

Precise cropping in Pixelmator

There is a technique to this. If you zoom in to a corner and then choose the crop tool, Pixelmator will zoom back out before allowing you to crop. This doesn’t hurt anything, but it means you wasted your time by zooming first.

So choose the crop tool and then zoom in to one of the corners. You will almost certainly need to pan during this process, which you must do with two fingers, as Pixelmator interprets all one-finger swipes while in crop mode as directions to move the crop handles. Once you get zoomed in to a corner, use one finger to align the crop with the sides of the rounded corner. This is relatively easy to do because the lines jump one pixel at a time at high zoom.

After cropping the first corner, you’re best bet is to tap the Apply button and then go back into crop mode to do the opposite corner. Every time I’ve tried to crop both corners in a single trip to crop mode, I’ve screwed up the crop while moving from one corner to the other. Inevitably, Pixelmator interprets one of my zoom or pan motions as a one-finger swipe and changes the crop.

Now we have our overlay cropped down to a precisely aligned rectangle, which I save back into the Photos app.

Precisely cropped to a rectangle

It’s time to run the Round Corners shortcut. This is a Share Sheet shortcut that acts on images. It asks the user first for the corner radius to use in the masking.

Corner radius prompt

I set the default radius to 40 pixels because I’ve found that to work reasonably well for most overlays. The rounded corner mask that Shortcuts applies isn’t an exact match for the rounded corners used in overlays. I think that’s because Shortcuts uses a quarter circle for the rounding (hence the need for a radius) and iOS uses a squircle.

The shortcut then asks if a background should be applied. The answer you give determines whether you end up with this

Rounded corners with no background

or this

Overlay with solid gray background

saved to your Photos app.

Here are the steps of the Round Corners shortcut:

Round Corners shortcut

I think the comments do a decent job of explaining what’s going on, but there are two tricks worth noting. First, I’m using Federico Viticci’s technique of embedding a base64-encoded version of the background image into the shortcut itself. It’s there in the Text step a little more than halfway down. Second, to save space, that background image is just a 1×1 pixel image. It gets resized to slightly larger than the target image (20 pixels larger in all four directions) before the overlay is done.

In case you missed it above, here’s the download link for the shortcut.

An obvious improvement would be to get rid of the hand cropping. The OpenCV library, which has bindings for Python, might be a way to grab just the needed portion of the image and would probably handle the masking, too. It works in iOS, but I think you have to be a real developer, not just a scripter, to use it there. I could probably get it running on my Mac or blog server if I dedicate the time to it.

Drafts, Shortcuts, and blogging

For the past several months, almost all of my blog posts have been written on my iPad. My system for publishing the posts, though, was still Mac-based. It consisted of a set of scripts and Makefiles that would compile the Markdown source of the post into HTML and regenerate whatever new pages were needed to update the site. It did all this locally, on the Mac, and then ran rsync to upload the new and altered pages to the blog server. A good system for all those years I was writing posts on the Mac, but less good if I’m going to be writing mostly on the iPad.

To publish a post written on the iPad, I had to get the Markdown source file over to the Mac (Dropbox made this easy) and then I had two choices:

  1. Leave my iPad, go to the Mac and run the publishing scripts. I almost never did this.
  2. Log into my Mac from the iPad using Prompt and run the publishing scripts.

The second option, in which the Mac was basically an intermediary between the iPad and the server, seemed like a waste. So a couple of days ago I moved all the publishing scripts and Makefiles to the server, cutting out the middle man.

My publishing system is a melange of Python and PHP—Python because that’s what I prefer scripting in; PHP because this used to be a WordPress site and I have some custom PHP from those days that I don’t want to rewrite. A few Makefiles control the scripts to ensure that only the pages that need to be regenerated are. A system like this runs as easily on Linux as it does on the Mac, so I just had to add a library or two and change a few paths here and there to get everything working on the server. Then it was time to do some scripting on the iPad.

First, I needed to be able to upload a draft from Drafts to the server. I already had a two-step action for uploading a draft to Dropbox, so I was more than halfway there.

The source code for a post starts with a header that looks something like this:

Title: Drafts, Shortcuts, and blogging
Keywords: drafts shortcuts blogging
Summary: A change to how I blog means new Drafts actions that use Shortcuts.
Date: 2018-12-15 12:10:23
Slug: drafts-shortcuts-and-blogging

The name for the Markdown source file and the folder into which it’s saved are determined by the year, the month, and the slug. The first step in my uploading action is this script:

 1:  // Set template tags for the path and filename
 2:  // of a blog post.
 4:  var d = draft.content;
 6:  // Set up regexes for header info.
 7:  var dateRE = /^Date: (\d\d\d\d)-(\d\d)-\d\d \d\d:\d\d:\d\d$/m;
 8:  var slugRE = /^Slug: (.+)$/m;
10:  // Get the year and month and set the path.
11:  var date = d.match(dateRE);
12:  var year = date[1];
13:  var month = date[2];
14:  var path = '/path/to/blog/source/' + year + '/' + month + '/';
16:  // Get the filename from the slug.
17:  slug = d.match(slugRE)[1];
19:  // Set tags for use in other action steps.
20:  draft.setTemplateTag('source_path', path + slug + ".md");

This is almost identical to the earlier script, so I won’t describe it in full. The main differences are in Line 14, which defined the path on the server to the folder where the Markdown source files are kept, and Line 20, which defines the source_path template tag that will be used in the second step of the action.

Drafts1 has action steps for easily uploading to Dropbox, Google Drive, One Drive, Box, and WebDAV, but not for uploading via SFTP. I could install Dropbox for Linux on the server or maybe get WebDAV working on it, but I didn’t really want to install new stuff on the server just to be able to upload files. I could also switch to using Coda or some other editor on the iPad that handles SFTP, but I wanted to stick with Drafts. Because I already know how to upload files via SFTP in Shortcuts, I decided to use the Run Shortcut action step:

Run Shortcut step for uploading to server

This step call the Upload Blog Source shortcut (which we’ll get to in a minute) and passes to it the source_path template tag that was defined above, a line of 10 carets, and then the full contents of the current draft. As you can probably guess, the line of carets is there to provide a distinct separator that the Upload Blog Source shortcut can parse.

Speaking of the Upload Blog Source shortcut, here it is:

Upload Blog Source shortcut

The second step of the shortcut splits the input text, using ten carets as the separator. This creates a list. The next two steps take the first item of that list, which is the source_path followed by a newline, and strips the trailing whitespace. This output is available to later parts of the shortcut through a magic variable. By default, this magic variable would be named Replace Text, but because there is another Replace Text step in the shortcut, I renamed it sourcePath to avoid confusion. Unfortunately, this renaming is hidden when you take a screenshot of a shortcut, which could be its own source of confusion.

The next three steps return to the list of split items created in Step 2, pull out the last item from it, and strip the leading whitespace. This leaves us with the text of the draft.

Finally, the last step connects to the server and runs the cat command to redirect the standard input passed to the step (the Markdown source) to a file defined by sourcePath.

This is harder to explain than it is to do, but it would be easier if Drafts had a native action step for SFTP. I think I’ll put that bug in Greg Pierce’s ear.

OK, now I have an action that saves a draft to the server. I can use Prompt to log onto the server and run the make command that generates the necessary HTML and publishes the new pages. But wouldn’t it be nicer to just have an action that does that directly from Drafts. Of course it would. This is a single-step action that uses Run Shortcut:

Run Shortcut step from Publish action

Boy, that’s dull. Here’s the shortcut it runs:

Publish shortcut

My Makefile has several sections. By default, when make is run without an argument, it runs the sections needed to publish a new post. When given the up argument, it runs the sections needed to update an already-published post. Thats why there are two options to the Publish shortcut.

Publish shortcut options

Many of you are thinking I could have written a shortcut just like this to log in and run make on my Mac, which would have saved me the trouble of moving all my publishing scripts to the server. You’re right, I could have. But I never did because the incentive wasn’t strong enough. It was only after I put the publishing system on the server—something I’ve been meaning to do for longer than I’ve had an iPad—and needed to solve other problems that I felt compelled to write the publishing shortcut. Motivation is funny.

The obvious drawback to setting things up this way is that I’ve now made it harder to blog from my Mac. But BBEdit knows SFTP, so it won’t be hard to teach it how to upload a file to right place. And there are any number of ways on a Mac to run a command on a remote server. I’ll fill those holes soon.

  1. Which is, by the way, Time Magazine’s #3 app of 2018

An unfortunate hole in my portable brain

This morning I got an email from one of my business partners. She’s out of town on a job and needed our FedEx number sent to another lab so they can ship some samples to us. No problem, I thought, I’m sure I have it on my phone. But no, that was one of those things I always meant to save on my phone but never got around to. My partner thought she had it on her phone, too.

Here are the things I have gotten around to saving to my phone:1

Some of these may seem silly, but I’ve made use of almost all of them at one time or another. A couple of years ago, when my mom moved to a nursing home and I needed to close out certain services at her house, I learned that the phone service was still in my dad’s name. She’d never changed it when he died ten years earlier. So I used his SSN (along with my grandmother’s maiden name, which wasn’t saved to my phone but didn’t need to be) to impersonate him with the phone company and get the account closed. That was a little weird.

(I have since learned that friends my age commonly pretend to be their aging parents to deal with customer service reps. I am, however, the only one I know who pretended to be a dead parent.)

As I look through the list, I see that I still haven’t added things I’ve always meant to. In particular, apart from the FedEx number, I should be keeping the account numbers for various insurance policies.

Up until recently, I’ve had (or intended to have) all of this stuff in secure notes in 1Password. As part of my shift to a more iCloud-based system, I’ve copied them over to locked notes in the Notes app. There have been advantages and disadvantages to the change.

  1. And iPad and Macs, but it’s mostly when I’m out with just my phone that I need them. 

License files for Airtable

Shortly after my software license post went up, Jezper Söderlund tweeted me a very good question: How do you handle software that uses a license file instead of a license key? Turns out there’s a simple answer, and I needed it.

After exporting the licenses from 1Password and importing them into Airtable, I had noticed that the entry for Witch, the better-than-stock app switcher from Many Tricks, had no license key. Weird, I thought, but I didn’t follow up on it. When I saw Jezper’s tweet, I realized why.

Witch does, in fact, use a license file instead of a license key to authorize its use. The license file is buried in the Application Support subfolder of your Library folder. 1Password has a system for adding attachments to software license entries, and I had done that when I bought Witch. Unsurprisingly, the file attachment didn’t get exported to the CSV file. I was a little surprised, though, that the CSV didn’t have a field to indicate there was an attachment for that entry.

In any event, now that I knew I needed to handle file attachments, the solution was simple. I added a new field to my Airtable database and chose the Attachment field type.

Airtable field type

With this field added to the database, it was easy to drag Witch’s license file into Airtable. When you click on an empty attachment field in Safari on the Mac, the field tells you it’s ready to have a file dragged and dropped onto it.

Airtable attachment field in Safari

I scrolled through all the other software licenses in 1Password to see if any others had license files. They didn’t, but now I’m ready to handle any new apps that do.