[Scala]Ubuntu11.xx上でPlay framework 2.0 for Scalaで、ImageMagick/jMagickを使ってみる
Ubuntu 11.xx上で、Play framework 2.0 for ScalaからImageMagickを使う
ということで、今回のコンセプトですが
cookpadにはtohuがある
ぼくらにはない
でもapacheのモジュールで作るのもしんどい
という事で、Play framework for Scalaで作るという事なのです
まずはJDKのインストール
これは、
からダウンロードします。
しかし、SunがOracleに買収されたのは未だにショックです。。
というのはおいといて
ダウンロードしてきたJDKを解凍し、/usr/localに移動します。
tar xvfz jdk-7u4-linux-x64.tar.gz sudo mv jdk1.7.0_04 /usr/local
JAVA_HOMEを設定します。
/etc/environment
に
JAVA_HOME="/usr/local/jdk1.7.0_04"
を追加
その下にあるPATHにも
/usr/local/jdk1.7.0_04
を先頭あたりに追加
続いてScalaのインストール
からダウンロード
解凍
unzip scala-2.9.1.final.zip
scalaも/usr/localに移動します。
sudo mv scala-2.9.1.final /usr/local
JAVA_HOMEと同様にSCALA_HOMEを設定します。
/etc/environment
を開いて、JAVA_HOMEの下に
SCALA_HOME="/usr/local/scala-2.9.1.final"
を追加
その下のPATHにも
/usr/local/scala-2.9.1.final/bin
を追加。
最終的に、PATHは以下のようになると思います。
PATH="/usr/local/jdk1.7.0_04/bin:/usr/local/scala-2.9.1.final/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"
次にImageMagickのインストール
sudo apt-get install imagemagick
jMagickもaptでインストール
sudo apt-get install libjmagick6-java
若干パッケージ名が違うので注意
パッケージで入れた場合、jmagick6.jarは/usr/share/javaに置かれます。
libJMagick.soですが、
/usr/lib/jniに入ります。
このjni、パスが通っていませんので、後々エラーが出ると思うので
ここでパスを通しちゃいます。
/etc/bash.bashrcあたりに
export LD_LIBRARY_PATH=/usr/lib/jni:$LD_LIBRARY_PATH
を追加しておきます。
次にPlay Frameworkを入れます。
からダウンロード
今回は2.0を使っています。
1.x.xではないです。
ダウンロードした物を解凍
unzip play-2.0.zip
play自体は、個人用ホームに置きます。
mv play-2.0 ~
playコマンドにエイリアスを設定
~/.bashrc
に
alias play=~/play-2.0/play
を追加
これで、playコマンドがたたけるようになりました。
早速新しいプロジェクトを作成します。
play new ImageResizer
ImageResizerディレクトリに入ります。
cd ImageResizer
libディレクトリを作成します。
mkdir lib
とりあえず、/usr/share/javaからjmagick6.jarをこのlibにコピーします。
ちょっとめんどくさくなってきたので、ソースを貼り付けます。
#/app/controller/ImagesController.scala
package controllers
import play.api._
import play.api.mvc._
import java.io.File
import scalax.file.Path
import java.io.FileInputStream
import play.api.libs.iteratee.Enumerator
import java.security.MessageDigest
import magick.Magick
import magick.MagickImage
import magick.MagickException
import magick.ImageInfo
object ImagesController extends Controller {
trait createpathtrait[T];
implicit def createpathimp(a: Array[String]) = new createpathtrait[Array[String]]{def createpath = {("" /: a)(_ + "/" + _)}}
// 画像サイズ指定部分の文字列解析用正規表現
val regWithCut = """(.+)x(.+)c""".r
val regXY = """(.+)x(.+)""".r
val regY = """^x(.+)""".r
val regX = """^(.+)x""".r
val reg = """^(.+)""".r
/*
* イメージを返す
* imageType :: imagesディレクトリの第一階層のディレクトリ名を指定する
* imageId :: イメージのID
* size :: イメージのサイズ
* hash :: imageType、imageId、sizeから算出したハッシュ値
* ext :: 拡張子
*/
def index(iamgeType:String, imageId:String, size:String, hash:String, ext:String) = Action {
val filePath = Play.current.path.getPath() + "/images/" + Array(iamgeType, imageId + "." + ext).mkString("/")
// ハッシュ用文字列生成
val hashSeed = iamgeType + imageId + size + ext
val digestedBytes = MessageDigest.getInstance("MD5").digest(hashSeed.getBytes)
val hash = digestedBytes.map("%02x".format(_)).mkString
// TODO
// ハッシュ値がURLの物と一致しない場合、エラー
// TODO
// imageType、imageIdから、イメージを探す
// 拡張子はいずれかなので、正規表現で検索か?
val info = new ImageInfo(filePath)
val image = new MagickImage(info)
var image2:MagickImage = null
var width:Float = 0
var height:Float = 0
// TODO
// sizeによって画像のサイズを変換する
// 変換エンジンはImageMagickを使いたい
val changedSize:(Double, Double) = size match {
// case regWithCut(x, y) => {
// // TODO x,yのサイズで画像をカット
// // とりあえず、まだ実装しない
// (x.toFloat, y.toFloat)
// }
case regXY(x, y) = {
// TODO 縦横比を固定で、x,yの範囲に収まるように拡大縮小
val scaleX = x.toFloat / image.getDimension().getWidth()
val scaleY = y.toFloat / image.getDimension().getHeight()
if(scaleX > scaleY) {
(image.getDimension().getWidth() * scaleY, image.getDimension().getHeight() * scaleY)
} else {
(image.getDimension().getWidth() * scaleX, image.getDimension().getHeight() * scaleX)
}
}
// case regY(y) => {
// // 縦横比は固定で縦のサイズをyに設定
// (y)
// }
// case regX(x) => {
// // 縦横比は固定で横のサイズをxに設定
// (x)
// }
// case reg(x) => {
// // 縦横比は固定で、縦横の長い方の辺をxに設定
// (x)
// }
}
image2 = image.scaleImage(changedSize._1.toInt, changedSize._2.toInt)
val file = new java.io.File(filePath)
val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file)
SimpleResult(
header = ResponseHeader(200),
body = Enumerator.apply(image2.imageToBlob(info))
)
}
}
#/conf/routes
# Routes # This file defines all application routes (Higher priority routes first) # ~~~~ # Home page GET / controllers.Application.index GET /images/:imageType/:imageId/:size/:hash.:ext controllers.ImagesController.index(imageType, imageId, size, hash, ext) # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.at(path="/public", file)
テスト用の画像をどこからか持ってきます。
/images/sample
に入れます。
このsampleというディレクトリは
イメージタイプとしてURLから指定可能なように作ってみました。
このプロジェクトを実行します。
$> play [ImageResizer] $ run
URLにアクセスしてみます。
http://localhost:9000/images/sample/Chrysanthemum/200×200/b0f87c3f6aa9818bfa2942a6224a9648.jpg
どうでしょうか、縮小されたイメージが表示されましたでしょうか。
このImageResizerの今後の展開ですが
まだ未実装な部分を実装していきます。
また、
/imagesに置いた画像から、別の拡張子の画像を生成できるように
というのも実装したいと思います。

