前回作った「Google APIを使って写真のExif情報を取得する(Python)」ですが、簡単に作っていたので使い勝手が悪く使うのが面倒になってしまいました。
で、今回はこれを改善してみようかと思います。
まず、何処で使う物を、何で作るのかを検討。。ほぼ自宅で使う。けど、何処でも使えるようにしたい。という事はWebベース。開発言語は。。Python、Java、・・・Javaは色々と面倒くさい。。やっぱりPythonでしょう!
ということで、PythonでCGIで動くようにしてみました。Webベースのアプリにしておけば、どの端末でも利用できるし何処でも使えるし。
Webサービスとして公開したいところですが、セキュリティーとか、僕のサーバのリソースに余裕が無いのでソースの公開までにします。ソースはGitHubに置いています。
■どんな物なのか
写真には、色々な情報を持っていて、これは「撮影時のカメラの状態」「位置情報※」などがあります。
※今回は位置情報は取得していません
例:iPhoneで撮影した場合の情報
メーカ(make):Apple
モデル(model):iPhone 4S
ISO:160
絞り(fstop):2.4
露出(exposure): 0.05
レンズ焦点距離(focallength):4.28
フラッシュ(flash):false
日時(time):2013-03-0X
このような情報が写真ファイルの中にあるわけですが、通常は見なくてもいい情報なので見るまでの手続きが多かったりします。
通常見なくてもいい情報を簡単に見えるようにしようというのが今回の目的です。
接続画面
アルバム表示
Lightboxで表示
■技術情報
今回使っている言語、仕組みは以下のようになっています
・HTML5
・Ajax
・JavaScript
・Python
■インストール方法
下記GitHubから「PicasaWebAlbumExif_Python_CGI」全てをダウンロードしてCGI実行ディレクトリに配置する。起動ファイルは「picasa.html」※動作確認済みブラウザーはChrome、Firefox、iOS(iPhone,iPad)。Windows、IEでは動作確認していません。
■ソース
※最新版はGitHubで管理しています
https://github.com/brokendish/PicasaWebAlbumExif_Python_CGI
【picasa.cgi】
#!/usr/bin/python # -*- coding: utf-8 -*- import gdata.photos.service import gdata.media import gdata.geo import getpass import sys import datetime import cgi import os import Cookie import picasaAlbumList import urllib ##クッキーからデータを取得 #cookie = Cookie.SimpleCookie() #cookie.load(os.environ.get('HTTP_COOKIE', '')) #try: # ur = cookie["ur_save"].value # pw = cookie["pw_save"].value #except: # ur = "1" # pw = "2" print u"Content-type: text/html;charset=utf-8".encode('utf-8') #フォームからデータを取得 formG = cgi.FieldStorage() email=formG.getvalue('emailG', '') password=formG.getvalue('passwordG', '') ur=email pw=password ##--------------------------------------------------- ## 古典的暗号を使う(パッと見でわからなければいいので) ##--------------------------------------------------- ##ROT13単換字式暗号(シーザー暗号)ー暗号ーユーザ名 ur13=ur.encode('utf8').encode('base64_codec').encode('rot_13') #クエリ文字列用のエンコード ur13=urllib.quote_plus(ur13) #cookie["ur_save"]=ur13 ##ROT13単換字式暗号(シーザー暗号)ー複合ーユーザ名 #ur=ur13.decode('rot_13').decode('base64_codec').decode('utf8') ##--------------------------------------------------- ##ROT13単換字式暗号(シーザー暗号)ー暗号ーパスワード pw13=pw.encode('utf8').encode('base64_codec').encode('rot_13') #クエリ文字列用のエンコード pw13=urllib.quote_plus(pw13) #cookie["pw_save"]=pw13 ##ROT13単換字式暗号(シーザー暗号)ー複合ーパスワード #pw=pw13.decode('rot_13').decode('base64_codec').decode('utf8') ##--------------------------------------------------- print """ <html xmlns='http://www.w3.org/1999/xhtml' lang='ja'> <body bgcolor='#EFECED' text='#5E584E'></body> <style type='text/css'> td, th { border: 1px #857464 solid; } table { border: 1px #555555 solid; } .aa{ background-color: #5A5954; color: #FFFFFF; } .bb{ font-size: small;background-color: #B7B4AC; } .cc{ background-color: #5A5954; color: #FFFFFF} .ee{ border: 0px solid;background-color: #5A5954; color: #FFFFFF} .ff{ border: 0px solid;background-color: #5A5954; color: #FFFFFF;font-size:250%} .ss{ border: 0px solid;background-color: #5A5954; color: #FFFFFF;font-size:small} #t_left{float: left;} #t_right{float: left;} #t_Btm{} a:link { color: #4D4D4D; } a:visited { color: #000080; } a:hover { color: #E57400; } a:active { color: #E57400; } </style> """ print """ <div id="t_Btm"> <table> <tr class="ee"> <td rowspan=2> <a href="./picasa.html"><img src="./brokendish_iCON_Kuro.jpg" width="80" height="80"/></a> </td> <td class="ff" valign=bottom> Picasa WebAlbum Exif(写真情報取得) </td> <tr class="ee"> <td class="ss" align=right> <a href="https://brokendish.org">https://brokendish.org</a> </td> </tr> </tr> </table> </div> <hr> """ #print cookie.output() #print ur13 #print pw13 print """ <script type="text/javascript" src="lightbox/js/prototype.js"></script> <script type="text/javascript" src="lightbox/js/scriptaculous.js?load=effects,builder"></script> <script type="text/javascript" src="lightbox/js/lightbox.js"></script> <link rel="stylesheet" href="lightbox/css/lightbox.css" type="text/css" media="screen" /> <script language="javascript" type="text/javascript"> var xmlHttp; var selal; function loadText(alb){ xmlHttp = new XMLHttpRequest(); xmlHttp.onreadystatechange = checkStatus; xmlHttp.open("POST", "./picasaDisp.cgi", true); xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); xmlHttp.send("albumname=" + alb + "&email=%s&password=%s"); } function checkStatus(){ if (xmlHttp.readyState == 4 && xmlHttp.status == 200){ document.getElementById("t_right").innerHTML = xmlHttp.responseText; } } //リンク文字列取得 function getStr(self) { //リンクの文字列を「id=set_str」にセットする document.getElementById("set_albumname").value=self.firstChild.data; selal=self.firstChild.data; } //リンククリックでSubmitする function execute() { document.getElementById("t_right").innerHTML = selal + " Now! Loading.." loadText(selal) } </script> """ % (ur13,pw13) print """ <input type="hidden" name="albumnameG" id="set_albumname" /> <input type="submit" value="submit" name="button1" style="visibility:hidden"><p> </form> """ #アルバム名 albumname = formG.getvalue("albumnameG","") print '<div>' #左側に表示 print '<div id="t_left">' #Listデータ生成 picasaAlbumList.PicasaAlbumListDisp(ur,pw).runDisp() print "</div>" #右側に表示 print '<div id="t_right">' #表示データ生成 #XMLHttpRequestを使用して結果をinnerHTMLで表示 print "</div>" #print """ #<div id="t_Btm"> #<table> # <tr><td> #adasdasdas # </td></tr> #</table> #</div> #""" print'</html>' |
【picasa.html】
<html> <head> <title>Picasa WebAlbum Exif情報取得</title> </head> <body> <style type='text/css'> html,body{ width: 100%; height: 100%; margin: 0; padding: 0; background-color: #ffffff; } div{ margin: 0; padding: 0; } #content{ position: absolute; top: 50%; left: 50%; width: 400px; height: 320px; margin-top: -200px; margin-left: -200px; color: #555; font-weight: 200; font-size: 24px; line-height: 1; padding: 3px; border: 10px solid #f5f5f5; background: #E6E9E4; } .login { width:320px;height:40px;font-size: 24px;} .submit { width:120px;height:40px;font-size: 24px;} .tdB { width:100px;height:35px;vertical-align:bottom;font-size: 18px;color: #555;} .tdC { width:100px;height:40px;vertical-align:top;} .aa{ background-color: #5A5954; color: #FFFFFF; } .bb{ font-size: small;background-color: #B7B4AC; } .cc{ background-color: #5A5954; color: #FFFFFF} .ee{ border: 0px solid;background-color: #5A5954; color: #FFFFFF} .ff{ border: 0px solid;background-color: #5A5954; color: #FFFFFF;font-size:200%} #t_left{float: left;} #t_right{float: left;} #t_Btm{} a:link { color: #4D4D4D; } a:visited { color: #000080; } a:hover { color: #E57400; } a:active { color: #E57400; } </style> <script language="javascript" type="text/javascript"> function subm() { // var expires = 'Tue, 1-Jan-2030 00:00:00 GMT'; // document.cookie = 'ur_save' + '=' + document.getElementById("set_email").value + '; expires=' + expires; // document.cookie = 'pw_save' + '=' + document.getElementById("set_password").value + '; expires=' + expires; } </script> <div id="content"> <form name="form1" method="POST" action="./picasa.cgi"> <table align="center"> <tr class="ee"> <td> <a href="./picasa.html"><img src="./brokendish_iCON_Kuro.jpg" width="50" height="50"/></a> </td> <td class="ff" valign=bottom> Picasa WebAlbum Exif </td> </tr> </table> <table align="center"> <tr> <td class="tdB">ユーザID(Google ID)</td> </tr> <tr> <td class="tdC"> <input class="login" type="email" placeholder="メールアドレス" name="emailG" id="set_email" value="" required/> </td> </tr> <tr> <td class="tdB">パスワード</td> </tr> <tr> <td class="tdC"> <input class="login" type="password" placeholder="パスワード" name="passwordG" id="set_password" value="" required/> </td> </tr> <tr> <td align="right" class="tdC"> <input class="submit" type="submit" value="connect" name="button1" onclick=subm();><p> </td> </tr> </table> </form> </div> <hr> </body> </html> |
【picasaAlbumList.py】
#!/usr/bin/python # -*- coding: utf-8 -*- import gdata.photos.service import gdata.media import gdata.geo import getpass import sys import datetime import cgi import os import Cookie class PicasaAlbumListDisp: def __init__(self,email,password): self.email=email self.password=password def runDisp(self): #---------------------------------------------------------------------------------- gd_client = gdata.photos.service.PhotosService() gd_client.email = self.email gd_client.password = self.password gd_client.source = 'exampleCo-exampleApp-1' gd_client.ProgrammaticLogin() username=self.email albumid = "" #--------------------------------------------------------------------------------------------- albums = gd_client.GetUserFeed(user=username) print """ <table> <tr class="cc"> <th></th><th>Album</th><th>枚数</th> </tr> """ for album in albums.entry: print '<tr><td class="cc"></td><td class="bb" width="50"><a href="javascript:void(0);" onclick="execute(getStr(this)); return false;">%s</a></td><td>%s</td></tr>' % (album.title.text, album.numphotos.text) print '</table>' #--------------------------------------------------------------------------------------------- |
【picasaDisp.cgi】
#!/usr/bin/python # -*- coding: utf-8 -*- import gdata.photos.service import gdata.media import gdata.geo import getpass import sys import datetime import cgi import os import Cookie import urllib print u"Content-type: text/html;charset=utf-8".encode('utf-8') #フォームからデータを取得 formG1 = cgi.FieldStorage() email=formG1.getvalue('email', '') password=formG1.getvalue('password', '') albumname=formG1.getvalue('albumname', '') ##--------------------------------------------------- ## 古典的暗号 ##--------------------------------------------------- ##ROT13単換字式暗号(シーザー暗号)ー暗号ーユーザ名 #ur13=ur.encode('utf8').encode('base64_codec').encode('rot_13') #cookie["ur_save"]=ur13 #クエリ文字列用のデコード email=urllib.unquote_plus(email) ##ROT13単換字式暗号(シーザー暗号)ー複合ーユーザ名 email=email.decode('rot_13').decode('base64_codec').decode('utf8') ##--------------------------------------------------- ##ROT13単換字式暗号(シーザー暗号)ー暗号ーパスワード #pw13=pw.encode('utf8').encode('base64_codec').encode('rot_13') #cookie["pw_save"]=pw13 #クエリ文字列用のデコード password=urllib.unquote_plus(password) ##ROT13単換字式暗号(シーザー暗号)ー複合ーパスワード password=password.decode('rot_13').decode('base64_codec').decode('utf8') ##--------------------------------------------------- print """ <body bgcolor='#EFECED' text='#5E584E'></body> """ #---------------------------------------------------------------------------------- gd_client = gdata.photos.service.PhotosService() gd_client.email = email gd_client.password = password gd_client.source = 'exampleCo-exampleApp-1' gd_client.ProgrammaticLogin() username=email albumid = "" albums = gd_client.GetUserFeed(user=username) for album in albums.entry: if album.title.text == albumname: albumid = album.gphoto_id.text photos = gd_client.GetFeed('/data/feed/api/user/%s/albumid/%s?kind=photo' % (username, albumid)) print "<h2>Album -- %s</h2>" % (albumname) for photo in photos.entry: print '<table align="center">' print '<tr><td><a href="%s" rel="lightbox"><img src="%s"/></a></td>' % (photo.content.src, photo.media.thumbnail[2].url) # print '<tr><td><a href="%s"> <img src="%s"/></a></td>' % (photo.content.src, photo.media.thumbnail[2].url) print '<td><table width="450">' print '<tr><td>%s\n</td></tr>' % (photo.summary.text) camera="unknown" exposure="unknown" flash="unknown" focallength="unknown" fstop="unknown" iso="unknown" make="unknown" model="unknown" time="unknown" if photo.exif.make: camera = '%s %s' % (photo.exif.make.text, photo.exif.model.text) if photo.exif.exposure: exposure = '%s' % (photo.exif.exposure.text) if photo.exif.flash: flash = '%s' % (photo.exif.flash.text) if photo.exif.focallength: focallength = '%s' % (photo.exif.focallength.text) if photo.exif.fstop: fstop = '%s' % (photo.exif.fstop.text) if photo.exif.iso: iso = '%s' % (photo.exif.iso.text) if photo.exif.make: make = '%s' % (photo.exif.make.text) if photo.exif.model: model = '%s' % (photo.exif.model.text) if photo.exif.time: time = '%s' % datetime.date.fromtimestamp(int(photo.exif.time.text)/1000) # print '<tr><td class="aa">camera:<td>%s\n</td></td></tr>' % (camera) print '<tr><td class="aa">メーカ(make):<td>%s\n</td></td></tr>' % (make) print '<tr><td class="aa">モデル(model):<td>%s\n</td></td></tr>' % (model) print '<tr><td class="aa">ISO:<td>%s\n</td></td></tr>' % (iso) print '<tr><td class="aa">絞り(fstop):<td>%s\n</td></td></tr>' % (fstop) print '<tr><td class="aa">露出(exposure):<td>%s\n</td></td></tr>' % (exposure) print '<tr><td class="aa">レンズ焦点距離(focallength):<td>%s\n</td></td></tr>' % (focallength) print '<tr><td class="aa">フラッシュ(flash):<td>%s\n</td></td></tr>' % (flash) print '<tr><td class="aa">日時(time):<td>%s\n</td></td></tr>' % (time) print '</table></td>' print '</tr>' print '</table>' print '</table>' #--------------------------------------------------------------------------------------------- |