非破壊自炊に使う画像トリミングアプリを作った。

最近家庭内で論文の執筆が行われており
電子版が販売されないような専門書を電子化することに関する需要の高まりがあった。
そのための、非破壊自炊を行うためのものとして以下のような器具が導入された。

これは、Book Shooter MK-Vというもので、 ↓の制作者の方のブログに作り方も公開されている。 tges.blog117.fc2.com www.youtube.com

これを使って本のページの画像が量産された結果、今度は大量にある画像の不要部分をトリミングをするという作業が必要になった。
スマートフォンのカメラを使用して撮影しているため、アプリにするのが都合が良いということでたくさんの画像を切り抜くだけのアプリを作成することにした。
既に公開されているもので使えないか...? とも思ったのだが、切り抜きの範囲指定を数値で入力しないといけないようなものしかなかったので、画像を見ながら範囲指定を行えるようなUIを目玉機能とした。

リリースした

裁断くん

裁断くん

  • Fumiya Kubota
  • Photo & Video
  • Free
apps.apple.com

こんな感じ

機能としては「画像を複数枚選択して全部を同じように切り抜く」以上でも以下でもないんだけど、UIはそれなりに気合いを入れて楽しく制作した。
今後は「大量の画像を全体的に明るくしたい」みたいな需要を狙って簡単な画像処理もできるようにするかもしれないし、しないかもしれない。

おわり

自分の強さと向き合う

Googleの入社エントリが流行した。
東大の入学式の祝辞が耳目を集めた。

僕の学歴は良いとは言えない。というか大卒ですらない。最終学歴は情報系の専門学校卒業だ。
僕の勤務先はGoogleではない。NTTデータでも好調なベンチャー企業でもない。単なる零細の開発会社だ。

自分は小市民であるし、俗物であるからやっぱり東大生に送られた「環境のおかげだったこと忘れないようにしてください。」という言葉や ぼくはこうやって(8年前)Googleに入った - アスペ日記この方の

ぼくがGoogleに入れたのは、遺伝子のおかげじゃなかったら何なんだ?

といった指摘に痛快さを感じてしまった。スカッとジャパンみたいな、見たことないけど。

しかし。
恵まれた環境にいるのは本当に東大生やGoogle社員だけだろうか。
自分は?
確かに自分は凄い人間ではない。冒頭に書いたように学歴があるわけでも、給与が特別多いわけでもない。知能だって平均的だろう。処理能力が特別高いわけでもない。今後何者かになれるとも思わない。
しかし一応エンジニアとして人並み程度の給料をもらえる立場であるし、ささやかながら自分の作ったアプリにレビューやブックマークを付けてもらえるようなものを作ったこともある。
社会の凄い人達は「遺伝子や環境のおかげ」で、僕は可哀想にも凡庸に生まれてしまったからそうではないと?

これは個人的な決意

自分の「強さ」を認めるのは勇気が必要で、とても、難しいものだなと思う。
自分はそんなに能力を肯定されたりしないような感じで生きてきたせいもあるのか、自分の強さについて考えるとそれを否定し、自分を憐れむ言葉がいくらでも浮かんでくる。
CSもよく知らない、英語もできない、ネットワークもよく知らない、コミュニケーション能力が低いからこれ以上伸びしろがないだとか。

けれどもやっぱり、ぼく程度の人間であろうと今この時点の生活にいることは「遺伝子や環境のおかげ」に他ならないと思う。
そして、それは社会の一部の凄い人達「だけ」がノブレスオブリージュ的に持つべきものではなくて、何か一つでもできることがあると思える人は持つべきものではないかな。これは早いとか遅いとかの問題はなくて、準備ができた人からでいい。

棚上げテキスト ver 1.1.1

棚上げテキスト

棚上げテキスト

ストレスがたまるとゲームかコード書きに没頭して逃避する癖がある。
特に好評を得ていたわけでもない、どころか一ヶ月に二桁ダウンロード程度であるが、久しぶりにAppStoreを見たらありがたいコメントがついていたので3年ぶりのアップデートにトライした。

機能、UI的なこと

  • ディレクトリを追加できるようにした。
  • ディレクトリを追加して棚上げに名前空間的なものを適用するようにした。
  • 保存ボタンを消して画面遷移時に自動で保存するようにした。
  • メモ画面を横から出てくる感じの画面遷移を使うようにした。

これでまあ、メモとして最初にディレクトリを作って不要になったら消すという流れで完結できるようになったと思う。
このアプリを最初に作った時は、片手入力と思考の流れを拡張するというのがテーマだった。
自分はアイデアや文章を書きなぐっている時に思考が横道を逸れることがあって、そんなときに、別のメモに移るという操作をするとコンテキストが分断されてしまうという体験があって、それを解決するために「棚上げ」 というのを解決方法にしようと思って作った。
Scrapboxのリンクもあとで深掘りしたいワードをとりあえず青くしとくか的な感じで使われていると思うのでたぶん同じような問題意識から作られているんじゃないかなあと思う。
というかやりたかったことはだいたいあっちにある。 *1 けどまあ、片手入力の拡張としてはそんなに悪くもないだろう。

f:id:ssuwam:20190312192627g:plain

コードのこと

コードは3年前から何も触ってなかったのでSwift2でしかも当時流行っていたBondという謎のRxみたいなライブラリに依存していたのでSwift4, RxSwiftに更新した。
Swift2はそんなに大きなアプリでもないのに200くらいコンパイルエラーが出て、「これは最終的に大きな破綻をしていて全部捨てる羽目になるのでは?」という考えが過ぎったが、Xcodeの指示に従うと動くところまで来たのでよかった。


自分用のメモなのだが、自分で作ったアプリはバグ踏むのが嫌であんまり使えないという問題があって、そこまで使うことはなさそうな気がする。 というように書くとマジで誰得な上にApple税を支払っている感じになってしまうのであるが、何のために作っているかわからないのは今に始まったことでもないのでとりあえず書いたものをExportする機能の実装はしたい。

*1:Scrapboxは一覧画面が雑多なテキストでいっぱいになるのでコンテキストがごっちゃになってると見る気しなくなるという問題もある気がするけど。

Sanic+Ginoの開発環境ボイラープレート

Python Advent Calendar 2018 - Qiitaの12/13の記事です。

Sanicって良いですよね。速いし、シンプルだし、ドキュメントも充分です。
もうすぐ2019年になりますし、Pythonでサーバーを書くならasyncioを使ってノンブロッキングに実装したいものです。
個人的にWebフレームワークはDjangoみたいなフルスタックなものよりFlaskみたいな小さいものから始めて適宜追加していく方が全体を把握しやすいので好きです。
しかしながら、シンプルといってもウェブアプリケーションを作るなら

  • 新しいURLルーティングが増えた時に整理しやすいようにしておく
  • テストを書きやすいようにしておく
  • コンフィグ等を拡充しやすいようにしておく
  • DBとの接続やマイグレーションを出来るようにしておく

といったことは治安を守って快適に開発していくためには最低限必要なことかなと個人的には思います。
SanicのHello World Exampleから始めるのではなく、↑が揃ったSanic用のボイラープレートでもあればなあと考えていたので最近作った開発環境を晒したいと思います。

Hello World Example

from sanic import Sanic
from sanic.response import json

app = Sanic()

@app.route('/')
async def test(request):
    return json({'hello': 'world'})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

作ったもの

こちらになります。

github.com

以下はこれの解説になります。 なお、使っている主な技術を先に列挙すると

  • Python3.7
  • Docker
  • docker-compose
  • Pipenv
  • Sanic
  • tox
  • pytest
  • Postgre SQL
  • Alembic
  • Gino
  • SQLAlchemy

といった感じです。

とりあえず動かす

https://github.com/sasaujp/sanic-gino-boilerplateをコピーなりcloneなりして

$ docker-compose up -d
$ pipenv install --dev
$ pipenv run tox

を実行するとdocker-composeでPostgreSQLが立ち上がり、pipenvでパッケージがインストールされ、toxでテストが起動し、一通りのコードが実行されます。 サーバーを起動する場合は最後を

$ pipenv run python main.py

とするとポート8000でサーバーが起動します。

URLルーティング

/myapp/blueprints を見てください。

/myapp/blueprints/__init__.pyを見ると

from sanic import Blueprint
from .api import api
from .pages import pages


bp = Blueprint.group(api, pages)

apipages入れ子にしています。

/myapp/blueprints/api/__init__.pyを見ると

from sanic import Blueprint
from .hello import hello
from .todo import todo


api = Blueprint.group(hello, todo, url_prefix='/api')

hellotodo入れ子にしていて、url_prefixが設定されています。

/myapp/blueprints/api/hello.pyを見ると

from sanic import Blueprint, response

hello = Blueprint('hello_api', url_prefix='/hello')


@hello.route('/world')
async def hello_api(request):
    return response.json({'hello': 'world'})

Hello, WorldなAPIがあります。
SanicのBlueprintは入れ子にすることができ、url_prefixでpathの設計が出来ます。
トップのBlueprintはここで登録されているため、 このAPI/api/hello/worldでアクセスすることができます。

テスト

toxを使用し、pytestでテスト、flake8, mypyで文法チェックをしています。
よく使われている方法だと思われ、検索で出てくる情報も豊富なので細かく解説はしませんが
tox.iniで設定をしています。

コンフィグ

myapp/config.pyにあります。
今はまだDBの設定を書いているくらいであまり書くことはないのですが、tox.iniでセットしている環境変数でテスト用のコンフィグに分岐するようにしていて、普段とDB名が変わるようにしています。
/myapp/__init__.pyで登録しています。

DB関連

マイグレーション

マイグレーションとはDBのスキーマの変更をバージョン管理するためのもので、Alembicを使っています。
これもよく使われている技術で情報も豊富なので細かく解説はしません、しませんが
このボイラープレートを開発に使う場合は/alembic/versionsの中身を消した上で始めると良いと思います。

Gino

Ginoは今回使った技術の中でそこまでメジャーではない部類になるのかなと思います。
ノンブロッキングなWebサーバーを実装するにあたってSQLAlchemyとDBを非同期IOで橋渡しをしてくれるものが必要でした。
GinoはPostgre SQLにしか対応していませんが、とても使いやすい印象を受けたので採用しています。
Ginoの初期化は/myapp/blueprints/events.pyでサーバー起動時に行なっています。
具体的な操作は/myapp/blueprints/api/todo.pyのTodo APIで行なっています。
挙動のテストは/tests/http/test_todo.pyで行なっています。
SQLAlchemyを使っている人であればかなり手に馴染むのではないかなと思います。

終わりに

この記事、および今回作ったものは個人開発で出来てない部分の自戒のために書いたのは正直あります。
プライベートでは勢いで書き始めて辛い思いをすることがほとんどなので...。
asyncioや非同期IOは難しい印象を受ける方も多いと思いますし、実際慣れるまでは挙動の想像がしづらかったりするのですが ちゃんと書けば性能として帰ってくるし気分も良いので、これから挑戦してみようという方の一助になればと思います。

ワイWebエンジニア、なんJのためになんかしたい

自分は色々あって野球chからなんJに入植したなんJ民の第一世代だ。最近はなんJというコミュニティ(?)に対してエンジニアとして何か貢献したいという気持ちが強くなっていて、こういうスレを建てたりしていた。

ワイWebエンジニア、なんJのためになんかしたい | ログ速@2ちゃんねる(sc)

いち住民として、近年は全盛期と思えるくらいに居心地の良い場所になっているなと感じていて、なんJは雑談のためのUI/UXという意味でかなり理想的なものになっているように思う。
個人的には

  • スレの保持数が少ないため、盛り上がっているスレがすぐにわかり、そうでないスレは落ちる
  • そもそも雑談なんて長いスパンで行われるものではない
  • 野球という薄いコンテキストがあると雑談が成立しやすい
  • 野球というテーマによって定期的に話題の流入があるため淀みにくい

が良い点かなと思う。*1

ただ、「現在そうなっていること」にはそれなりの歴史的経緯があるため、他の場所での再現性があるわけではないのだけど。 自分もプログラミングに関する質問があったらできる範囲で積極的に答えるようにしている。teratailやstackoverflowで活動している人にとっては、回答が自分に帰属しないような場所でそれをするのは不思議に感じるかもしれない。


近年はインターネットで何者かになりたい・ならなければという話題は誰もが興味を引く「エモい」話題で、自分もそういう欲求があるから誰も使わないアプリ作ったりしている。

けれども、ここで言われているような強者にはなれないなと思うし、そういう人の方が多いだろうと思う。
強者である人は、社会的な強さだったり、文章のうまさだったり、何らかの生きづらさだったり、専門性の高さだったり、ゲームの上手さだったり、毎日ブログや動画を投稿できるマメさだったりがあるわけだけど
それ以前の問題として自分は人に見せられるような、コンテンツにはなれないなと感じる。
なのでまあ、今日も明日も集合的無意識の一部に溶け込んで生きるのだと思う。ずっと前からそうだったのでおっさん的な諦観と言われると辛いものがあるが...。


建てたスレはそれほど伸びずに25で落ちたけれども、何かできることは探していこうと思う。
スレの書き込み的には最近はWindowsのPC向けの専用ブラウザの不満が高まっているのを感じる。個人的にはkakikomi.txtをウェブで一元管理などができると良いなと思っているのでその辺りを組み込んだやつが作れるといいかなと思う。ただ、現在は専用ブラウザの開発が制限されているのでなかなか難しい....。

Tevereのデータを多少更新した

https://tevere.ccで集めているデータはhttp://dbpedia.org/sparql で集めているが
http://wikidata.dbpedia.org/sparqlのデータを集めて年月日に関するデータはこっちの情報を優先して正とする。
というような修正をした。
それによって、いくつかの日付情報が修正され、真珠湾攻撃などいくつか表示されていなかった戦いが表示されるようになった。

続きを読む

歴史上の戦いを年代ごとにGoogle Mapにプロットして指揮官やカテゴリで絞り込んで見られるやつ

を作った。

http://tevere.cc

f:id:ssuwam:20180529145522p:plain

データは例によってDBpediaから集めている。

何ができるの?

スライダーを動かすと表示する戦いの年代を選ぶことができる。
地図上に表示されたマーカーが戦いが行われた場所を示し、マーカーをタップすると詳細が表示される。

詳細にはその戦いで指揮した司令官、その戦いが含まれるカテゴリが表示されて
それをタップするとその司令官が参加した戦いやそのカテゴリの戦いを絞り込むことができる。 f:id:ssuwam:20180529145855p:plain

続きを読む