無知を晒す

ふだんの出来事はこっちに書いてます: http://tana.hatenablog.com

どれが最新のファイルかわからなくなったことはないですか? XMPでどれが最新か見分けませんか?

こんにちは.私は id:side_tana.これは ミクシィグループ Advent Calendar 2018 - Qiita 9 日目の記事です.*1

qiita.com

日々を過ごしていると,目の前に複数のファイルがあり,そのどれが最新かわからなくて困る, といった場面に出くわします.皆さんも経験があるのではないでしょうか?

f:id:side_tana:20181209204244p:plain
画像はイメージです

特に雑にファイルをコピーしたり,何らかのサービスやツールを経由してデータをやりとりしているとファイルシステムのタイムスタンプも役に立たず途方にくれることもしばしばだと思います.*2

で,最近 Adobe XMP というファイルにメタデータを付与するための仕様について知る機会があったので,今回は Adobe XMP のデータを元に最新のファイルを見つけてみたいと思います.

なお Adobe XMP と書いているように Adobe が中心となって策定している仕様を利用しますので,全てのファイルで有効な方法ではありません.

PSD ファイルのメタデータを確認してみる

PSD に含まれる XMP メタデータについては,Photoshop で簡単に確認ができます.対象のファイルを Photoshop で開き,ファイルメニューからファイル情報を選択し,開いた画面の左側にあるリストから「Rawデータ」を選択すると,以下のような画面が表示されます.

f:id:side_tana:20181209204731p:plain

これが XMP で表現されたメタデータになります.こうして XMP のデータを眺めているとこんな箇所が出て来ます.

   <xmpMM:History>
    <rdf:Seq>
     <rdf:li
      stEvt:action="created"
      stEvt:instanceID="a8ae5a69-eb77-4089-95e2-f42d2b3de612"
      stEvt:when="2018-08-07T23:37:16.842+09:00"
      stEvt:softwareAgent="XD"/>
     <rdf:li
      stEvt:action="saved"
      stEvt:instanceID="f6d3e01d-15ed-47a9-92a1-2ea2301b2a71"
      stEvt:when="2018-09-23T23:01:14.891+09:00"
      stEvt:softwareAgent="XD"/>
    </rdf:Seq>
   </xmpMM:History>

いかにもそれらしいですね.この xmpMM:History 要素ですが,仕様上は XMP Media Management namespace のプロパティとして以下のように定義されています.

High-level actions that resulted in this resource. It is intended to give human readers a description of the steps taken to make the changes from the previous version to this one. The list should be at an abstract level; it is not intended to be an exhaustive keystroke or other detailed history. The description should be sufficient for metadata management, as well as for workflow enhancement.

ファイルの更新履歴のようなので,これで最新のファイルを発見できそうです.

PSD ファイルから XMP メタデータを取り出してみる

XMPメタデータを読み取るために,我々*3はまず PSD のヘッダフォーマットについて理解する必要があります.

PSD ファイルは8BPS から始まる26バイトのヘッダブロックを持ちます.次に可変長のカラーモードデータを持ち,そのあとにイメージリソースが続きます.イメージリソースには複数のブロックが含まれ,各ブロックは8BIMから始まり,2バイトのイメージリソースID,可変長の name フィールド,4バイトのイメージリソースデータのバイト長,実際のイメージリソースデータ,と続きます.

また,XMPメタデータはイメージリソースブロックに含まれ,イメージリソースID は 1060,nameフィールドは 2バイトの null であることがドキュメントで示されています.これらの情報を元に実装すると,<?xpacket?> で囲まれた xml ドキュメントを取り出すことができます. *4

f:id:side_tana:20181209210045p:plain
man ascii は便利 #宣言的知識

こうして xmp メタデータを取り出すことができればあとはこっちのものです.実際に複数の PSD ファイルの履歴をまとめて表示するページを用意しました*5.どうぞお手元の PSD ファイルをドラッグ&ドロップで読み込ませて見てください.(全ての処理はブラウザ上で完結しているので,外部への送信などはしていません.)

XmpMmHistoryViewer


f:id:side_tana:20181209215250g:plain

こうして メタデータから最新の編集時刻を見つけ出し,最新版を見つけ出すことができました.*6

おわりに

今回は XMP メタデータについて紹介し、実際にその一部である XMP Media Management namespace に含まれる ResourceEvent を利用してみました。XMP には他にもキャンバスサイズやサムネイル、使用しているフォントリストなど、使いがいのあるデータが色々と埋まっています。一方で,XMP は必ずこのデータを含む,と言った制約はほぼないため,欲しいデータが含まれているかどうかは実際に手を動かして見ないとわからないのが難しいところですね.

ぜひ年末のファイルシステムの大掃除に役立てたり、正月休みの空いた時間に身の回りをファイルを手にとってメタデータを取り出してみたりして楽しんでください。

*1:昨日の記事は @manji602 さんで ユーザにやさしいサービスを作るための3つのポイント - 問い合わせはサービス改善への近道 - - Qiitaでした.

*2:と書いておいてなんですが筆者はここしばらくソースコード以外のデータを触る業務から離れているためこう言った経験はめっきり減りました.と思ったけど Google Spreadsheet が野放図に複製されてどれが最新かわからなくなる地獄みたいなのあったな,あれまじでどうにかなりませんか,本当に困っています.

*3:我々

*4:実際のところ,あるファイルから XMP メタデータを取り出す方法というのは大きな問題です.XMP メタデータはファイル形式が変わっても引き継がれる場合があるため,事前にファイル形式を定められないケースがあるためです.具体的には Photoshop で作成した画像を jpeg として書き出した際にメタデータが引き継がれる,と言ったようなケースです.基本的なアプローチとしては今回のようにファイル形式に関する前提知識を利用して取り出すことが推奨されています.xpacket マーカを頼りに探索的に取り出すことアプローチもありますが,不確実性が高く壊れやすいロジックのため推奨されていません.

*5:動作についてはAdobe Photoshop CC 2019 で作成された PSD ファイルでのみ正しく動作することを確認してます.偶然手元にあった Adobe Photoshop CS5 Macintosh で作られたやつはダメだった.2019 では単一の要素にまとめられてた箇所か とっ散らかってた.

*6:本当は編集ツリーみたいなのまで作ろうと思ったのですが,どうやらイベントが新規に記録されるタイミングと更新されるタイミングがあるらしく,意図通りに保存記録を積み上げたデータが作れなかったので断念したという背景があります

ショートカットアプリで遊んだらすごかった

こういうツイートを見て,こうしちゃおれんと思って帰宅してすぐインストールした.

しばらくいじっていると色々できそうなことがわかったので,取り急ぎ雨雲ズームレーダーのスクリーンショットをとって HTTP で外部に送り出すショートカットを作った.

f:id:side_tana:20180921005243j:plain

ここからインストールできるっぽい? 雨雲ズームレーダー

全体像はこんな感じです.

f:id:side_tana:20180921011149p:plain

最後のアクションがLAN内にアップローダがいることを期待するのでそのままでは動かないと思います.アップローダはとりあえず動けばいいかってことで go で雑に書いた .適当に置いて go run uploader.go していただいて,アップローダの ip アドレスを正しく指定するとこんな感じの画像が入るはず.

f:id:side_tana:20180921010320p:plain

入力と出力の型がよくわかんなくて最初戸惑ったけど,慣れてくると結構簡単? って感じで,めちゃくちゃ簡単にプログラム作れて感動した.Siri から簡単に呼び出せるのもいいし,↑みたいな感じで簡単に公開用 URL を作れるのもいい.

バージョン管理できないとか,任意のDOMを選択,みたいな高度なことはできないっぽいけど,なんかパネルを並べていくだけで動くものができるのはすごい.未来のプログラミング体験だと思う.

GAE/SE Node で puppeteer を動かすよ

みなさん puppeteerつかってますか? 私は使ってません。なぜなら安定的に稼働させるための環境がないから...*1

しかしそれも今日までです。

先日 beta になった GAE/SE Node について

という話を聞きました。聞いたからにはやります。以下の通り。

const puppeteer = require('puppeteer')
async function takeScreenShot(url, filePath) {
  const browser = await puppeteer.launch({args: ['--no-sandbox']});
  const page = await browser.newPage();
  await page.setViewport({
    width: 1024,
    height: 768
  });
  await page.goto(url);
  await page.screenshot({
    path: filePath
  });

  await browser.close();
  return
}

こんな感じの関数を定義して動かした。ブログ用にちょっと整形したので、なんらかのミスで動かないかも。

以下感想と解説です。

起動時に --no-sandbox オプションがいる

コンテナ環境下で Chromium を動作させる場合に --no-sandbox オプションを要求されるの知らなくて最初うごかせなかった。ちゃんとエラーメッセージには書いてあるので、あとはどうやって puppeteer 経由で起動オプション渡すかって話だけど、上のコードみたいに .launch() に渡すオプションに args キーの値として渡せばいいらしい。

--no-sandbox オプションについてはちゃんと調べられてない。システムコール周りの話なのかなと思ってるけどなんなんだろうか……

インスタンスサイズ

デフォルトのインスタンスだとメモリ不足になったので、大きめのインスタンスを使っている。具体的には F4 インスタンス

f:id:side_tana:20180625225037p:plain

めちゃくちゃシンプルなページでも標準の F1 や F2 ぐらいだとこんな感じでメモリ不足に陥る。

上のスニペットで最後に毎回 browser.close() してるのはメモリ問題への対策なのだけれど、これでも連続して重めのページをレンダリングすると死んでしまう。あんまり死ぬようなら F4_1G にあげるしかか無いけど、その辺は様子見ながらやっていこうと思う。

その他

実際には 1 週間のライフサイクルを設定した GCS バケットスクリーンショットをアップロードし、 Slack に投稿している。 Slack に投稿するところ久々にやったので、画像の展開方法わかんなくてちょっと大変だった。( attachments.[].image_url が必要なやつ)

f:id:side_tana:20180625225847p:plain 要所を黒塗りにしたら訳がわからなくなりました

反省

開発環境あんまり整えずにガーッと書いたので、ローカルで何も考えずに動かすと GCS にアップロードできずに落ちたり、flowtype も無く typescript で書いているわけでも無いので後半めちゃくちゃ辛くなってしまった。

最近は会社も家も静的型付け言語 + IDEの静的解析とか、flowtype みたいなスタティックタイプチェッカの支援を受け続けてるし、テストもだいたい書いているのであまり苦がなかったのですが、久々にこう、大変な感じでしたね、、、。

*1:まあ別に転がしてる VPS とかラズパイとかあるんですけど、Slack の slash コマンドと組み合わせたいな〜とか考えるといい感じの環境ないな〜っという意味です

Fitbit StudioにiPhoneが繋がらない場合に試すべき民間療法

参考までに環境をまとめておくと

  • iPhone 6s
  • iOS 10.3.3
  • mobile app: Fitbit 2.43(730)
  • Fitbit Ionic: バージョン 27.30.5.8

で、具体的な手順としては

  • Fitbit App のアンインストール
  • 端末名の変更
  • Fitbit App のインストール

という感じ。アプリのインストールとアンインストールは勘でやったので不要かもしれません。

とにかくこれでアプリの開発者向けメニューから DeveloperBridge を有効にした際に「非アクティブ」と「接続しています…」みたいなのが交互に出てくる状況からは脱せました。

f:id:side_tana:20171117011543p:plain
*1

他に言語設定英語にしたり日本語にしたりしたけど関係あったのかな。

ところでfitbit ionic の開発環境は全てブラウザで提供されていて、PC、スマートフォン、ionic本体 が全てサーバを介してWebSocketで接続され、アプリのインストールやログの取得もWebSocketで行われていて、気合入ってるって感じ。

GarminのアプリケーションはUSBで本体繋いで、ビルドしたアプリケーションパッケージをファイルとしてコピーするだけだったので簡単に理解できたけど、試すたびに本体をUSBで繋ぐ必要があったりしてなかなか大変であった。

*1:前は "たな太郎のiPhone" という名前を設定していました

YAPC::Kansai でタイトルの長いやつをやります

えー、どうも、このところは猫も杓子もディープラーニングだってんで、ビッグデータやらHTML5やらなんてのはとんと聞かなくなっちまいまして。今じゃすっかり定着しちまいましたが、その前にはクラウドってのが流行り言葉でありました。その頃といえば PaaS とか IaaS とか、これも今日はきちんと使われちゃいますが、当時はもうめちゃくちゃだった[要出典]。さてそんな XaaS に BaaS というのがあったわけです。なんの略かといえば、 Backend as a Service でございますな。

そんな BaaS の中でもとくにモバイルアプリ向けのバックエンドを提供する一派がありまして mBaaS なんて名乗っていたわけですが。その中でもひときわ有名なのに Parse.com ってサービスがあった。こいつは 2016年の初めに終了宣言をしてそれから1年後、まあ今年の初めですな、宣言通りサービスを終了しました。

さて慌てるのは Parse.com を使っていた事業者だ。

というわけで、利用しているBaaSが終了するときにすべきこと または Parse.com の終了と私たちの取り組み というタイトルで一席ぶたせていただきます。

愉快な話ができるよう準備しておりますので、是非お越しください!