2011年11月17日木曜日

Firefox用のWeaveMinimalServerを時短で作ろう

Weave Server


どうも。
いち、プログラマのyu1rowです。
今回は、ZBOXに入れたUbuntu ServerでWeave Minimal Serverを急いで作ってしまおう、って話です。

補足と注意点


[Weave Minimal Serverとは?] 
yu1rowも使っているFireFoxでブックマークや履歴などの設定をいろんなPCやスマートフォンで共有できちゃうサーバです。
Toby Elliott氏とLuca Tettamanti氏により、PHPで実装された無料のソフトウェアです。

[注意点] 

今回作るサーバはセキュリティの考慮はされておりません。
家庭内でブックマークを共有しちゃう想定の、HTTP通信をナマで行うものです。
もしセキュリティが考慮されているどこからでもアクセスできるサーバを作りたいという場合、最低でも以下の作業が必要です。
  • HTTP通信ではなく、SSLで保護された通信を行うようにApacheの設定を行う
  • HTTPSのポート(443番)を空ける
  • ルータ等をかましている場合、NATの設定を行う
  • グローバルIPを所持していない場合、DynamicDNSなどのサービスを使用する
慣れない人は、上記を行うにはちょいと敷居が高いかもしれません。
今回はあくまでライトに、ホームユーズを想定したお話ですのでご注意下さい。

手順


以前ZBOXにインストールしたUbuntu Serverでやったらうまくいきました。
なので、確認した環境はそれだけです。

以下手順です。
  1. Apache2、php、sqliteをインストール
    $ sudo apt-get -y install apache2 php5 php5-sqlite

  2. 80番ポートを開ける
    $ sudo ufw allow 80

  3. WeaveServerをインストールする
    $ sudo wget -P/var/www/ http://people.mozilla.org/~telliott/weave_minimal.tgz
    $ tar xzf /var/www/weave_minimal.tgz -C /var/www/
    $ sudo chown -R www-data. /var/www/weave_minimal
    $ printf 'Alias /weave /var/www/weave_minimal/index.php\n' | sudo tee /etc/apache2/conf.d/weave
    $ sudo /etc/init.d/apache2 restart

  4. WeaveMinimalServer初期化
    ※セオリーではブラウザからアクセスするんですが、面倒なんでコマンドラインから以下のように叩きました
    printf "GET /weave/1.0/blah/info/collections HTTP/1.0\n\n^C\n" | telnet localhost 80

    ※以下のURLにブラウザからアクセスして、出てきた認証ダイアログで「キャンセル」でも初期化できます
    http://(サーバのアドレス)/weave/1.0/blah/info/collections HTTP/1.0

  5. WeaveServerにユーザを追加する
    ※「(c)reate」を選び、メールアドレス(実はメールアドレスじゃなくてもいい)、パスワードを入力します
    $ sudo php /var/www/weave_minimal/create_user

  6. FireFoxの設定
    手元にあったFirefox 8.0でSyncサーバの設定をしてみました。
    [ツール] → [オプション]
    [Sync] → [Firefox Sync をセットアップ]
    [すでに Firefox Sync アカウントを持っています] → [接続]
    下のほうのリンク、[他の Sync デバイスを持っていない]
    ■アカウント上記で追加したユーザのメールアドレス
    ■パスワード上記で追加したユーザのパスワード
    ■サーバ[独自サーバを使用する...] -> http://(サーバのアドレス)/weave/
    ■Sync キー適当に。他の場所で設定するときに同じものを使う。ってことを覚えておこう。
    [次へ] → [セットアップが完了しました] → [完了]

ねっ?カンタンでしょ?
これもメンドイって思った人は以下の方法で。

時短っ!


チマチマ手順踏むのんも面倒って人のための対話式スクリプトを作りました。
Download script

これをダウンロードして実行権限を与えた後、直接実行して使います。
前回までの流れで作った、ZBOX nanoに入れたUbuntu Serverではうまく動きました。
きっとUbuntuならうまくいくんじゃないでしょうか?保証できませんけどw

サーバー作るのもメンドクサイって?
だまらっしゃい!

iPhoneのFirefoxHomeでつながらないよ


Weave Minimal Serverのスクリプト書き換えが必要です。
※書いてます。待ってね。

2011年11月13日日曜日

ZBOX nano に入れた Ubuntu Server にリモート接続する

Ubuntu Serverにちょっと触れる


どうも。
いち、プログラマのyu1rowです。
今回は、前回インストールが終わったUbuntu Serverをイジります。

課題1:電源を入れても画面(テレビ)に表示されない


インストールは我が家のテレビ(REGZA)に繋いで行いました。
そして完了後、そのまま操作を続けようとしたら何も表示されなくなりました。
これはバーチャルコンソールを使うという方法で前回は逃げていましたが、今回コレを解決しようと思います。

解決する方法はたったの2ステップ!

[1.ブートローダ(GRUB)の設定をイヂる]
ウンチクは置いときましょう。
とにかく設定ファイル(/etc/default/grub)の"GRUB_CMDLINE_LINUX_DEFAULT"に"nomodeset"を書くと、テキストがズラズラーっと流れていく昔ながらのLinuxの起動画面にできます。
低解像度になりますが、どうせ後で他のパソコンから接続するようにするんだからどーでもいい。
$ sudo vi /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT='nomodeset'

※ファイル修正後に以下のようにupdate-grubコマンドで設定を反映しないと意味が無い。忘れないこと。
$ sudo update-grub

[2.再起動]
$ sudo reboot

以上です。

課題2:インターネットに繋げる


我が家ではDHCPサーバが既に稼動してまして、たぶんブロードバンドルータなどを使用している場所では大体DHCPサーバが動いてると思います。
そんなワケで、IPを自動で取得するなら以下の設定だけでOK。
あ、固定IPを割り振る設定方法はググって下さいw

[まずはeth0があるか確認]
ZBOX nanoでは以下のコマンドでeth0、wlan0、loが列挙されるハズ。
$ ifconfig -a

[設定ファイルの修正]
確認できたら今度は設定ファイル(/etc/network/interfaces)をいぢる。
$ sudo vi /etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
※1、2行目は最初からあると思う。今回は4、5行目を追加。

[ネットワークの有効化]
設定ファイルを変更したら、以下のコマンドでネットワークを有効化できるはず。
$ sudo /etc/init.d/networking restart

[疎通確認]
googleさんに5回ほどpingでも送って確認してみましょか。
$ ping -c 5 google.com
↓こんな感じのメッセージが最後に表示されたら成功!
--- google.com ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 55.000/55.000/55.000/0.100 ms

閑話:vimをインストールする


設定ファイルを編集しながら、なんかviがすんげぇ使いづらいなぁって思ってたんです。
こりゃ普通のvimじゃないなぁって思って調べてみました。

"vi"を知らない?ちょー有名なテキストエディタだよ!ちょー有名なんだってばよ!
Windowsなら"メモ帳"って感じ?Linuxにはだいたい入ってる。
使い方から歴史まで、いろんな情報はグーグル先生が知ってる。
先生、詳しい説明はお願いします!
ちょー有名なテキストエディタにはemacsなんてのもあるけど、俺はダンゼンvi派!
viなんてどーでもいいよ!って人は閑話は読み飛ばしちゃってもかまいません。でもvi使おうよ。

まず、viのある場所を確認。
$ whereis vi
vi: /usr/bin/vi /usr/share/man/man1/vi.1.gz
そしたら、見っけたファイルを見てみる。
$ sudo ls -al /usr/bin/vi
lrwxrwxrwx 1 root root 20 2011-11-14 00:00 /usr/bin/vi -> /etc/alternatives/vi
/etc/alternatives/viにリンクしてるらしい。更に掘り進む。
$ sudo ls -al /etc/alternatives/vi
lrwxrwxrwx 1 root root 17 2011-11-14 00:00 /etc/alternatives/vi -> /usr/bin/vim.tiny
↑実体見っけました!・・・で、vim.tinyって何?って思ったときは迷わずググる。"vim-tiny"はvimの簡易版らしい。
っちゅーワケでネットにも繋がったし、vimの通常版をインストールすることにした。
インストールは(ネットに繋がっていれば)コマンド一つでOK!カンタン!
$ sudo apt-get install vim

実体はどうなったかな・・・?
$ sudo ls -al /etc/alternatives/vi
lrwxrwxrwx 1 root root 18 2011-11-14 00:00 /etc/alternatives/vi -> /usr/bin/vim.basic
↑よし!vim.basicに切り替わってた!これでviコマンドで使い慣れたvimが使える!よかったよかった!

課題3:OpenSSHをインストールする


いつまでもテレビに繋ぎっぱなしだと家族に怒られちゃいます。
そこで、他のパソコンから操作できるようにSSHサーバを入れてみます。
あ、ちゃんとインターネットに繋がるようにしてからじゃないとダメだかんね?

[探してみる]
Ubuntuのパッケージソフトを管理するソフトは"apt"っていうらしい。
単純に使うだけの表面上のお付き合いはそんなに難しくない。
まずはインストールできるソフトの一覧を更新して、その中かからお目当てのSSHサーバを探してみる。
SSHサーバの名前は"openssh-server"ってのは知ってるけど、一応探してみるんだ。自己満足で。
更新は"apt-get update"、検索は"apt-cache search"
$ sudo apt-get update
$ apt-cache search openssh-server
openssh-server - secure shell (SSH) server, for secure access from remote machines
↑ちゃんと"openssh-server"があった。

[そしてインストール]
ちょーカンタン。"apt-get install"でインストール。
$ sudo apt-get install openssh-server
インストール中に出てくる
[The following extra packages will be installed] は、インストールするソフトに必要な、他のソフト一覧、
[Suggested packages] は、そのほかオススメソフト一覧、
らしい。
Do you want to continue [Y/n]?って聞かれたら、"y"でインストールが始まる。

[繋いでみる]
インストールが終わったら、SSHサーバがちゃんと動いているか確認してみる。
自分で自分に繋ぐのが一番手っ取り早い。
$ ssh localhost
Are you sure you want to continue connecting (yes/no)? yes
steve@localhost's password: (パスワード)
↑初めて繋ぐときは公開鍵をローカルに保存したりとか、色々ごちゃごちゃやりますが、"yes"で接続できます。
ウェルカム的なメッセージが出たら接続成功!
↓接続を切るときは、"exit"とか"logout"で。
$ exit

課題4:ファイアーウォールを設定する


サーバーを運用するにはセキュリティってモノを考えるべきです。
今回は、外から誰かがサーバに繋ごうとすると全部シカトする設定をします。
でも、SSHサーバをインストールしたのでその接続だけは受け入れてやります。

設定には他のLinuxでもおなじみの"iptables"が使用できます。
でも、Ubuntuではカンタンにファイアーウォールの設定ができる"ufw"っていうコマンドがありました。
楽チンなんで、今回はこれを使います。

[ファイアーウォールを有効にして、接続をシカトする]
"ufw enable"でファイアーウォールを有効にします。
$ sudo ufw enable

[SSH(22番)だけ受け入れる]
SSHの接続には22番のポートを使用します。
"ufw allow"で22番の接続だけは受け入れてやります。
$ sudo ufw allow 22

[ファイアーウォールの状況、ルールを確認する]
ファイアーウォールが動作(active)しているか、22番ポートは許可されているかを"ufw status"で見てみます。
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere
22                         ALLOW       Anywhere (v6)
↑ファイアーウォールは有効(active)、22番だけ許可されている。

[ルールを消したり、リセットしたりする]
許可を取り消したい場合、"ufw delete allow"を、全部の許可ルールをリセットしたい場合、"ufw reset"を行います。
$ sudo ufw delete allow 22
$ sudo ufw reset

[ファイアーウォールを無効にする]
ファイアーウォールを無効にする場合、"ufw disable"とします。
これを実行した場合、全部の接続を受け入れることになります。
$ sudo ufw disable

[IPアドレスの調べ方]
他のパソコンから接続するには、接続する先のIPアドレスを知らなければなりません。
自分自身のIPアドレスが何なのか"ifconfig"を使用して調べます。
$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 00:11:22:33:44:55
          inet addr:192.168.1.15  Bcast:192.168.1.255  Mask:255.255.255.0
"inet addr"のところの"192.168.1.15"ってなってるのがIPアドレス。

[他のパソコンから繋いでみる]
ちゃんと設定ができたら他のパソコンからSSHのクライアントソフトで22番ポートに繋げることができるはずです。
SSHクライアントソフトは無料のものがいくつもあります。
俺はその中でも良く使われている"putty""Poderosa"を併用しています。
サーバのIPアドレスがわかったら、繋いで確かめてみましょう。
SSH接続に必要な情報は以下の通りです。
ホスト(IPアドレス)上記で調べたIPアドレス。
ポート番号普通は22番。
SSHプロトコルバージョン今回入れたOpenSSHは、設定を変えなければバージョン"2"。
ユーザID接続するユーザID(今回の例では"steve")。
パスワードパスワードで認証する場合、ユーザのパスワード。
エンコーディング文字の表示方式です。UbuntuのデフォルトはUTF-8。
他のパソコンから操作できるようになったらもうテレビに繋ぐ必要もありません。
HDMIケーブルなんか引っこ抜いちゃいましょう!
まぁ、テレビ使い続けるってのもひとつのテですけどね?

番外編:タイムゾーンを変更する


本筋とは全然関係無いんですが、自分用のメモです。
Ubuntuのインストールをした後にタイムゾーンを変更したい場合、以下のコマンドを使用します。
ここで"Asia/Tokyo"を選ぶと日本時間(JST)を使用する設定に変更できます。
$ sudo dpkg-reconfigure tzdata

ZBOX nano に Ubuntu Server をインストールする

あらあらー、おやおやー、それからどんどこしょー?


どうも。
いち、プログラマのyu1rowです。
最近買ったZBOX nanoにLinuxを入れて遊ぼうと思いまして。
どんなディストリビューションを入れようかと色々悩んで、結局Ubuntu Serverを選択しました。
そんでもって前回、ブート可能なインストール用フラッシュメモリを作成しました。
さて、インストールはどうなったんでしょうか?ってのが今回のお題。

結論から言うと、インストールは成功


少しばかりの紆余曲折はあったものの、インストールは成功しました。
ただ、いくつかの注意点を挙げておきます。
  • フラッシュメモリはUSB3.0(青い方)に繋いではいけない
  • 前回作ったフラッシュメモリはレスキューモードを使う必要がある
  • レスキューモードインストールなので、途中(パーティーション作るところ)でちょっと迂回が必要
  • インストール直後、画面が見えなくなったらCtrl+Alt+F1で仮想コンソールを使う
こんなところでしょうか。
あとインストール中、「もう全然ダメ、最初からやり直したい!」 ってなったら[Ctrl]+[Alt]+[Del]で再起動したって下さい。

さて、具体的な紆余曲折っぷり、お暇な方は以下を見ていって下さい。

まずは、ZBOXに色々ブっ刺す


XBOX・・・じゃなかった、ZBOXに色々刺します。
刺したものは以下のとおり。
  • 使い古したUSBキーボード(普通の109日本語キーボード)
    確か、日本橋の古ぼけた電気屋で昔500円くらいで買ったヤツ
  • 前回作っておいたフラッシュメモリ
    これ、USB3.0の端子(端子の中が青色になっている方)に繋ぐと、インストール途中で進めなくなってしまうんで注意!
  • お手軽だったんで、HDMIケーブルでリビングに置いてあるテレビ(REGZA)に繋いでみた
  • 当たり前やけど、ACアダプタ刺さんと、電源入らへんよ?
この状態で前面パネル左下の電源ボタンを押すと、カワイイ音を出してZBOXが起動します。

閑話:BIOS設定画面と起動デバイス選択


話の本筋とは関係ありませんが、豆知識です。
ZBOXの起動直後に特定のキーを押すと、BIOS設定したり、起動デバイスを選択したりできます。
  • [DEL] Key
    ZBOXのBIOSセットアップ画面を表示させることができる。
    今回は日付と時刻を調整してみた。
    日付と時刻は[Main] - [System Date], [System Time]で設定できる。
    設定したら、[Save & Exit] - [Save Changes and Exit] - [Yes]で保存して終了。
  • [F7] Key
    システムの起動元のデバイスを選ぶことができる。
    BIOSであらかじめ起動デバイスを選ぶのが面倒な時に便利かも。
    今回、インストールにフラッシュドライブを使うので、[Please select boot device]と表示されているところでフラッシュメモリ(例:[I-O DATAUSB Flash Disk AB])を選ぶ。「AB」ってなんだ?

閑話休題:インストール開始!


っと意気込んでみたものの、フラッシュメディアから起動した画面で、[Install Ubuntu on a Hard Disk]を選んでみてもウンスン言いません。全然ダメ。
色々試してみて、[Advanced options] > [Rescue a broken system] でインストールできそうな画面が出てきました。
困ってた人、コレを選びましょうねw
※なんで「Insutall Ubuntu」がダメだったのかは未調査です。知ってる人教えてー!

よし、ガンガンいこうぜ!


あとはまぁ、日本人ですから「日本語」を選んでみたりとか、そーいうのはありますけど、適当にガンガンとインストールを進めていきます。
インストールの時に選んだオプションをご紹介します。
  • [Language] -> [Japanese - 日本語]
  • [国・領土・地域] -> [日本]
  • [Detect keyboard layout?] -> [いいえ]
  • [キーボードが由来する国] -> [日本語]
  • [キーボードのレイアウト] -> [日本語]
    ※今回使ったのは一般的な109キーボードなんで…
    ※このあと、ロードとかでちょっと待つ。ソワソワせずに、待ってやる。
  • [プライマリネットワークインターフェイス] -> [eth0] -> [キャンセル]
    ※LANケーブルも刺さなかったし、無線LANの設定も面倒だったので…当然[ネットワークの自動設定に失敗しました]って出るけど、まぁ気にせず[続ける]を選択。
  • [ネットワークの設定方法] -> [今ネットワークを設定しない]
    ※ネットワークの設定は後ですることにした。
  • [ホスト名] -> [pooh] -> [続ける]
    ※サーバー名にはよく神話の神々の名前、星座なんかが使われるけど、ディズニーキャラクターの名前使っている人がいるのを見て真似してみた。今回は邪悪なる天然蜂蜜熊、「pooh(プーさん)」を使う。
    ※ここで「pooh.hogehoge.com」みたいなFQDN名を使うとダメみたい。ちょっと怒られる。
  • [ルートファイルシステムとして使うデバイス] -> [戻る]
    ※ココ、今回の注意点!レスキューモードでインストールしているので、ハードディスクをマウントしようとする。
    買ったハードディスクは新品、フォーマットもされていなくてもちろんマウントできないので、
    [戻る]を選択して以下のステップを進めていくこと。
  • [インストールプロセスの次のステップの選択] -> [ディスクのパーティショニング]
  • [パーティショニングの方法] -> [ガイド - ディスク全体を使う]
    ※面倒だったんで勝手にやってもらった。もちろん自分で設定したい人は手動でやってもいいよ!真似しなくてもいいよ!
  • [パーティショニングするディスクの選択] -> [TOSHIBAの500GBのハードディスク]
    ※今回買って繋いであるハードディスクを選択した...っていうか、選択肢がこれしかなかったwもちろん、違うメーカーのハードディスクとか、SSDを買った人は違う表示がでるかんね!
    このあと、↓のような表示が出た。
    • [パーティション1] -> [ext4]
    • [パーティション5] -> [swap]
    うーん…容量の振り分けは表示されない。まぁいいけど。
    そしてデフォルトのファイルシステムext4
    みんな待ってた(?)ext4!少なくとも俺は待ってたext4!やったね!
    ext3の弱点を補ったファイルシステム!詳しくはググれ。
  • [ディスクに変更を書き込みますか?] -> [はい]
    ※この直後、ハードディスクの中身が消えるから注意!パーティショニングされるのをしばらく待つべし。
  • [新しいユーザの本名(フルネーム)] -> [自分の名前を入れる(例:Steve Jobs)]
  • [あなたのアカウントのユーザ名] -> [ユーザIDを入れる(例:steve)]
  • [新しいユーザのパスワードを選んでください] -> [パスワードを入れる]
  • [確認のため、再度パスワードを入力してください] -> [もっかいパスワードを入れる]
  • [ホームディレクトリを暗号化しますか?] -> [※お好みで]
    ※今回俺は暗号化せんかった。
  • [このシステムのアップグレードをどのように管理しますか?] -> [※お好みで]
    ※今回俺は自動的にアップデートするようにしてみた。
  • [インストールするソフトウェアの選択] -> [※お好みで]
    ※今回俺はとりあえず何も選ばんかった。
  • [マスターブートレコードに GRUB ブートローダをインストールしますか?] -> [はい]
    ※インストールせな、起動してくれへんでw
  • [システム時間を UTC に設定していますか?] -> [いいえ]
    ※俺は家のPC全部をJSTで統一することにしている。Windows(J)デフォルトもJSTやし。[はい]でUTCにしても普通は全く問題ないと思う。
これで、インストールが始まります。

終わったー!再起動再起動…って何も見えへんやんけ!!!


再起動しても、動いているように見えるのに、TVに何も表示されんくなりました。
理由はなんとなく想像つくんですが、まぁそれは省略。
どうすりゃいいのかだけ簡潔に申しますと
  • [Ctrl]+[Alt]+[F1]を押す
    ※[F2]~[F6]のどれでもいいけどね!
「仮想コンソール」って機能を使うときの常套手段なんやけどね。
これでテキストのログイン画面が出てきます。
今回の例だと、こんな感じ。
pooh login: 
ここでユーザIDを入れて[Enter]、パスワードを入れて[Enter]、これでウェルカム的なメッセージが出てきたらインストール&ログイン完了!

お疲れ様っした!!

次何しよう?


次、こんなことします
  • 電源入れたのに、テレビに何も表示されないのをどうにかしてみる
  • インターネットに繋がるように設定をする
  • ファイアーウォールの設定をする
  • テレビに繋がなくても操作できるように、他のPCからつなげられるようにする(OpenSSHをインストール&設定する)
です。
お楽しみに!

2011年11月8日火曜日

iTextでバーコードを作ってみる

バーコードの画像を作りたい


どうも。
いち、プログラマのyu1rowです。
Javaでバーコードを作るのに手っ取り早い方法を探してみたんですが、iTextでうまくいきましたので、備忘録を残します。

PNGファイルに保存するサンプルソース


今回使用したiTextのバージョンは2.1.7です。
ちょっと長いのでソースを折りたたんでます。
package com.yu1row.blog;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import javax.imageio.ImageIO;

import com.lowagie.text.pdf.Barcode;
import com.lowagie.text.pdf.Barcode128;
import com.lowagie.text.pdf.Barcode39;
import com.lowagie.text.pdf.BarcodeCodabar;
import com.lowagie.text.pdf.BarcodeDatamatrix;
import com.lowagie.text.pdf.BarcodeEAN;
import com.lowagie.text.pdf.BarcodeInter25;
import com.lowagie.text.pdf.BarcodePDF417;
import com.lowagie.text.pdf.BarcodePostnet;

public class MakeBarcode {
 private static final Color COLOR_FORE = Color.BLACK;
 private static final Color COLOR_BACK = Color.WHITE;
 private static final String CODE_CODE128 = "yu1row.com";
 private static final String CODE_CODE39 = "YU1ROW.COM";
 private static final String CODE_CODEBAR = "A12345B";
 private static final String CODE_DATAMATRIX = "DATAMATRIX!";
 private static final String CODE_EAN = "49111111111111";
 private static final String CODE_INTER25 = "1234";
 private static final String CODE_PDF417 = "yu1row.com";
 private static final String CODE_POSTNET = "555551234";

 public static void main(String[] args) {
  make(new Barcode128(), CODE_CODE128, "CODE128.png");
  make(new Barcode39(), CODE_CODE39, "CODE39.png");
  make(new BarcodeCodabar(), CODE_CODEBAR, "CODEBAR.png");
  make(new BarcodeDatamatrix(), CODE_DATAMATRIX, "DATAMATRIX.png");
  make(new BarcodeEAN(), CODE_EAN, "EAN.png");
  make(new BarcodeInter25(), CODE_INTER25, "INTER25.png");
  make(new BarcodePDF417(), CODE_PDF417, "PDF417.png");
  make(new BarcodePostnet(), CODE_POSTNET, "POSTNET.png");
 }

 private static boolean make(Barcode barcode, String code, String fileName) {
  barcode.setCode(code);
  return writeToPngFile(barcode.createAwtImage(COLOR_FORE, COLOR_BACK), fileName);
 }

 private static boolean make(BarcodeDatamatrix barcode, String code, String fileName) {
  try {
   barcode.generate(code);
   return writeToPngFile(barcode.createAwtImage(COLOR_FORE, COLOR_BACK), fileName);
  } catch (UnsupportedEncodingException e) {
   return false;
  }
 }

 private static boolean make(BarcodePDF417 barcode, String code, String fileName) {
  barcode.setText(code);
  return writeToPngFile(barcode.createAwtImage(COLOR_FORE, COLOR_BACK), fileName);
 }

 private static boolean writeToPngFile(Image image, String fileName) {

  // ImageをBufferedImageに変換
  BufferedImage bimg = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
  Graphics g = bimg.getGraphics();
  g.drawImage(image, 0, 0, null);
  g.dispose();

  // BufferedImageをファイルに保存
  try {
   ImageIO.write(bimg, "PNG", new File(fileName));
  } catch (IOException e) {
   return false;
  }
  return true;
 }
}

日本でよく使われるのってあんまり無いですけどね。
実装が面倒な色々の手間が省けて良いと思います。

ZBOX nanoにUbuntuをインストールするためのUSBメモリを作る

Fedoraはやめて、Ubuntuに


どうも。
いち、プログラマのyu1rowです。
ZBOXにFedoraを入れようと思ってたんですけど、急に心変わりしてUbuntuを入れることにしました。
なんかけっこう流行ってるし。

インストールするのは「Ubuntu Server」。
ZBOXにはCDドライブがないので、USBメモリをブート可能にしてインストールすることにします。

USBメモリを作る前の準備


ちょっと準備。
USBメモリが無けりゃ買おう。
あと、2つほどダウンロードしておく。
  1. 2GB以上のサイズのUBSメモリを用意
  2. Ubuntu ServerのISOイメージをダウンロード
  3. 「Universal USB Installer」をダウンロード
こんな感じでしょうか。
※ダウンロードするISOイメージは「Ubuntu 11.10 - Latest version」の64bitを選択しました。

ブート可能なUSBメモリを作る


今回使ったUSBメモリはBUM-A4G/R。
↑こんなの。
差す部分が出たり引っ込んだりして、キャップがいらない。
だからなんなん?って言われても知らんがな。

ブート可能なUSBメモリをWindowsで作るには「Universal USB Installer」を使う。
今回ダウンロードしたのは「Universal-USB-Installer-1.8.6.8.exe」、これを起動する。
起動したら「License Agreement」が表示されるんで、「I Agree」を選ぶ。
ライセンス条項に同意したくなかったら選ばない。そしたら話は進まない。アレー?
同意したら次の画面で4項目を設定する。

  • Step 1: Select a Linux Distribution from the dropdown to put on your USB
    ドロップダウンからUSBメモリに入れるLinuxディストリビューションを選びます。
    今回は「Ubuntu 11.10」を選びます。
  • Step 2: PENDING: Browse to your ubuntu-11.10*.iso
    ダウンロードしておいたUbuntuのISOイメージファイルを選びます。
    Browseボタンを押すと選択ダイアログが表示されます。
  • Step 3: Select your USB Flash Drive Letter Only
    USBメモリのドライブ文字を選択します。
    今回パソコンに差したらFドライブだったので、「F:¥」を選びました。
  • Step 4: Set a persistent file size for storing changes (Optional)
    データを保持するUSBメモリの領域サイズを指定します。
    作業内容とかを保存しとく領域っぽいんですが...0でもええんかな?
    全部消えちゃっていいので最大サイズを選んでみました。
    ※あんまり意味がなかった。0でいい。
    ここで選んだサイズの「casper-rw」ってファイルが出来上がります。
全部設定できたらCreateを押します。
そしたらこんなん出ます。
「消してインストールしてまうけどホンマにええねんな?
FドライブはホンマにジブンのUSBデバイスなんやな!?」
ってカンジのことを聞いているようです。
迷いが消えたら「はい」を押す。

まぁまぁ待ちます。30分くらいかかるかも?
Step 4の領域サイズを0にしておくと10分くらいかも?
これでブート可能なUSBメモリが完成!・・・したハズ。
次はインストールに挑戦してみよう。

2011年11月7日月曜日

ZOTAC ZBOX nano AD10

ちっちゃいパソコン欲


どうも。
いち、プログラマのyu1rowです。
タイトル通りで、以前からちょっと探してたんです。
ちっちゃいパソコン。
Fedoraインストールして遊ぼうかなと思いまして。

今日、用事があって大阪の電気屋街をウロウロしてて出会いました。
ZOTACの「ZBOX nano AD10」っていうベアボーン。

テレビ(REGZA)のリモコンより縦横がちっちゃい。
っていうか最近テレビのリモコン巨大化しすぎ。

電源を入れるとグリーンの輪が出る。
俺は...まぁまぁ好き。かな。
前面。
オーディオのI/Oやらカードスロットやら。
あと赤外線の受信ポート。
MediaCenter対応のリモコンがついてきたけど、Fedora入れるからあんまり意味がない。
背面。
電源にHDMIx1、DisplayPortx1、USB3.0x2、USB2.0x2、eSATAx1、RJ45(GBit)x1
あとKensingtonLockも付いて盗難にも安心!…HDDとか簡単に取り出せてまうけどね。

購入リスト


メモリとHDD、またはSSDを別に買う必要があります。
今回買ったものリストです。余計なものは買ってません。
メーカー型番等説明金額
ZOTACZBOX NANO-AD10ベアボーン¥24,780
TOSHIBAMK5076GSX(2.5inch SATA 500GB)ハードディスク¥5,950
TranscendJM1066KSN-4G(4GB DDR3 1066 SO-DIMM)メモリ¥1,880
合計金額¥32,610
メモリの安さに度肝を抜かれました。
今ってこんな安いのん!?

ベアボーンのZBOX NANO、チップセットがAMDのHudson-M1ですって。
Hudsonって聞くと某CIツールを思い出します。今はJenkinsですが。そして関係ありません。
 このチップセット、GbitLANやらUSB3.0やらその他諸々新しいI/Fが詰め込まれててよろしいです。
楽しみです!気に入りました!

APU(CPU+GPUのことらしい。AMDの呼び方)がAMD Fusion E350 APU。
※APUは "Accelerated Processing Unit" の略らしい。"Accelerated"あたりに言葉の陳腐化を感じる

正直性能は知らんが省電力なんですって。

セットアップというか、組み入れ


ZBOXを開腹して、メモリとHDDを入れるだけ。超簡単。

今回入れるモノ達。
ちっこい。こんなんにホンマに500GBとか入るん?
ホンマに4GBとか保持できてまうん?
ハンダごてじゃ作れなさそうなことは確か。

あけたとこ。
やっぱちっちゃい。
これ規格とかって名前あるのん?
Micro-ITXとか??もっとちっこいの?
最近の規格はわからん。

入れたとこ♥
うーん...簡単すぎてどーしょーもない。なんの障害も感じない。
まぁベアボーンってそういうモンなんでしょう。

閉めたとこ。
底のゴムがネジになっている。
指で開け閉め簡単。なんの障害も感じない。
ねじ山がなめるとかありえない。

力尽きた


眠くなってしまったので、インストールとかはまだ。
とりあえずTV(REGZA)にHDMIケーブルで繋いでみた。
なんかシステムが入ってないとかいうメッセージは出た。
うん。知ってる。

次はFedoraを入れよう。
今バージョンは・・・15?知らん間にまたバージョン上がってまんがな。
って思ってたら、あと2日でバージョン16がFinal Releaseの予定ですって!!
ちょっとwww
2日後ダウンロードして入れてみよう。

2011年9月9日金曜日

サービス停止を待つ

どうも。
いち、プログラマのyu1rowです。

今回は小ネタです。
タスクスケジューラなんかで、以下のような事をしようとしまして
  • Apacheを終了
  • なんかゴニョゴニョ作業する
  • またApacheを起動

まず、コマンドプロンプトとかからApacheのサービスを停止するには、以下のようなコマンドを使います

> sc stop Apache2.2

起動する場合は、こう

> sc start Apache2.2

しかし、バッチファイルで連続して処理を行う場合は、sc stopコマンドはすぐ終わってしまいますが、終了処理に時間がかかるのでサービスはまだ停止していない、みたいな事になります。
これを待ちたいなぁと思いまして。

なんとかして作ったバッチファイルが、これ
@ECHO OFF
SET servicename=Apache2.2

REM ***** Apacheの停止
sc stop %servicename% > NUL

REM ***** Apacheの停止待ち
:JOIN
ping localhost -n 1 > NUL
sc stop %servicename% > NUL
SET status=%ERRORLEVEL%
IF %status%==1061 GOTO JOIN

REM ***** ゴニョゴニョなんか処理する
REM GONYOGONYO

REM ***** Apacheの開始
sc start %servicename% > NUL

※Windows 7でしか試してません
※管理者権限じゃないといけません

大事なのは、9行目と11行目。
完全に停止していないうちにもう一回sc stopすると、ERRORLEVELに1061が返ります。
そして、完全に停止していたら1062が返ります。
多分、これでうまくいくんちゃうかな?
ご利用は自己責任で☆

※追記
ERRORLEVELに返って来る1061や1062だとかいうコード、一体何か?
ADVAPI32.DLLのControlServiceが返すコードの模様。
以下1061,1062についてのみ抜粋
コード意味
ERROR_SERVICE_CANNOT_ACCEPT_CTRL(1061)サービスの状態が SERVICE_STOPPED、SERVICE_START_PENDING、SERVICE_STOP_PENDING のいずれかであるため、要求された制御コードをこのサービスへ送信できません。
ERROR_SERVICE_NOT_ACTIVE(1062)このサービスはまだ開始されていません。

詳しくはココ

2011年9月5日月曜日

画像を色抜き合成する(改良)

どうも。
いち、プログラマのyu1rowです。
以前に書いた、「画像を色抜き合成する」なんですが、アンチエイリアスのかかった画像なんかではフチなんかが汚くなってしまいます。
まぁ、「白」と決めたら「白」のみが透明になって、「白っぽい色」はそのままになるんで 当然なんですが。
そこで、「っぽい色」も透明になるように改良します。

「っぽい色」はどう判定する?


色を「赤・緑・青」の三要素で考えるとき、ある色と「近い」かどうかは、その距離を計算することで何とかなりそう。
2つの値の距離は中学生頃に習った「ピタゴラスの定理」が使えると思う。
2次元、3次元どちらにしてもこの定理で距離が求められるので、「赤、緑、青」を3次元空間の座標とみなして、調べる色と、期待する色がその空間でどの程度の距離なのかを以下のように計算。
  • 距離 = sqrt( (r1-r2)^2 + (g1-g2)^2 + (b1-b2)^2 )
※sqrt : 平方根
※r1, r2 : 画像の特定のピクセル、色抜きする色の赤成分の値(0~255)
※g1, g2 : 画像の特定のピクセル、色抜きする色の緑成分の値(0~255)
※b1, b2 : 画像の特定のピクセル、色抜きする色の青成分の値(0~255)

閾(しきい)値についてちょっと


距離が一定(閾値)以下の場合、「っぽい色」と判定して距離に応じて重ね合わせる画像に透明度を設定して完了!
これでうまくいったかな?って思って、適当な画像を重ね合わせてみたトコロ...まぁまぁうまくいってそう?
閾値を画像によってイイカンジに計算できりゃ完璧なんでしょうが、まぁメンドイので今回は以下のカンジで妥協。
  • 閾値 = ( (255^2) * 3 ) * 0.5
言葉にすると、「一番遠い色」を100%としたときに、50%までの距離を閾値とする、ってカンジです。

何はともあれ、今回のソースっす!


package com.yu1row.blog;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;

public class Practice03 {
    /**
     * 画像同士を合成した {@link BufferedImage} を取得します。
     * <p>
     * 元画像に対し、重ね合わせ画像の特定の色を透明にし、
     * 元画像に重ね合わせて合成画像を得ます。
     * </p>
     * @param src 元画像
     * @param lay 重ね合わせ画像
     * @param alphaColor 重ね合わせ画像の透明色
     * @return 合成画像
     */
    public static BufferedImage getOverlayedImage(
            BufferedImage src, BufferedImage lay, Color alphaColor) {
        if (src == null) { return null; } // 元画像がnullの場合
        if (lay == null) { return src; } // 重ね合わせ画像がnullの場合

        // 色抜きされたイメージを作成(近似割合50%)
        Image alphaImage = getTransparentImage(lay, alphaColor, 0.5);

        // 結果画像を作成
        // 元画像のクローンに、色抜きイメージを描画してオーバーレイを行う
        BufferedImage result = getBufferedImageClone(src);
        Graphics g = result.getGraphics();
        g.drawImage(alphaImage,0,0,null);
        g.dispose();

        return result;
    }

    /**
     * {@code src} の {@code alphaColor} に近い色を透明色にします。
     * <p>
     * {@code alphaColor} に近い色が透明色となります。
     * {@code transRate} に指定された割合で近似色と判断されます。
     * </p>
     * @param src 透明色を設定するイメージ
     * @param alphaColor 透明色にする色
     * @param transRate 近似割合(0.0~1.0)
     * @return 透明色が設定されたイメージ
     */
    private static Image getTransparentImage(
            BufferedImage src, Color alphaColor, double transRate) {
        if (src == null) { return null; } // 元画像がnullの場合

        // 閾値
        final double threshold = ( Math.pow(255.0, 2.0) * 3 ) * transRate;
        // 画像のサイズ取得
        int width = src.getWidth();
        int height = src.getHeight();
        // 画像→int[]変換
        int[] pixel = new int[width*height];
        PixelGrabber pg = new PixelGrabber(src,0,0,width,height,pixel,0,width);
        try { pg.grabPixels(); } catch (InterruptedException e) { return null; }
        // 画像の色抜き(透明度設定)
        for(int i = 0; i < width * height; ++i) {
            // 色の距離を計算
            int r = (pixel[i] >> 16) & 0xFF;
            int g = (pixel[i] >>  8) & 0xFF;
            int b = (pixel[i] >>  0) & 0xFF;
            double distance =
                    Math.pow((double)(r - alphaColor.getRed()), 2.0) +
                    Math.pow((double)(g - alphaColor.getGreen()), 2.0) +
                    Math.pow((double)(b - alphaColor.getBlue()), 2.0);
            // 閾値を超えていなければ、透明度設定
            if (distance < threshold) {
                double ratio = (threshold - distance) / threshold;
                pixel[i] ^= (int)(255.0*ratio) << 24;
            }
        }

        // 色抜きされたイメージを作成
        return Toolkit.getDefaultToolkit().createImage(
                new MemoryImageSource(width, height, pixel, 0, width));
    }

    /**
    * {@link BufferedImage} のクローンを取得します。
    * @param src 元の {@link BufferedImage} オブジェクト
    * @return {@link BufferedImage} のクローン
    */
    private static BufferedImage getBufferedImageClone(BufferedImage src) {
        if (src == null) { return null; } // 元画像がnullの場合

        // 同サイズ、同タイプのBufferedImageを作成
        BufferedImage dst = new BufferedImage(
                src.getWidth(), src.getHeight(), src.getType());

        // クローンに描画
        Graphics g = dst.getGraphics();
        g.drawImage(src, 0, 0, src.getWidth(), src.getHeight(), null);
        g.dispose();
        return dst;
    }
}
※平方根を計算する Math.sqrt() は、前述の説明では出てきましたが、処理が重いので使ってません。

まぁ自身ねーんですよ、コレ


にも書いたとおり、一応実現しましたがね、歯車の再開発してるようにしか思えないんですよ。絶対とっくに簡単に実現できるAPIとかあると思う。
もっと素晴らしく簡単に実現できる方法、誰か知ってたら教えてください。お願い。

2011年8月29日月曜日

SyntaxHighlighterでソースコードを綺麗に見せよう

どうも。
いち、プログラマのyu1rowです。
ソースコードを載せることもあるブログとしては、綺麗に見せたいですよね。
というわけで、ソースコードを綺麗に整形してくれる"SyntaxHighlighter"を導入することにしました。
実際にBloggerに導入したので、手順をメモします。

どうすりゃいいの?


基本的には3ステップです。
  1. SyntaxHighlighterのダウンロード
  2. ファイルをどこかにアップロード
  3. blog内容を編集

Step.1 ダウンロード


↓以下のサイトからダウンロードしました。
SyntaxHighlighter ダウンロード先(2011/08/28現在)
ちなみに、このときのバージョンは3.0.83。

ダウンロードしたファイルを展開すると、いくつかファイルとフォルダが現れます。
以下の2つのフォルダと、中のファイルを使います。
./scriptsjsファイルが収められています
./stylescssファイルが収められています

Step.2 アップロード


ここに一番時間がかかったように思います。
というのも、Bloggerにはファイルをアップロードすることができず、別のスペースを借りることにしたのですが、Bloggerと同じくgoogleが運営する「サイト」を使ってみたところ、分かりづらくて使いづらくて...
まぁ他に使い慣れているスペースがあるならば、そちらを検討するのもテです。

以下の3つのファイルだけで最低限のことはできますので、お好みのスペースにアップしてください。
./scripts/shCore.js 基本のスクリプトファイルです。
./scripts/shBrushJava.js Javaのソースを整形します。
C#のソースを整形したければ"shBrushCSharp.js"を使います。
他に使用できる言語はここを参照してください。
./styles/shCoreDefault.css 基本のスタイルです。
他のスタイルも色々あるみたいですが、未検証です。

Step.3 blogを編集


最後にblogを編集します。
上記の3つのファイルを<script>タグと<link>タグで<head>タグの中に埋め込みます。
その後に、<script>タグでSyntaxHighlighter.all()という関数を動かすようにします。これで準備完了。

あとは、装飾したいコードを<pre>タグで囲みます。
<pre>タグの"class"属性には"brush: XXXX;"と書きます。
例えばJavaのコードなら、"XXXX"の部分は"java"と書きます。

以下に記述する例を載せておきます。
<html>
<head>
<title>コード装飾の例</title> 
<script type="text/javascript" src="http://yoursite.com/scripts/shCore.js"></script>
<script type="text/javascript" src="http://yoursite.com/scripts/shBrushJava.js"></script>
<link type="text/css" rel="stylesheet" href="http://yoursite.com/styles/shCoreDefault.css"/>
<script type="text/javascript">SyntaxHighlighter.all();</script>
</head> 
 
<body>
<pre class="brush: java;">
public class Hoge {
/** デフォルトコンストラクタです。 */
public Hoge() { } 
}
</pre>
</body>
</html>
  • 4~7行目は順番が重要かもしれません
  • 他の言語を増やしたい場合、5行目の<script>タグを必要に応じて増やします。
    他に使用できる言語については、ここを参照してください。
  • Bloggerの場合は、「デザイン」⇒「HTML の編集」で<head>タグの中に埋め込むようにしました。
これでコードを美しく表示することができました。
他にもテーマだとか、コードを別ウインドウで表示する?機能だとか色々できるみたいです。
皆様それぞれに工夫してみてください。

2011年8月25日木曜日

文字列を中央に描画する

文字列を中央に描画...がうまくできなかった話


どうも。
いち、プログラマのyu1rowです。

例えば画像の中央に文字列を描画したい場合、java.awt.FontMetricsクラスを用いて、文字列が描画されたときの全体のサイズを取得して実現できます。
しかし、これで取得した領域で計算すると、文字がちょっと上にずれます。というか、ずれて見えます。
これは文字列の「ベースライン」を考慮していないからのようです。

とある四角形を、とある領域の真ん中に描きたい場合、描画開始位置の計算は、普通は以下のようになります。
  • x = ( 領域の幅   - 四角形の幅   ) / 2;
  • y = ( 領域の高さ - 四角形の高さ ) / 2;
しかし、java.awt.Graphics.drawString()は「ベースライン」を描画開始位置に合わせてしまいますので、y座標を補正する必要があります。
方法は、ベースラインから文字の上端までの距離をy座標に足すだけで、距離の取得はFontMetrics.getMaxAscent()を使用します。

補正後の描画開始位置の計算は、以下の通り。
  • x = ( 領域の幅   - 四角形の幅   ) / 2;
  • y = ( 領域の高さ - 四角形の高さ ) / 2 + FontMetrics.getMaxAscent();

御託は置いといて


はい、ソースどーん!
package com.yu1row.blog;

import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class Practice01 {

    public static void main(String[] args) throws IOException {
        Rectangle size = new Rectangle(200, 30);
        BufferedImage image = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
        drawStringCenter(image.getGraphics(), size, "よろしくお願いしまーす!");
        ImageIO.write(image, "PNG", new File("center.png"));
    }

    public static void drawStringCenter(Graphics g, Rectangle rect, String text) {
        // Calc draw position
        FontMetrics fm = g.getFontMetrics();
        Rectangle rectText = fm.getStringBounds(text, g).getBounds();
        int x = (rect.width - rectText.width) / 2;
        int y = (rect.height - rectText.height) / 2 + fm.getMaxAscent();
        // Draw text
        g.drawString(text, x, y);
    }
}

アラビア文字など、右から左に書かれる文字列がどうなるのかとか、面倒なんで未検証です。

2011年8月19日金曜日

画像を色抜き合成する

「画像を重ねてよ」って言われて、どうしようかって思ったんです


どうも。
いち、プログラマのyu1rowです。
2枚のBufferedImageがありまして、2枚目の画像の特定の色を透明にしてしまいたいという要件がありました。
なんせあんまりJavaの画像処理のコトしらないし、とりあえず以下のソースのように対処しました。
package com.yu1row.blog;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;

public class Practice02 {
    /**
     * 画像同士を合成した {@link BufferedImage} を取得します。
     * <p>元画像に対し、重ね合わせ画像の特定の色を透明にし、元画像に重ね合わせて合成画像を得ます。</p>
     * @param src 元画像
     * @param lay 重ね合わせ画像
     * @param alphaColor 重ね合わせ画像の透明色
     * @return 合成画像
     */
    public static BufferedImage getOverlayedImage(BufferedImage src, BufferedImage lay, Color alphaColor) {
        if (src == null) { return null; }   // 元画像がnullの場合
        if (lay == null) { return src; } // 重ね合わせ画像がnullの場合

        // 重ね合わせ画像のサイズ取得
        int width = lay.getWidth();
        int height = lay.getHeight();
        // 重ね合わせ画像→int[]変換
        int[] pixel = new int[width*height];
        PixelGrabber pg = new PixelGrabber(lay,0,0,width,height,pixel,0,width);
        try { pg.grabPixels(); } catch (InterruptedException e) { return null; }
        // 重ね合わせ画像の色抜き
        int color = alphaColor.getRGB();
        for(int i = 0; i < width * height; ++i) {
            if (pixel[i] == color) {
                pixel[i] = pixel[i] & 0x00FFFFFF;
            }
        }

        // 色抜きされたイメージを作成
        Image alphaImage = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(width, height, pixel, 0, width));

        // 結果画像を作成
        // 元画像のクローンに、色抜きイメージを描画してオーバーレイを行う
        BufferedImage result = getBufferedImageClone(src);
        Graphics g = result.getGraphics();
        g.drawImage(alphaImage,0,0,null);
        g.dispose();

        return result;
    }

    /**
    * {@link BufferedImage} のクローンを取得します。
    * @param src 元の {@link BufferedImage} オブジェクト
    * @return {@link BufferedImage} のクローン
    */
    public static BufferedImage getBufferedImageClone(BufferedImage src) {
        if (src == null) { return null; }

        // 同サイズ、同タイプのBufferedImageを作成
        BufferedImage dst = new BufferedImage(src.getWidth(), src.getHeight(), src.getType());

        // クローンに描画
        Graphics g = dst.getGraphics();
        g.drawImage(src, 0, 0, src.getWidth(), src.getHeight(), null);
        g.dispose();
        return dst;
    }
}

getOverlayedImage()のsrcにlayを重ね合わせます。
layの中で、alphaColorに指定した色が透明になって透けます。

自信ねーんですよ、コレ


実際コレで一応実現しましたがね、歯車の再開発してるようにしか思えないんですよ。
もっと楽にできる素晴らしいやりかた、誰か教えてください。

※追記
改良?しました

2011年8月11日木曜日

SeekBarとImageButtonのソースっす

ImageButtonでSeekBarの加減算


どうも。いち、プログラマのyu1rowです。
以前に書いた「SeekBarとImageButton」に、リンクで辿ってくる人が多いようです。
せっかく辿っていただいても、ソースがねーよってんじゃあ、ガッカリでしょうね。
そうでもないんかな?
というわけで、一応ソースコードを載っけておきましょう。
我流ですので、悪しからず。

public class MainActivity extends Activity {

    /** アクティビティが作成される初回に呼び出されます。 */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);

        // 加算ボタンのイベント
        ((ImageButton) findViewById(R.id.btnAdd)).setOnClickListener(new OnClickListener() {
            @Override public void onClick(View v) { increment(R.id.sbDisp, 1); }
        });

        // 減算ボタンのイベント
        ((ImageButton) findViewById(R.id.btnSub)).setOnClickListener(new OnClickListener() {
            @Override public void onClick(View v) { increment(R.id.sbDisp, -1); }
        });
    }

    /**
     * シークバーの値を増減します。
     * @param id シークバーの ID
     * @param diff 増減する値 (マイナス値で減算)
     */
    private void increment(int id, int diff) {
        SeekBar bar = (SeekBar) findViewById(id);
        bar.incrementProgressBy(diff);
        bar.incrementSecondaryProgressBy(diff);
    }

}

上記のコードでは、「btnAdd」、「btnSub」というIDのボタンで、「sbDisp」というIDのシークバーの値を増減します。
実際のSeekBarの値を表示してぇよ!って人は、シークバーのsetOnSeekBarChangeListenerでリスナーを登録して、ラベルに値を表示する等してみましょう。
以上ですっ!

JSpinnerのちょっと困った話

JSpinnerを使おうと思いまして


Java+Swingのお仕事が続く毎日、yu1rowです。
スピナーってありますよね。
「増やす」ボタンと「減らす」ボタンが付いてるテキストボックス、みたいな。
数値入力ができるモードで、ちょっと困ったんで、その話。

止まっちゃうんですが!?


50~200まで入力できて、「増やす」と「減らす」ボタンを押すと、25ずつ増えたり減ったりするスピナーを作りました。
「↑」とか「↓」のキーボード入力でも増やしたり減らしたりできます。

ところが。

キーボードからも入力できるんで、「199」とかも入力できるんですね。
でも、「199」の状態で「増やす」ボタンを押しても増えてくれないんですよ。
199+25=224なんで、上限の「200」を超えちゃうからなんでしょうけど…。
こっちとしては、「200」になって欲しいわけです。

反対に、「55」の状態から「減らす」ボタンを押しても同じです。
「50」になって欲しいなぁ…と。

結局どうしたのか?



 ボタンを押したときのイベントと、テキストボックスでキー入力したときのイベントを捕まえて対処しました。
JSpinnerの中には以下のものが入っています
  • JButton (2個)
  • SpinnerModel (1個)
さらに、SpinnerModelの中には以下のものが入っています
  • JFormattedTextField (1個))
この2個のJButtonと1個のJFormattedTextFieldのイベントを捕まえちゃいます。
2個のJButtonにはそれぞれ以下の名前がついています
  • 「Spinner.nextButton」
  • 「Spinner.previousButton」
フレームに"spinner"という名前のJSpinnerがあるとする場合、以下のコードで2個のボタンにイベントを登録できます。
※コード中の「setMinimumValue()」と「setMaximumValue()」というメソッドは後述

for (Component c : spinner.getComponents()) {
    if ("Spinner.nextButton".equals(c.getName())) {
        // 次ボタンのイベント登録
        ((JButton) c).addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setMinimumValue();
            }
        });
    } else if ("Spinner.previousButton".equals(c.getName())) {
        // 前ボタンのイベント登録
        ((JButton) c).addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                setMaximumValue();
            }
        });
    }
}

イベントから呼び出す「setMinimumValue()」と「setMaximumValue()」、そこから使用される「isSpinnerNumberModel()」は以下のように記述します。

/**
 * スピナーのモデルが {@link SpinnerNumberModel} かどうかを取得します。
 * @return スピナーのモデルが {@code SpinnerNumberModel} の場合 {@code true} 、
 * そうでない場合 {@code false}
 */
private boolean isSpinnerNumberModel() {
    SpinnerModel model = spinner.getModel();
    // modelがnull
    if (model == null) { return false; }
    // 数値モデル以外
    if (model instanceof SpinnerNumberModel == false) { return false; }
    return true;
}

/**
 * 最大値を設定します。
 * <p>
 * このメソッドは以下のどれかの条件に当てはまる場合は何も行いません。
 * <ul>
 * <li>スピナーのモデルが {@link SpinnerNumberModel} ではない</li>
 * <li>既に最大値がセットされている</li>
 * <li>次にセットすべき値 ({@link JSpinner#getNextValue()}) が {@code null} ではない</li>
 * </ul>
 * 以上の条件以外の場合、最大値 ({@link SpinnerNumberModel#getMaximum()}) が設定されます。
 * </p>
 */
private void setMinimumValue() {
    if (!isSpinnerNumberModel()) { return; }
    // SpinnerNumberModelにキャスト
    SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel();
    // 既にMaximumであれば無視
    if (model.getValue().equals(model.getMaximum())) { return; }
    // 次にセットするべき値がある場合は無視
    if (spinner.getNextValue() != null) { return; }
    // 最大値をセット
    if (model.getMaximum() != null) { model.setValue(model.getMaximum()); }
}

/**
 * 最小値を設定します。
 * <p>
 * このメソッドは以下のどれかの条件に当てはまる場合は何も行いません。
 * <ul>
 * <li>スピナーのモデルが {@link SpinnerNumberModel} ではない</li>
 * <li>既に最小値がセットされている</li>
 * <li>次にセットすべき値 ({@link JSpinner#getPreviousValue()}) が {@code null} ではない</li>
 * </ul>
 * 以上の条件以外の場合、最小値 ({@link SpinnerNumberModel#getMinimum()}) が設定されます。
 * </p>
 */
private void setMaximumValue() {
    if (!isSpinnerNumberModel()) { return; }
    // SpinnerNumberModelにキャスト
    SpinnerNumberModel model = (SpinnerNumberModel) spinner.getModel();
    // 既にMinimumであれば無視
    if (model.getValue().equals(model.getMinimum())) { return; }
    // 次にセットするべき値がある場合は無視
    if (spinner.getPreviousValue() != null) { return; }
    // 最小値をセット
    if (model.getMinimum() != null) { model.setValue(model.getMinimum()); }
}

キーボードの「↑」と「↓」キーのイベントを捕まえて値を変更させる場合のイベントは、以下のように登録します。
※ここでも前述の「setMinimumValue()」、「setMaximumValue()」、「isSpinnerNumberModel()」というメソッドを使用しています

// SpinnerNumberModelでない場合はイベント登録しない
if (isSpinnerNumberModel()) {
    // JFormattedTextFieldを取得
    JFormattedTextField textField 
        = (JFormattedTextField) spinner.getEditor().getComponents()[0];
    // keyPressedイベントの登録
    textField.addKeyListener(new KeyAdapter() {
        @Override
        public void keyPressed(KeyEvent e) {
            switch (e.getKeyCode()) {
                case KeyEvent.VK_UP:
                    setMinimumValue();
                    break;
                case KeyEvent.VK_DOWN:
                    setMaximumValue();
                    break;
            }
        }
    });
}

一応、これで目的の動作をしているようです。
※ご使用に際しては、自己の責任と計画を以てお願いします

これでよかったんかいな?


上記のようなモノを実装したカスタムしたコンポーネントを作って、今回はやり過ごしました。
ホンマはプロパティーひとつで出来ちゃうような、スマートなやり方があるのかもしれません。
今回はそれが見つけられなかったので、こんな強引なやり方で対処することになりました。
もっとスマートなやり方、募集中です。

2011年8月9日火曜日

JComponentのvisibleChanged?

色々忙しくて全く更新できていません


本業の方では仕事が変更になり、C#からJavaへ使用言語が変わりました。だからというわけでは...あるんですが、備忘録的にメモを残します。

Swingのお仕事


今回のお仕事では、Swingをメインに据えて作業していくことになりました。
そこで戸惑ったのが、C#ではVisibleプロパティを使って、ボタンなど、画面のモノの表示を消したり出したりしていました。
そしたら、Control.VisibleChangedなんてイベントが走りましてね、これを捕まえることができたんですが...

JavaのSwingコンポーネントでは?どうすんの?

何はともあれソースっす


結論から言うと、java.awt.event.ComponentListenerを追加すりゃなんとかなりました。
例えばボタンを作りましてね、そのVisibleを監視するのは以下のように

private void initComponents() {
    JButton button = new JButton("ボタンでっせ");
    button.addComponentListener(new ComponentAdapter() {
        @Override
        public void componentShown(final ComponentEvent e) {
            buttonVisibleChange(true);
        }

        @Override
        public void componentHidden(final ComponentEvent e) {
            buttonVisibleChange(false);
        }
    });
    add(button);
}

private void buttonVisibleChange(boolean visible) {
    System.out.println(visible);
}

  • componentShown() が表示されるとき
  • componentHidden() が消えるとき

見たまんまですね(^ー^

とにかく、C#とはちょっと勝手が違って悪戦苦闘気味ですが、こんな備忘録が増えていくかもしれません。

2011年6月15日水曜日

ポゴちゃんがやってきた

ポゴちゃん


PogoPlugってのを買いましてね
ピンクの

 今日からコイツとの共同生活
もちろん普通に使う気なんてありません
"PlugApps"っていうディストリ入れてみます
とりあえずは、宅内のDHCP,NTP,DNSあたりを
メインサーバから切り離して、コイツで動かそうと思います
愛称は「ポゴちゃん」です
まんまです

とても、小さい



型番とか金額とか


今回買ったのは"Pogoplug POGO-E02(ピンク)"
大体8千円くらいかな?
すげー安い
アメリカではポゴちゃんの後継機が出だしているそうで
"POGO-B03"だとか"POGO-E04"とかいうらしい
俺はそんなハイスペックは求めないのでコレで十分

あと他に買ったもの


USBメモリを買いました
ポゴちゃんに挿すための
4GBくらいの適当なヤツです


これからちょっとコイツと遊ぶことにしました
お楽しみに~^^

2011年5月30日月曜日

Proc Minder

ライブラリを公開します。
特定のアプリケーション(EXE)のプロセスが実行されているか、
監視に使用できるライブラリ(DLL)です。
------------------------------
■Title
Proc Minder
■Version
0.0.1
■Date
2011/05/30
■ダウンロード
Direct link
------------------------------
[vector]   

2011年5月26日木曜日

FlowChartLoop

ソフトウェアを公開します。
エクセルのオートシェイプのフローチャートには
ループの開始/終端がありません。
これはそのオートシェイプを作成するVBAマクロ、
及びテスト用のワークブックです。
誰か使うかなぁ?
------------------------------
■Title
FlowChartLoop
■Version
0.0.1
■Date
2011/05/26
■ダウンロード
Direct link
------------------------------

2011年5月24日火曜日

Change TimeStamp

ソフトウェアを公開します。
コマンドプロンプトやスクリプト内でファイルの
作成日時、更新日時、アクセス日時を変更できる
コマンドラインツールです。
------------------------------
■Title
Change TimeStamp
■Version
0.0.1
■Date
2011/05/24
■ダウンロード
Direct link
------------------------------
[vector]  

ShortcutTool

ソフトウェアを公開します。
ショートカットファイル(*.lnk)の情報を表示する、それだけのツールです。
------------------------------
■Title
ShortcutTool
■Version
0.0.1
■Date
2011/05/24
■ダウンロード
Direct link
------------------------------
[vector]  

2011年5月10日火曜日

FolderButton

ライブラリを公開します。
.NET Framework 2.0以降で使用可能な、
フォルダ選択を行うボタンコントロールです。
------------------------------
■Title
FolderButton
■Version
0.0.1
■Date
2011/05/10
■ダウンロード
Direct link
------------------------------

2011年4月27日水曜日

Get Registry

ソフトウェアを公開します。
レジストリキー/値の存在を確認する、
または値自体を取得する、コマンドラインツールです。
------------------------------
■Title
Get Registry
■Version
0.0.1
■Date
2011/04/27
■ダウンロード
Direct link
------------------------------
[vector] 

Multi Replace

ソフトウェアを公開します。
変更されたファイルのみを更新する、コマンドラインツールです。
------------------------------
■Title
Multi Replace
■Version
0.0.1
■Date
2011/04/27
■ダウンロード
Direct link

------------------------------
[vector] 

2011年3月19日土曜日

SeekBarとImageButton

なぜかSpinnerを使っていた


どうもこんばんは。いち、プログラマのyu1rowです。

練習で作ってたBMIの計算ツール、基本的に身長と体重を入力してもらうワケです。
しかし、入力用に最初に採用したUIがSpinner。
身長、体重の上限下限が決まったとして、その間の値を全部イチイチ入れてました。
すっげめんどい。

さらにまぁ、使ってみると入力の面倒なこと面倒なこと。
何でSpinner?って聞かれても、「何も考えてなかった」ってのが適切な答えでしょうか。
「すぴなー」って響きが耳にきもちぃし、正直てきとーに選びました。
後々SeekBarを使うように変更するワケですが。

SeekBarの微調整をボタンで!


SeekBarを使うように修正いたしますと、指でグリグリ動かすと値が変更できるし、
イベントをめんどうがらずにちゃんと実装すれば、リアルタイムで値が変わるのが見えます。
Androidプログラマ的に、一皮ムケた感じ。。。は別にしませんがね。

ただ、値の範囲が広いと、指でちょいちょいっと微調整するのが非常にめんどい!
ということで、プラスとマイナスボタンを横に置いて、微調整できるようにしました。

でもなー
ボタン長押ししたら、なんかどあーーって変わっていって欲しいねん。
まぁ要するに、ボタン長押しでクリックがリピートして欲しいんですよ。
なんか実装がちょっとばかし面倒そうなので、後日また頑張ってみましょ。
なんか眠くなってきたから寝ましょ。今日はここまで!

追記


(2011/08/11)
検索エンジンでこのエントリにたどり着く人が多いようです。
おそらくソースコードも載せた方がいいんじゃなかろうかと思って、記事を追加しました。
SeekBarとImageButtonのソースっす

2011年3月17日木曜日

多言語対応

どうして多言語化?

自己満足に近しいのかもしれませんが、日本語と英語に対応しておきたいワケです。

文字情報に頼らない、言語フリーなデザインを追い求めていきたいトコロですが。
まあそれは、おいおい。できるときに。無理せずに一般的な方法でいっときましょ。
自分に甘めに、世界に許しを乞いましょ。媚びましょ。

やり方、調べてみた

ハイ、それで実際どうやって日本語と英語を切り替えるの?
って思って、ちょっとぐぐっただけでわかりました。
  • [res] - [values] - [strings.xml] 
ってのが、プロジェクト作ったらありました。
これに加えて同じように
  • [res] - [values-ja] - [strings.xml]
 ってのを加えると、日本語環境用の設定が作れちゃいます。
YAHOO!!って奇声あげながら多言語化完了!

ちょっと、つまづいた

せっかくなんで、英語環境に切り替えてみたら、エラーでアプリが御っ死んでしまいました。
原因は。。。うすうすわかってたんですけどね。

[values]と[values-ja] で共通の部分を、面倒だったんで、ニッポン男児万歳とばかりに、[values-ja]にしか書きませんでした。
ええ、面倒だったんで、[values]の[strings.xml]にはぜんぜん書きませんでした。

これ、モンダイ、です。

英語環境、日本語環境でどっちでも共通のものについては、まとめて[values]の[strings.xml]の方に書けば良かったんです。
[values-ja]に無かったら、[values]の方を探してくれるんですって!婆ちゃが言ってた!!

嘘です。敬愛する[La France Software Design]のisaさんに今日教えてもらいました。YAHOO!!
もっかい作り直して動かしてみたら、今度はエラーになりませんでしたとさ。
とっぴんぱらりの、ぷう。

Android はじめました。

見てくれた奇特な方。こんにちは。
いち、プログラマのyu1rowです。
Android端末を手に入れたので、日曜プログラムを始めます。
うそです。日曜プログラムをしたかったからAndroid端末を手に入れたんです。
とりあえず、縁のあったBMI計算機を作ってみました。
自分の端末で動くのはうれしいです。
で、スクリーンショットってどうやって撮るんかな??