携帯向けPicasaビューワ更新しました。
バグ修正だけですけど・・・。
過去の記事:
アプリケーション動作イメージ
QRコードとかアプリケーション概要とか
2010年9月11日
Picasa Web Album Viewer for Mobile
![]() | ![]() | ![]() |
| アルバム選択 | フォト選択 | フォト変換 |
相変わらずCookie対応でないと動きません。
新しくない携帯で試したところ、
そもそもGoogleへのAuthSub認証すらできないようです。
携帯での使用を想定してますが、シンプルなHTMLというだけで
パソコンやその他の端末でも表示できると思います。
あ、PSPとかでも表示できるかな?
タグ編集、順序入れ替え機能など
気が向いたら実装したいところです。
2010年9月1日
携帯向けPicasaViewer
Google App Engine for Java(GAE/J) と
Picasa Web Albums Data API で、
携帯電話用 Picasa Web ビューワ的なものを
組んでみました。今のところ、
自分のアルバムの画像しか見られませんが。
概要
原寸大を含めた、自由な大きさに縮小して、画像をダウンロード出来ます。携帯用Picasa Web Albumって小さいサムネ画像しか見られないのが、
すごく不便じゃないですか?
パソコンで収集した画像をPicasaでPicasa Webと同期して、
携帯で見られるようにしてみようというわけです。
すでに似たようなサービスありそうですが、
あったら教えてください。ガラケー不便です・・・orz
動作要件
N-06Aで動作確認してます。DoCoMoの携帯で、比較的最近のなら動くはずです・・・。
未確認ですが、AUやSoftbankでも動くんじゃないかな・・・?
ブラウザがCookieをサポートしていて、
pngやjpegを表示できれば多分動きます。
まぁ、動くっても大したサービスをするわけではないんですが。
アカウント認証
ちなみに、認証にはGoogleのAuthSub認証を使ってるので、自分のプログラムではユーザIDやパスワードを扱ってません。
いろいろと大きな問題は起こらないはず・・・。
と言いつつ、いかなる損害にも責任は負えませんのでご了承ください・・・。
なので、まぁ、これがちょっとした暇つぶしにでもなれば嬉しいです。
参考になったURLやつまづいた箇所
これらを組むに当たって参考になったURLや、つまずいた箇所を紹介したいと思います。
APIドキュメント
JavaSE6 APIドキュメントJava Servlet 2.4 APIドキュメント(非公式日本語版)
Google App Engine APIドキュメント
Google Data API Client Libraryドキュメント
言うまでもなくAPIドキュメントです。Servletの日本語版はとても助かりました。
GAE/J 導入
スタート ガイド: Java - Google App Engine - Google CodeGAEの親切な日本語のチュートリアルです。
基本的にはこれに沿って導入すれば大体把握できるんじゃないかと。
(Firefoxだと、localhostへの接続が失敗したような気がしますが、再現しないので気にしないことにします。)
ただし、一部のコードが間違っていて、コンパイルエラーが出ます。
「JSPの使用」にあるサンプルコード、
resp.sendRedirect("/intl/ja/guestbook.jsp");の、/intl/ja/guestbook.jspなんてものは無いので、/guestbook.jspに変更します。
GData 導入
EclipseでGoogle APIプログラミング~環境の構築 | takulabこちらを参考にGoogle Data APIを導入しました。わかりやすかったです。
ただ、activation.jarは、最近は標準でJDK辺りに組み込まれてるらしいので、
探さなくていいかも。
そういえば、 Eclipseのプロジェクトに、別個にダウンロードしたJDKを
代替JREとして設定したような気がするけど、なんでだったっけ・・・?
気合で動かす
Developer's Guide: Java - Picasa Web Albums Data API - Google Codeモット! モバイルプログラミング: Google Data API
この辺りを参考に、気合で。というか、細かいことはよく理解してません。
でも動くぜ!さすがGoogle先生や!
後者のブログで使われていますが、Google Data APIのドキュメントの
/gdata/java/sample/photos/PicasawebClient.java
は、簡単にアルバムやフォトを取得できて、大変お世話になりました。
AuthSub認証の設定
クリボウのプログラミングひとりごと: GAE/J の AuthSub で This website has not registered with Google to establish a secure connection for authorization requests. の警告をなくす方法さすがに自分のプログラムにIDとパスワード入力してもらうのは嫌だったので、
こちらを参考にGoogleの認証を行うように設定しました。
IDからアルバムやフォトを取得
最後に、How to get the absolute URL for the image (640 or 800 pixel size) - Google Picasa Web Albums API | Google グループ
こちらにを参考にわかったことですが、
特定のアルバムIDとフォトIDからAlbumEntryやPhotoEntryを取得するには、
PicasawebClient.javaに以下のように関数を追加すればできるようです。
public class PicasawebClient {
...
private static final String ENTRY_PREFIX = "http://picasaweb.google.com/data/entry/api/user/";
...
public AlbumEntry getAlbum(String albumID) throws IOException, ServiceException {
String albumUrl = ENTRY_PREFIX + "default"
+ "/albumid/" + albumID;
return service.getEntry(new URL(albumUrl), AlbumEntry.class);
}
...
public PhotoEntry getPhoto(String albumID, String photoID) throws IOException, ServiceException {
String photoUrl = ENTRY_PREFIX + "default"
+ "/albumid/" + albumID + "/photoid/" + photoID;
return service.getEntry(new URL(photoUrl), PhotoEntry.class);
}
...
}
ちなみに、albumID、photoIDは、AlbumEntry#getGphotoId()、PhotoEntry#getGphotoId()で取得できます。
2010年8月26日
Google App Engine と Eclipse AmaterasIDE で 謎のエラー
Google App Engine (GAE)でサーブレットの勉強がてら遊んでいたのですが、
何も変更していないのに、
急にwar/WEB-INS/appengine-web.xmlが
以下のようなエラーを吐くようになりました。
appengine-web.xmlを別の名前にリネーム -> 複製 -> 元の名前に戻す
など、Eclipseに別のファイルとして読み込みなおさせることで
エラーが解決するようです。
考えられる原因としては、
Amateras XMLエディタによるエラーの誤検出があります。
EclipseからXMLファイルを開くときの選択肢として
Amateras XMLエディタ、XMLエディタ、テキストエディタがありますが、
テキストエディタは当然としても、
XMLエディタではエラーは検出されなかったためです。
全く意味不明で禿げるかと思った・・・。
日本語の資料あんまり出てこないし、英語苦手だし・・・。
誰か詳しい方がいれば、原因を教えてください・・・。
何も変更していないのに、
急にwar/WEB-INS/appengine-web.xmlが
以下のようなエラーを吐くようになりました。
cvc-elt.1: Cannot find the declaration of element 'appengine-web-app'.結論からいうと、
appengine-web.xmlを別の名前にリネーム -> 複製 -> 元の名前に戻す
など、Eclipseに別のファイルとして読み込みなおさせることで
エラーが解決するようです。
考えられる原因としては、
Amateras XMLエディタによるエラーの誤検出があります。
EclipseからXMLファイルを開くときの選択肢として
Amateras XMLエディタ、XMLエディタ、テキストエディタがありますが、
テキストエディタは当然としても、
XMLエディタではエラーは検出されなかったためです。
全く意味不明で禿げるかと思った・・・。
日本語の資料あんまり出てこないし、英語苦手だし・・・。
誰か詳しい方がいれば、原因を教えてください・・・。
2009年11月8日
透過BufferedImage作成
Javaの透過BufferedImageによる描画について書いてみようと思います。
SRPGの戦闘システム風JavaAppletの描画で用いました。
今までは特に工夫せずに毎回一から線とか四角で描画していましたが、
毎回同じことをするのは無駄だと思ったので、少しいじりました。
まずメニューとかマップとかのオブジェクトごとに
java.awt.image.BufferedImageインスタンスを持っておいて、
最初か変更のあったときだけそれに描画しておいて、
そのBufferedImageを毎回スクリーンに描画するって寸法です。
ペイントソフトでいうレイヤーみたいなもんですね。
で、まぁ、このBufferedImageが不透明度100%で初期化されるので、
これを透明な状態で初期化しなければなりません。
http://www.ibm.com/developerworks/jp/java/library/j-begjava-index/#c
こちらを参考にしました。といっても最後にsetPaintMode()しただけですが。
こうしてGraphicsオブジェクトを初期化したあとは普通に描画していくだけです。
ちなみに
http://www.ne.jp/asahi/hishidama/home/tech/java/image.html#画像を加工する
こちらではBufferedImage.setRGB()で透明度を指定しているようですが、
気が向いたら処理時間を比べてみようと思います。
SRPGの戦闘システム風JavaAppletの描画で用いました。
今までは特に工夫せずに毎回一から線とか四角で描画していましたが、
毎回同じことをするのは無駄だと思ったので、少しいじりました。
まずメニューとかマップとかのオブジェクトごとに
java.awt.image.BufferedImageインスタンスを持っておいて、
最初か変更のあったときだけそれに描画しておいて、
そのBufferedImageを毎回スクリーンに描画するって寸法です。
ペイントソフトでいうレイヤーみたいなもんですね。
で、まぁ、このBufferedImageが不透明度100%で初期化されるので、
これを透明な状態で初期化しなければなりません。
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2D = img.createGraphics(); g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f)); Rectangle2D.Double rect = new Rectangle2D.Double(0,0,img.getHeight(),img.getHeight()); g2D.fill(rect); g2D.setPaintMode();コードはこんな感じになります。width, heightには幅と高さを入れてください。
http://www.ibm.com/developerworks/jp/java/library/j-begjava-index/#c
こちらを参考にしました。といっても最後にsetPaintMode()しただけですが。
こうしてGraphicsオブジェクトを初期化したあとは普通に描画していくだけです。
ちなみに
http://www.ne.jp/asahi/hishidama/home/tech/java/image.html#画像を加工する
こちらではBufferedImage.setRGB()で透明度を指定しているようですが、
気が向いたら処理時間を比べてみようと思います。
2009年11月3日
ヘックスなシミュレーションゲーム
以前公開したSRPGの戦闘システム風JavaAppletを更新しました。
描画周りと敵AIに手を加えました。
ヘックスのアルゴリズムの実装について書いてみようと思います。
結構苦労したので・・・。
ヘックスの座標系:
特に考えずに決めてしまったので、ちょっと後悔してます。
基本的には
カーソルの移動とかはこの座標系がいいですね。
距離を考えるときには
縦方向基準な座標系とでもいうのでしょうか。
距離についての詳細は下記。
結局使わずに終わってしまいました。
一応言い訳しておくと、
座標系の実装は隠すようになってるから何でもいいんです。
今更変えるのは面倒なんです・・・。意味ないし・・・。
2ヘックス間の距離:
http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx
こちらのブログを参考にしました。天才だと思います。
見つけるのに苦労しました。検索結果のもっと上のほうに出てきてもいいのに・・・。
射線:
障害物の向こう側に攻撃が届かないシステムについて。
点と線分の距離から、
障害物のあるヘックスの中心からの距離が一定以下ならそいつに阻まれます。
http://www.deqnotes.net/acmicpc/2d_geometry/lines
こちらを参考に点と線分の距離を求めてます。
以下ソース引用
汚いコードだと思いますがすいません。
この関数は引数のtarget座標に攻撃が届くか否かを返します。
Coordは座標(x,y)を持つクラスです。
current:攻撃者の座標としてすでにセットされてます。
hexSize:ただの係数なので1でも何でもいいんですが、
計算する上である程度の大きさがあったほうがいいです。
後で位置関係をatan2に突っ込むのですが、そこがうまくいかなくなります。
r:ヘックスを覆う円の半径です。√3/2が六角形の半径です。
大きめにしないと隣り合った障害物の隙間を通り抜けてしまいます。
getCoordByHex():はヘックス座標系から実際の画面上(?)の座標を返します。
まず、距離が射程range外もしくはマップ外であればはじきます。
でもって、マップのすべてのヘックスについて
障害物でないか、射程外か、自分自身かターゲットでなければ、
上で引用した点と線分の距離を用いて判定しています。
後半になるほど面倒になって説明が雑になってますが許してください・・・。
描画周りと敵AIに手を加えました。
ヘックスのアルゴリズムの実装について書いてみようと思います。
結構苦労したので・・・。
ヘックスの座標系:
特に考えずに決めてしまったので、ちょっと後悔してます。
基本的には
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □こんな感じのギザギザなx座標を使ってます。
カーソルの移動とかはこの座標系がいいですね。
距離を考えるときには
□ □ □ □ □ □ □ □ □ □ □ □ □ □こんなのですね。
縦方向基準な座標系とでもいうのでしょうか。
距離についての詳細は下記。
□ □ □ □ □ □ □ □ □ □ □ □ □ □ □ □多分最も一般的なのがこれだと思うんですが、
結局使わずに終わってしまいました。
一応言い訳しておくと、
座標系の実装は隠すようになってるから何でもいいんです。
今更変えるのは面倒なんです・・・。意味ないし・・・。
2ヘックス間の距離:
http://blogs.wankuma.com/izmktr/archive/2009/06/26/176657.aspx
こちらのブログを参考にしました。天才だと思います。
見つけるのに苦労しました。検索結果のもっと上のほうに出てきてもいいのに・・・。
射線:
障害物の向こう側に攻撃が届かないシステムについて。
点と線分の距離から、
障害物のあるヘックスの中心からの距離が一定以下ならそいつに阻まれます。
http://www.deqnotes.net/acmicpc/2d_geometry/lines
こちらを参考に点と線分の距離を求めてます。
以下ソース引用
private static int obstacleHeight = 4; // 障害物の高さ
private static int unitHeight = 2; // ユニットの高さ
/*
* 攻撃者の座標はcurrentとして設定済。
* 目標の座標targetと射程Range(水平方向と高さ方向の射程。min, maxは水平方向の射程)から、
* 攻撃可能か否かbooleanを返す。
*/
public boolean raySearch(Coord<Integer> target, Range range) {
if(!searchFloat(target.x, target.y, range)) // range内にtargetがいなければ偽
return false;
int hexSize = 128; // 理論上は1でもいいが、大きい方が誤差が出にくい?
double r = hexSize/2 * 1.732/2 * 1.2; // hexsizeを覆う円の半径。これに射線が触れるか判定する。
Coord<Double> currentC = getCoordByHex(current.x, current.y, hexSize); // ヘックス座標から実座標を取得。
Coord<Double> targetC = getCoordByHex(target.x, target.y, hexSize);
double thetaL = Math.atan2(targetC.y - currentC.y, targetC.x - currentC.x); // 射線の角度
for(int y = 0; y < map.length; y++)
for(int x = 0; x < map[y].length; x++) { // マップ上のヘックス全てについて、
if((target.x == x && target.y == y)
|| (current.x == x && current.y == y)
|| distanse(current.x, current.y, x, y) > range.max) // 自分か目標か射程外なら障害物になり得ない
continue;
Coord<Double> barC = getCoordByHex(x, y, hexSize); // 今チェックするヘックスの実座標
int offsetH = 0;
if(map[y][x] <= OBSTACLE) // 障害物なら
offsetH = obstacleHeight;
int difH = height[target.y][target.x] - height[current.y][current.x]; // 自分と目標の高さの差
int h = height[y][x] + offsetH - unitHeight; // ユニットの高さの分、当たりやすくなる
if((barC.x - currentC.x) * difH / (targetC.x - currentC.x) + height[current.y][current.x] > h
|| (barC.y - currentC.y) * difH / (targetC.y - currentC.y) + height[current.y][current.x] > h) // このヘックスが、xかy方向に高さで邪魔にならなければ、次。
continue;
// 以降、図形の問題をごにょごにょ
double theta = Math.atan2(barC.y - currentC.y, barC.x - currentC.x) - thetaL;
if(Math.cos(theta) < 0 || Math.cos(thetaL - Math.atan2(targetC.y - barC.y, targetC.x - barC.x)) < 0)
continue;
if(Math.hypot(barC.x - currentC.x, barC.y - currentC.y) * Math.abs(Math.sin(theta)) < r)
return false;
}
return true;
}
汚いコードだと思いますがすいません。
この関数は引数のtarget座標に攻撃が届くか否かを返します。
Coordは座標(x,y)を持つクラスです。
current:攻撃者の座標としてすでにセットされてます。
hexSize:ただの係数なので1でも何でもいいんですが、
計算する上である程度の大きさがあったほうがいいです。
後で位置関係をatan2に突っ込むのですが、そこがうまくいかなくなります。
r:ヘックスを覆う円の半径です。√3/2が六角形の半径です。
大きめにしないと隣り合った障害物の隙間を通り抜けてしまいます。
getCoordByHex():はヘックス座標系から実際の画面上(?)の座標を返します。
まず、距離が射程range外もしくはマップ外であればはじきます。
でもって、マップのすべてのヘックスについて
障害物でないか、射程外か、自分自身かターゲットでなければ、
上で引用した点と線分の距離を用いて判定しています。
後半になるほど面倒になって説明が雑になってますが許してください・・・。
登録:
投稿 (Atom)



