Picasa Web Albumの写真情報取得CGI版

前回作った「Google APIを使って写真のExif情報を取得する(Python)」ですが、簡単に作っていたので使い勝手が悪く使うのが面倒になってしまいました。
で、今回はこれを改善してみようかと思います。
まず、何処で使う物を、何で作るのかを検討。。ほぼ自宅で使う。けど、何処でも使えるようにしたい。という事はWebベース。開発言語は。。Python、Java、・・・Javaは色々と面倒くさい。。やっぱりPythonでしょう!
ということで、PythonでCGIで動くようにしてみました。Webベースのアプリにしておけば、どの端末でも利用できるし何処でも使えるし。

Webサービスとして公開したいところですが、セキュリティーとか、僕のサーバのリソースに余裕が無いのでソースの公開までにします。ソースはGitHubに置いています。

 

 

 

picasaCGI_001

 

 

■どんな物なのか

写真には、色々な情報を持っていて、これは「撮影時のカメラの状態」「位置情報※」などがあります。
※今回は位置情報は取得していません

例:iPhoneで撮影した場合の情報
メーカ(make):Apple
モデル(model):iPhone 4S
ISO:160
絞り(fstop):2.4
露出(exposure): 0.05
レンズ焦点距離(focallength):4.28
フラッシュ(flash):false
日時(time):2013-03-0X

このような情報が写真ファイルの中にあるわけですが、通常は見なくてもいい情報なので見るまでの手続きが多かったりします。
通常見なくてもいい情報を簡単に見えるようにしようというのが今回の目的です。

 

接続画面

picasaCGI_002

アルバム表示

picasaCGI_003

Lightboxで表示

picasaCGI_004

 

■技術情報
今回使っている言語、仕組みは以下のようになっています
・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="http://brokendish.org">http://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>'
#---------------------------------------------------------------------------------------------
 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です