Created
January 19, 2017 02:18
-
-
Save stoyan/ddfa1710fe5d7e32b9337caa9a5207b9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From b62bc38b72a6646cd4cb87a84355a7e8c2720e8f Mon Sep 17 00:00:00 2001 | |
From: Stoyan <ssttoo@ymail.com> | |
Date: Wed, 18 Jan 2017 18:14:39 -0800 | |
Subject: [PATCH] Exif tool based on FAIL | |
--- | |
README.md | 6 +----- | |
manifest.json | 6 +++--- | |
package.json | 5 +++-- | |
public/exif-icon.png | Bin 0 -> 620 bytes | |
public/favicon.ico | Bin 1150 -> 1150 bytes | |
public/index.html | 4 ++-- | |
src/App.js | 53 +++++++++++++++++++++++++++++++++++++++------------ | |
7 files changed, 50 insertions(+), 24 deletions(-) | |
create mode 100644 public/exif-icon.png | |
diff --git a/README.md b/README.md | |
index 23b1a1f..2b18733 100644 | |
--- a/README.md | |
+++ b/README.md | |
@@ -1,5 +1 @@ | |
-File API Input Layer (FAIL) is a template-of-sorts for building one-off tools that require the user to upload files and then have the app do something amazing with the aforementioned files. Like cssshrink.com or similar. | |
- | |
-http://phpied.com/fail for more info. | |
- | |
-https://phpied.com/files/fail for a demo. | |
\ No newline at end of file | |
+A creepy tool to raise awareness of the information people are sending voluntarily or not. | |
\ No newline at end of file | |
diff --git a/manifest.json b/manifest.json | |
index 81e3352..d62b244 100644 | |
--- a/manifest.json | |
+++ b/manifest.json | |
@@ -1,9 +1,9 @@ | |
{ | |
- "short_name": "fail", | |
- "name": "File API Input Layer", | |
+ "short_name": "Photo Geo", | |
+ "name": "Where was ths photo taken", | |
"icons": [ | |
{ | |
- "src": "fail-icon.png", | |
+ "src": "exif-icon.png", | |
"sizes": "192x192", | |
"type": "image/png" | |
} | |
diff --git a/package.json b/package.json | |
index dde50a4..ea2b2db 100644 | |
--- a/package.json | |
+++ b/package.json | |
@@ -1,8 +1,9 @@ | |
{ | |
- "name": "fail", | |
- "version": "0.0.1", | |
+ "name": "exif", | |
+ "version": "1.0.0", | |
"private": true, | |
"devDependencies": { | |
+ "exifreader": "^2.0.1", | |
"react-scripts": "0.8.4", | |
"sw-precache": "^4.2.3" | |
}, | |
diff --git a/public/exif-icon.png b/public/exif-icon.png | |
new file mode 100644 | |
index 0000000000000000000000000000000000000000..eec7906d5dd7e5db9563326a8bc878d68955c7d2 | |
GIT binary patch | |
literal 620 | |
zcmeAS@N?(olHy`uVBq!ia0vp^2SAvE8Azrw%`pX1Q2{<7t}Mp?FI~Q||HvIJzn@bU | |
zKJA$CT-xQ&wQJXwZ+N(A=Y2W1-+K<+J#yl<iudnj>mTx3{o}L#ckt+KWv}1;^PXM1 | |
zc75r(hbuNd+`9YTw8c-`roPy==bpOHF9Dl>T$cZK{Qtzuz`%Ic)5S5Q;?~=XC;gZm | |
z1y}+NPS3c?He2@Je{;)YtrI7Fo}i`qC?@M^@cfxb;O2sR^ItsPqAthxTPb1pg{PUn | |
z%}<xv3m*8#dQgSox1bNx26-@}2g-O^XwQA1jwRP&gS?}#z#I1qEG)kTO&AZ>vG@Xo | |
z4(2g5{B2yolu)mr!E{5Oql@7idy^7Khyz8)>cLE)7$ZoGq3JINS3`w;6Q9EU{sqh@ | |
zzAL|A`1F@Us-eby@0(R1{dNz2S1sM%%9rhKUwWX*oI7@H9H)SSLjwaN6AK5ijE4VT | |
zw_5(+{n+XF)Y<1>OEu`dn;yJ-H*ehn&4hXe4XzvV3|&m$*c%o#{AFCAL0uuX49*+& | |
zoDB_sCo^zB7@I*1ZlDO5!PW3!>R-kKXOO_LFWmMkYiDhbeKrx8d>A}k{an^LB{Ts5 | |
D$b$)4 | |
literal 0 | |
HcmV?d00001 | |
diff --git a/public/favicon.ico b/public/favicon.ico | |
index 7fad314b6af978258bcb6de064e01c6ce41441d1..d1fa5b9c90434a096fe97cac7a661b657ac269d9 100644 | |
GIT binary patch | |
delta 84 | |
zcmeyz@sDGI_QZ7I#dge$llzzsOkT(MU~(U$p}Z#p`+q!mVx0j8On!11(-9UBXJVbh | |
H#03HX0KXkS | |
literal 1150 | |
zcmds0K@NZ*46BI=M>u)*=nwpo|Np=&F($K_aM25pGPbT;SOPF{mja$Eju}`0Yy?A$ | |
zTyYwJoG#m8f}}YuU$oZBjkv$`teYyLo<64iZ{3^q+IkQ4I?sncx?bPc^L2i`eC5B^ | |
TYrWC^%pa>j=9C>guk$|vJhWA9 | |
diff --git a/public/index.html b/public/index.html | |
index f230540..7fc7d72 100644 | |
--- a/public/index.html | |
+++ b/public/index.html | |
@@ -3,7 +3,7 @@ | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
- <link rel="shortcut icon" href="%PUBLIC_URL%/fail-icon.png"> | |
+ <link rel="shortcut icon" href="%PUBLIC_URL%/exif-icon.png"> | |
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> | |
<meta name="theme-color" content="#222"> | |
<!-- | |
@@ -15,7 +15,7 @@ | |
work correctly both with client-side routing and a non-root public URL. | |
Learn how to configure a non-root public URL by running `npm run build`. | |
--> | |
- <title>FAIL</title> | |
+ <title>Where was this photo taken</title> | |
</head> | |
<body> | |
<!-- | |
diff --git a/src/App.js b/src/App.js | |
index 11f973c..84a7e18 100644 | |
--- a/src/App.js | |
+++ b/src/App.js | |
@@ -1,5 +1,10 @@ | |
import React, { Component } from 'react'; | |
import './App.css'; | |
+const load = require('exifreader').load; | |
+ | |
+const bing = 'http://dev.virtualearth.net/REST/v1/Imagery/Map/Road/LATLONG/'+ | |
+ '15?pp=LATLONG&mapSize=500,500'+ | |
+ '&key=Ai_kb4YXmugLoiCy2Giijbk7My25iPiWt6YKREnN-Nvw9Ye9EiVcSjs2kI287_WB'; | |
class App extends Component { | |
@@ -35,12 +40,30 @@ class App extends Component { | |
const data = this.state.data.slice(); | |
files.forEach((f, idx) => { | |
if (!data[idx]) { | |
- const i = new Image(); | |
- i.onload = () => { | |
- data[idx] = i.naturalWidth + 'x' + i.naturalHeight; | |
+ var reader = new FileReader(); | |
+ reader.onload = (event) => { | |
+ try { | |
+ const tags = load(event.target.result); | |
+ const lat = | |
+ (tags.GPSLatitudeRef.value[0] === 'S' ? '-' : '') + tags.GPSLatitude.description; | |
+ const lon = | |
+ (tags.GPSLongitudeRef.value[0] === 'W' ? '-' : '') + tags.GPSLongitude.description; | |
+ | |
+ data[idx] = { | |
+ mapUrl: bing.replace(/LATLONG/g, lat + ',' + lon), | |
+ time: tags.DateTimeOriginal.description, | |
+ latlon: {lat, lon}, | |
+ | |
+ }; | |
+ } catch (_) { | |
+ data[idx] = { | |
+ mapUrl: '-1', | |
+ }; | |
+ } | |
this.setState({data}); | |
}; | |
- i.src = window.URL.createObjectURL(f); | |
+ reader.readAsArrayBuffer(f.slice(0, 128 * 1024)); | |
+ | |
} | |
}); | |
} | |
@@ -49,8 +72,8 @@ class App extends Component { | |
return ( | |
<div className="App"> | |
<div className="App-header"> | |
- <h1>Upload me some images</h1> | |
- <p>pst, you can just drop them anywhere</p> | |
+ <h1>Photo stalker creep</h1> | |
+ <p>upload or drop some photos and see when and where they were taken</p> | |
</div> | |
<div className="Tool-in"> | |
<Uploads onChange={this.handleUploads.bind(this)} /> | |
@@ -82,18 +105,24 @@ const Results = ({files, data}) => { | |
return ( | |
<table className="Results-table"> | |
<tbody> | |
- <tr><th>Image</th><th>filename</th><th>bytes</th><th>mime</th><th>dimensions</th></tr> | |
+ <tr><th>what</th><th>when</th><th>where</th></tr> | |
{files.map((f, idx) => { | |
if (!f.type.startsWith('image/')) { | |
return null; | |
} | |
return ( | |
<tr key={idx}> | |
- <td><img alt={f.name} src={window.URL.createObjectURL(f)} height="60" /></td> | |
- <td>{f.name}</td> | |
- <td>{f.size}</td> | |
- <td>{f.type}</td> | |
- <td>{data[idx] || '...'}</td> | |
+ <td><img alt={f.name} src={window.URL.createObjectURL(f)} width="300" /></td> | |
+ <td>{(data[idx] && data[idx].time) || '...'}</td> | |
+ <td>{ | |
+ data[idx] && data[idx].mapUrl | |
+ ? data[idx].mapUrl === '-1' | |
+ ? 'Lucky you! No geo location in this file.' | |
+ : <a href={`http://maps.apple.com/?ll=${data[idx].latlon.lat},${data[idx].latlon.lon}&q=Photo taken here`}> | |
+ <img alt={JSON.stringify(data[idx].latlon)} src={data[idx].mapUrl} width="300" /> | |
+ </a> | |
+ : '...' | |
+ }</td> | |
</tr> | |
); | |
})} | |
-- | |
2.8.0-rc2 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment