Improved screenshot statusbar cleaner

My plan worked. Federico Viticci, after seeing my post about cleaning up iOS screenshots with Python and the Python Imaging Library, couldn’t resist moving it into Pythonista and getting it to work directly on iOS. Even better, David Cross joined in, and between the two of them there was almost nothing left for me to do.

Here’s my latest incarnation of the Mac version of the script, which I’ve decided, in an excess of cleverness, to call statusbare:

python:
 1:  #!/usr/bin/python
 2:  
 3:  from __future__ import division
 4:  import Image
 5:  import sys, os
 6:  
 7:  # Dictionary of file names keyed to width and color.
 8:  barfiles = {(640, "black"): "640b.png",
 9:              (640, "white"): "640w.png",
10:              (1136, "black"): "1136b.png",
11:              (1136, "white"): "1136w.png"}
12:  
13:  # Where the statusbar files are.
14:  folder = os.environ["HOME"] + "/graphics/"
15:  
16:  # Open the screenshot and fill its statusbar with the background color.
17:  screenshot = Image.open(sys.argv[1])
18:  width = screenshot.size[0]
19:  bar = (0, 0, width, 40)
20:  barcolor = screenshot.getpixel((0, 0))[:3]
21:  screenshot.paste(barcolor, bar)
22:  
23:  # Decide whether the overlay text and graphics should be black or white.
24:  if sum(barcolor)/3 > 192:
25:    textcolor = "black"
26:  else:
27:    textcolor = "white"
28:  statusbar = Image.open(folder + barfiles[(width, textcolor)])
29:  
30:  # Paste the overlay and save.
31:  screenshot.paste(statusbar, bar, statusbar)
32:  screenshot.save(sys.argv[1])

The basics are the same as the earlier version, but there are a few differences:

  1. I have four versions of the overlay statusbar: black and white for both portrait and landscape. The names of the files are based on their width and color. This could be extended to versions for the iPad, including non-Retina resolutions, and if I had an iPad I’d do it. As it is, I’ll leave the creation of those other files as an exercise for the reader.
  2. I’m using a dictionary to select the overlay file instead of an if/then/else construct. This is a useful technique when you have to choose one of several alternatives. As you can see in Lines 8–11, the keys are (width, color) tuples. This seemed like the most natural key to use, as that’s what the file choice depends on.
  3. I’ve changed the rule for deciding whether to use a black or white overlay. One of the changes is to fix a mistake. I thought the getpixel method in Line 20 returned a (red, green, blue) tuple; I later learned that it returns a (red, green, blue, alpha) tuple with the alpha set to 255. Summing these values and dividing by three in Line 24 didn’t give me the average of the colors. So I changed Line 20 to what it is now, and barcolor has only the three color elements.

    I’ve also changed the limit for deciding whether a background should have black or white text and graphics in the statusbar. The average color value used to be 127, but after testing it with several apps, I decided that black is generally used with distinctly lighter backgrounds, so I bumped it up to 192. This could change in the future if I learn that it chooses the wrong color for some app.

OK, let’s move to the more exciting stuff: cleaning the screenshot directly on iOS via Pythonista. Much of the script is the same; for the Pythonista-specific stuff, I cribbed from this script from Federico.

Here’s the Pythonista version of Statusbare:

python:
 1:  #!/usr/bin/python
 2:   
 3:  from __future__ import division
 4:  import Image
 5:  import sys, os
 6:  import photos, clipboard, console
 7:   
 8:  # Dictionary of file names keyed to width and color.
 9:  barfiles = {(640, "black"): "640b.png",
10:              (640, "white"): "640w.png",
11:              (1136, "black"): "1136b.png",
12:              (1136, "white"): "1136w.png"}
13:   
14:  # Where the status bar files are.
15:  folder = os.environ['HOME'] + '/Documents/'
16:   
17:  # Open the screenshot and fill its statusbar with the background color.
18:  screenshot = photos.pick_image()
19:  width = screenshot.size[0]
20:  bar = (0, 0, width, 40)
21:  barcolor = screenshot.getpixel((0, 0))
22:  screenshot.paste(barcolor, bar)
23:   
24:  # Decide whether the overlay text and graphics should be black or white.
25:  if sum(barcolor[:3])/3 > 192:
26:    textcolor = "black"
27:  else:
28:    textcolor = "white"
29:   
30:  statusbar = Image.open(folder + barfiles[(width, textcolor)])
31:   
32:  # Paste the overlay and save.
33:  screenshot.paste(statusbar, bar, statusbar)
34:  console.clear()
35:  screenshot.show()

I’ve made a Gist of the script, so you can import it directly into Pythonista if you have this other script.

The main differences with the Mac version are:

  1. The overlay files are in Pythonista’s own Documents folder, which is accessed through the path given in Line 15. How do you put files into that folder? There are several ways, including jailbreaking, but I used iFunBox, a free Mac application. Open it, navigate to the Pythonista Documents folder, and drag your files into it.
  2. The screenshot is chosen by the standard iOS photo picker in Line 18.
  3. The cleaned screenshot is displayed in the Pythonista Console via PIL’s show method in Line 35. You can then tap and hold on the image to get a popup that allows you to either save the new image to your Camera Roll or put it on the clipboard.

    Cleaned screenshot in Pythonista

You might be wondering why I don’t just save the cleaned screenshot to the Camera Roll with the save_image method from Pythonista’s photos module. As Federico and David discovered, using save_image saves the image as a JPEG, not a PNG, and it gets contaminated by compression artifacts in the process. David found the show trick:

@viticci @olemoritz
Tested:
Photos.save_image() saves as JPG.
Image.show() and then “save image” saves as PNG with no artifacts

David Cross (@roguemonk) Mon Nov 4 2013 9:22 PM CST

I wouldn’t be surprised if Ole Moritz changes the save_image behavior in the near future. Even if he does, I’ll probably stick with the show technique because it gives me the option of putting the image on the clipboard—useful when I want to mail a cleaned image without keeping a copy around.

I suppose I should mention the design I chose for the overlays. After experimenting with ANIAT as the carrier, I decided to go with the Apple logo because it looks better and is more universal. As for the time, 4:00 PM seemed like a good combination of sharp and round character forms. If you like the design, or want to use it as the basis of your own overlays, you can download a zip file of the images.

Update 11/12/13
The final (as of today) version of this script, with more improvements suggested by readers, can be in this later post.