Photocreep

January 22nd, 2017. Tagged: images, JavaScript, react, tools

There's a new tool in town. It lets you drag photos and gives you a map of where the photo was taken. Creepy, isn't it? It figures this out using the meta (exif) information that's part of a photo.

The tool also lets you download a version of the photo without any exif information.

  1. The tool
  2. The code

Photo creep tool

Motivation

Raise awareness of the information people may be sharing involuntarily when they snap a photo on their phones and send it to others.

Implementation

The photocreep tool was built on top of FAIL which lets you build tools like this easily. Tools built with FAIL are PWAs that work offline too. FAIL is built on top of create-react-app which lets you build apps quickly. create-react-app is built on top of React which lets you build UIs in a way that makes sense. To get started with React go get my book. React was built on top of JavaScript which is a programming language that lets you build applications on top of documents on the Web. The Web is built on top of... 🙂

FAIL does not (yet) generate new projects but getting started is kinda trivial. Here's the diff that got me to initial working Photocreep.

The heavy lifting of reading EXIF data is done by exifreader.

The writing of the file without EXIF data is done by rendering the photo into a canvas, then using toDataURL() that only gives you the pixels, without any meta.

function download(idx, file) {
  const a = document.createElement('a');
  a.download = file.name;
  a.href = document.getElementById('image' + idx).toDataURL(file.type);
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
}

Btw to convert img to a canvas, you can go like:

<img src="file.jpg" onload="toCanvas()">

function toCanvas(img) {
  const canvas = document.createElement('canvas');
  canvas.width = img.naturalWidth;
  canvas.height = img.naturalHeight;
  const context = canvas.getContext('2d');
  context.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);
  img.parentNode.replaceChild(canvas, img);
}

One more mildly interesting bit is that I needed to convert some of the Lat/Long coordinates (namely West and South) to add a - so I can provide the values Bing/Apple/Any map expects.

const lat = (tags.GPSLatitudeRef.value[0] === 'S' ? '-' : '') + tags.GPSLatitude.description;
const lon = (tags.GPSLongitudeRef.value[0] === 'W' ? '-' : '') + tags.GPSLongitude.description;

Other tools for Mac

(I'm sure similar tools exist for other platforms, I just don't know them)

Open a photo with Preview. Press ⌘I (as in Info). Explore the ⓘ tab, then Exif and GPS sub-tabs. Note the handy little "Remove location info" button.

preview

Another (less powerful, but maybe quicker) thing is to right-click "Get Info" in Finder and see "More info"

getinfo

More alternative tools

jpegtran is a tool that comes for free with Mac/Linux. You can grab an exe for Windows too.

Use like so...

$ jpegtran -copy none -progressive before.jpg > after.jpg

This strips all meta. For more surgical exif fiddling, try exiftool (nice intro).

And, finally you can (make that should) always use ImageOptim. If runs jpegtran and more and cleans up meta info as part of the optimization process.

Reactions

I tweeted yesterday about the tool. Interesting responses.

The amazing Kornel (creator of aforementioned ImageOptim) warns about a potential privacy leak with converting a canvas to an image. Fix it, Chrome!

The extraordinary Mr.Heilmann mentioned he's done the same canvas-to-image meta stripping in his http://removephotodata.com/.

The unstoppable fiddler Eric Lawrence bemoans the size of the files generated by Canvas-to-file. I compared a photo taken by iPhone before and after the conversion.

sizes

The "after" result is smaller. This is because iPhone jpegs are not optimized to begin with. So - win. Then if you upload an optimized file (ideally through jpegtran/imageoptim) the meta is not there, so no "clean" file is generated either. So - non-lose. The problem is when you upload an optimized photo that still maintains meta. For this case and in general (fast by default!) I'll look into integrating an optimizer in JS-land. LMK if you know anything good. Initial search shows a promising emscripten-made mozjpeg-js npm package.

And finally, the greatest result came from a reaction by Jordan (of React fame) ended up with a bug filed by none other than Brenden Eich to make the Brave browser strip location meta by default. Awesome! Other browser vendors - please follow 🙂

Tell your friends about this post: Facebook, Twitter, Google+

Sorry, comments disabled and hidden due to excessive spam. Working on restoring the existing comments...

Meanwhile, hit me up on twitter @stoyanstefanov