ずいぶん昔に、mail2entryと言うものを入れて、いわゆるmoblogができるようにしている。
これの出所がずっとわからなくなっていたのだけれど、今回ググってみたらすぐに見つかった。
mail2entry for posting images from mail to MT - Joi Ito's Web - JP
2002年の記事だ。
で、使えるようにしてはいるものの、ちっとも投稿しやしないんだけど、たまにはと思ってiPhoneから投稿してみた。
そうしたら、メールに添付した写真が1600x1200と言うばかでかいサイズで、しかも90度回転して表示されてしまった。
どうも、iPhoneを縦にして写真を撮ると、画像としては回転した状態になって、中にOrientationの情報が入るらしい。普段使っている画像転送ソフトは自動で回転してくれるので今までは気にしていなかったようだ。
ほとんど使わないとは言え、たまには使いたいので、なんとかすることにする。
やりたいことは、exif情報を読んで適切に回転することと、サムネイル画像を作ること。
pythonを触ったことがあるのは学生の頃なので、もう10年以上昔でさっぱり覚えていない。ソースを読んでも、(と{と[の意味もわからないし、mapって?lambdaって?って感じ。
軽く触った感じでは、(がリストで、[が配列で、{が辞書のようだ。mapと言うのはJavaとかのMapではなくて、コレクションに対して繰り返し関数を適用するもので、lambdaは式を関数にするもの(?)らしい。
画像をいじるならImageMagickだろう!と思って調べたが、pythonにはあまり有名なImageMagickバインディングが存在しないらしい。
その代わり、The Python Imaging Libraryと言うものを見つけたので、これを使うことにする。
FreeBSDの場合、portsからgraphics/py-imaging をインストールすると入る。
Imageオブジェクトに対して、_getexif()を呼ぶと、Exif情報が配列で取れて、0x0112にorientationが入ってるらしい。なんで0x0112かって言うと、PIL/ExifTags.py にTAGSって言うのがあって、そこを見るとわかる。
数値が取れるんだけど、その意味は画像の写真の向きを修正する@PHP - ブックマクロ開発にを参考にした。
自分が使うだけなので、反転には対応せずに、回転だけを相手にすることにする。
回転は、Imageオブジェクトに対してrotate(角度)を呼べば良い。
サムネイルの作成は、Imageオブジェクトのthumbnail(サイズ, フィルタ)を呼ぶ。
元画像のサイズは、Imageオブジェクトのsizeプロパティが配列になっていて、size[0]が幅、size[1]が高さ。
サムネイルのサイズ決定のアルゴリズムは、[メモ]Python Image Libraryで画像のサムネイルを作る - 好きなことしかできませんが、何か?を参考にさせていただいた。
後は、settings.py でimgtemplate に画像一枚毎のテンプレートがあるんだけど、そこにはimageurlしか変数がないので、どうやってサムネイルのurlを渡すか悩んだんだけど、saveimage.save()が返す配列の要素をまた配列にしてやって、lambda式の中で配列の要素を参照してやるようにしたらうまく行った。
元のソースがGPL2だったので一応差分を公開しておくけど、savelocalには面倒なので対応していない。あと、Exifなしのjpegを渡したらたぶん落ちる。そうそう、サムネイルは長辺が400pixelとハードコードしてる。
saveimage.py
これの出所がずっとわからなくなっていたのだけれど、今回ググってみたらすぐに見つかった。
mail2entry for posting images from mail to MT - Joi Ito's Web - JP
2002年の記事だ。
で、使えるようにしてはいるものの、ちっとも投稿しやしないんだけど、たまにはと思ってiPhoneから投稿してみた。
そうしたら、メールに添付した写真が1600x1200と言うばかでかいサイズで、しかも90度回転して表示されてしまった。
どうも、iPhoneを縦にして写真を撮ると、画像としては回転した状態になって、中にOrientationの情報が入るらしい。普段使っている画像転送ソフトは自動で回転してくれるので今までは気にしていなかったようだ。
ほとんど使わないとは言え、たまには使いたいので、なんとかすることにする。
やりたいことは、exif情報を読んで適切に回転することと、サムネイル画像を作ること。
pythonを触ったことがあるのは学生の頃なので、もう10年以上昔でさっぱり覚えていない。ソースを読んでも、(と{と[の意味もわからないし、mapって?lambdaって?って感じ。
軽く触った感じでは、(がリストで、[が配列で、{が辞書のようだ。mapと言うのはJavaとかのMapではなくて、コレクションに対して繰り返し関数を適用するもので、lambdaは式を関数にするもの(?)らしい。
画像をいじるならImageMagickだろう!と思って調べたが、pythonにはあまり有名なImageMagickバインディングが存在しないらしい。
その代わり、The Python Imaging Libraryと言うものを見つけたので、これを使うことにする。
FreeBSDの場合、portsからgraphics/py-imaging をインストールすると入る。
Imageオブジェクトに対して、_getexif()を呼ぶと、Exif情報が配列で取れて、0x0112にorientationが入ってるらしい。なんで0x0112かって言うと、PIL/ExifTags.py にTAGSって言うのがあって、そこを見るとわかる。
数値が取れるんだけど、その意味は画像の写真の向きを修正する@PHP - ブックマクロ開発にを参考にした。
自分が使うだけなので、反転には対応せずに、回転だけを相手にすることにする。
回転は、Imageオブジェクトに対してrotate(角度)を呼べば良い。
サムネイルの作成は、Imageオブジェクトのthumbnail(サイズ, フィルタ)を呼ぶ。
元画像のサイズは、Imageオブジェクトのsizeプロパティが配列になっていて、size[0]が幅、size[1]が高さ。
サムネイルのサイズ決定のアルゴリズムは、[メモ]Python Image Libraryで画像のサムネイルを作る - 好きなことしかできませんが、何か?を参考にさせていただいた。
後は、settings.py でimgtemplate に画像一枚毎のテンプレートがあるんだけど、そこにはimageurlしか変数がないので、どうやってサムネイルのurlを渡すか悩んだんだけど、saveimage.save()が返す配列の要素をまた配列にしてやって、lambda式の中で配列の要素を参照してやるようにしたらうまく行った。
元のソースがGPL2だったので一応差分を公開しておくけど、savelocalには面倒なので対応していない。あと、Exifなしのjpegを渡したらたぶん落ちる。そうそう、サムネイルは長辺が400pixelとハードコードしてる。
saveimage.py
*** saveimage.py.ORIG 2009-06-25 22:57:07.000000000 +0900
--- saveimage.py 2009-06-25 23:47:34.000000000 +0900
***************
*** 1,6 ****
--- 1,8 ----
import os
import stat
import time
+ from PIL import Image
+ from StringIO import StringIO
from settings import *
import postimage
***************
*** 13,23 ****
# a very good way to do this w/o leakage ;-(
imagetemplate = "".join(['photo-',
time.strftime("%Y%m%d-%H%M%S", time.gmtime()),
! '-%s.%s'])
for index in range(len(images)) :
(image,imgtype) = images[ index ]
imagefilename = imagetemplate % (index,extension[imgtype])
if savelocal :
# XXX: what if the user doesn't want now.jpg and a timestamp?
imagefilepath = imagesdirpath + '/' + imagefilename
--- 15,48 ----
# a very good way to do this w/o leakage ;-(
imagetemplate = "".join(['photo-',
time.strftime("%Y%m%d-%H%M%S", time.gmtime()),
! '-%s'])
! thumbtemplate = imagetemplate + "s.%s"
! imagetemplate = imagetemplate + ".%s"
for index in range(len(images)) :
(image,imgtype) = images[ index ]
imagefilename = imagetemplate % (index,extension[imgtype])
+ thumbfilename = thumbtemplate % (index,extension[imgtype])
+
+ # rotate
+ img = Image.open(StringIO(image))
+ orientation = img._getexif()[0x0112]
+ if orientation == 3:
+ img = img.rotate(180)
+ elif orientation == 6:
+ img = img.rotate(270)
+ elif orientation == 8:
+ img = img.rotate(90)
+ out = StringIO()
+ img.save(out, imgtype)
+ image = out.getvalue()
+ # make thumbnail
+ zoom = min(400.0 / max(img.size[0], img.size[1]), 1.0)
+ img.thumbnail((int(img.size[0] * zoom), int(img.size[1] * zoom)), Image.ANTIALIAS)
+ out = StringIO()
+ img.save(out, imgtype)
+ thumbnail = out.getvalue()
+
if savelocal :
# XXX: what if the user doesn't want now.jpg and a timestamp?
imagefilepath = imagesdirpath + '/' + imagefilename
***************
*** 46,50 ****
postdata = postimage.post(imageinfo)
imageurl = postdata['url']
! imageurls.append(imageurl)
return imageurls
--- 71,85 ----
postdata = postimage.post(imageinfo)
imageurl = postdata['url']
! imageremotepath = imagesdirpath + '/' + thumbfilename
! import xmlrpclib
! imagedata = xmlrpclib.Binary(thumbnail)
! # XXX: what if the image isn't a jpg?
! imageinfo = { 'name' : imageremotepath,
! 'type' : "image/jpeg",
! 'bits' : imagedata }
! postdata = postimage.post(imageinfo)
! thumburl = postdata['url']
!
! imageurls.append([imageurl, thumburl])
return imageurls
mail2entry.py
*** mail2entry.py.ORIG 2004-03-12 16:22:29.000000000 +0900
--- mail2entry.py 2009-06-25 23:39:59.000000000 +0900
***************
*** 1,4 ****
! #! /usr/bin/env python2.2
"""Post a new MT entry from a mail message"""
--- 1,4 ----
! #! /usr/bin/env python
"""Post a new MT entry from a mail message"""
***************
*** 24,30 ****
if images :
imageurls = saveimage.save ( images )
imagecontent = map ( lambda imageurl : imgtemplate % \
! { 'imageurl' : imageurl }, imageurls )
else :
imagecontent = u''
--- 24,30 ----
if images :
imageurls = saveimage.save ( images )
imagecontent = map ( lambda imageurl : imgtemplate % \
! { 'imageurl' : imageurl[0], 'thumburl' : imageurl[1] }, imageurls )
else :
imagecontent = u''
私が使っているsettings.pyのテンプレート
# template: Template for the resulting blog entry. You probably don't
# need to change this.
template = "%(caption)s\n" + \
"%(imagecontent)s"
# imgtemplate: Template for a single image entry. This gets embedded
# within _template_ when creating the full entry. If multiple
# images are found within an email message, _imgtemplate_ will
# be used for each image. The concatenation of all _imgtemplate_
# are used within _template_.
imgtemplate = "<div class=\"photo\"><a href=\"%(imageurl)s\"><img src=\"%(thumburl)s\"></a></div>"
配列が使えることがわかったから、やろうと思えばimgタグにwidthとかheightとかを付けることも可能だけど、まあいっか。
