1月 | 2013 | HMDT Blog

カテゴリー : 2013年 1月

PDFの縦書き部分からテキスト抽出


最近続けているPDFの読み込み処理。縦書きPDFのテキスト抽出ができるようになってきた。

スクリーンショットは、縦書き表示があるPDFを読み込んで、PDF Kitと独自処理実装でテキスト抽出したもの。PDF Kitでは文字はとれるものの文章の体をなしていなけど、独自実装ではちゃんと文章になっている。

まだ問題はあるけど、まあ目処がついてきたかな。実装は、OS XとiOSに対応。

Map KitにPOI検索のためのMKLocalSearchが追加


Appleが、Map Kitを拡張してPOI (Point of Interest)を検索できるようにした、と発表。POIってのは、駅とか、飲食店とか、学校とかいった、地図上にある地形情報じゃないタイプのデータのこと。

APIが拡張されて、MKLocalSearch、MKLocalSearchRequest、MKLocalSearchResponseといったクラスが追加された。これを使うと、位置の領域や文字列を指定して、それに対応するMKMapItemを取得できるようだ。いままでも、CLGeocoderを使って似たような事ができていたけど、もっときちんとサポートされたらしい。iOS 6.1から使用可能。

この機能は、日本とロシアでは非サポートらしい。そりゃそうだよなー。マップのデータは、地形データはともかく、POIデータの無茶苦茶っぷりは酷すぎるからな。ものすごくAppleに好意的に考えれば、現在日本のPOIデータは絶賛改修中なのでもう少し待ってね、というメッセージ。普通に考えれば、日本のPOIデータもうどうにもならなかいから非サポート、放置する、というメッセージ。

iOS 6の地図の酷さについては、先日ちょっと検証をしてみた。日系ソフトウェアっていう雑誌があって、いまそこで連載をしているんだけど、それの次号(4月号)の記事にまとめるために。酷い酷いと言われていたけど、改めて調べてみたら、まぁーやっぱり酷かったね。興味のある方は、そちらを読んでみてください。

viewWillLayoutSubviewsが意図せず再帰呼び出し


UIViewControllerにviewWillLayoutSubviewsってメソッドがある。ビューコントローラが管理しているビューが再レイアウトされるときに呼び出されるもので、iOS 5から追加された。

このメソッドって、UIViewControllerが直接管理しているviewのframeが変更されたときだけ呼び出されると思っていたら、そのsubviewで再レイアウトが必要なときにも呼び出されちゃう事があるのね。しかも、すぐその場で。

デバッグ中にぶち当たった問題は、viewWillLayoutSubviewsの中でUIButtonの背景画像を変更したら、それがボタンの再レイアウトを誘発したらしく、その場で再びviewWillLayoutSubviewsが呼び出された。再帰的に。マジですかー。そんなもん、想像してなかったよ。

まぁ、なんべん呼び出されても大丈夫なようにはしてるんだけど、気持ち悪いよなー。

DropTalk HDがランキング1位獲得


昨日公開されたDropTalk HDですが、早速ランキング1位を獲得しました。イエィ!教育カテゴリの、トップセールスランキングで。iPad全体の有料ランキングでも、36位くらいまでいってた。

いやー、これは嬉しいです。このアプリは、エンタテイメントでもないし、万人向けでもない、特定の人たちに向けて開発されたものです。それがちゃんとランキングに顔を出してくるという事は、必要としている人たちがいて、その人たちに届いたんだ、と思っています。

プログラマやってて良かった、と思う瞬間ですな。

DropTalk HDが公開


dropletプロジェクトと共同で開発しました、VOCAアプリDropTalkのiPad版である、DropTalk HDがApp Storeで公開されました。

公開記念で、通常価格3,000円のところを、2,500円でセール中です。

長らくお待たせしてしまいましたが、機能的にはとてもいいものに仕上がったと自負しております。ユーザの方からのフィードバックがありますと、嬉しいです。

PDFとの格闘はToUnicodeへ


先日、PDFからテキスト抽出するためにCIDからUnicodeへのマップを作っている、と書いたら、「Fontディレクトリに含まれているToUnicodeを使うべし」というコメントをいただいた。

まったくもってその通りで、PDFの仕様書には、テキストを取得するにはToUnicodeを使えばいいよ、と書いてある。だけど、これは必須項目ではないので、巷にあふれているPDFファイルには、ToUnicodeが含まれているものもあれば、含まれていないものもある。というか、含まれているの見た事ねーよ!

と嘆いたら、「Appleの開発者向け日本語ドキュメントには含まれているよ」とのコメントが。早速確かめてみると、あったよ!これかー。なので、それをサンプルとしてToUnicode取得とストリームスキャンのためのコーディングをしている。

ちなみにこのPDFは、Creatorは不明。ToUnicodeが含まれていないPDFは、CreatorがAdobe Acrobatだったりする。Acrobat、貴様、ちゃんと入れとけよ。

CGPDFだと、Fontディレクトリから、ToUnicodeストリームを取得するところまでは、APIを使ってできる。でも、このストリーム(CGPDFStream型)からは、生データを取得できるのみでそれ以上のサポートはなし。あとは手作業で取っていくしかない。シクシク。ちなみに、PDFページのストリームを表すCGPDFContentStream型だと、もうちょっとサポートがあって、operatorのパースまでしてくれる。

でも、標準のAPIに機能が用意されてなくとも、その場ですぐにC言語にスイッチして低レベルのアクセスができるってのは、ほんっとに嬉しいし安心感がある。Objective-Cの最高の強みは、C言語をサブセットとして持っている事だね。スクリプト言語やマネージドコードとかいった輩は、どうにもならない檻の中だ。

PDFとの格闘で、CIDからUnicodeへのマップを作る


引き続き、PDFと格闘中。

PDFの内部データ触るには、CGPDF系の関数を使えばいい。その辺りは、iOSが提供してくれるので、ありがたく使わせてもらう。

そこまではいいんだけど、PDFから取得できるテキストデータは、CIDの形になっている。表示するだけならいいんだけど、コピーや検索するには、これをUnicodeに変換しないといけない。CIDからUnicodeへの変換が、ない。だいたいみんな、ここでひっかかる。

たぶん、Appleは持っているはず。PDFでコピーできるから。OS Xでは、PDF Kitを使えばテキスト取得できる。でも、iOSではない。

ないものは作ったれー!ということで、CIDからUnicodeへのマップを作っております。非常に原始的に、Adobe-Japanの仕様書を見て、対応するUnicodeの値を調べて、テキストエディタで記入する。

こんな方法しかないのかー!?やってみると、縦書き文字なんかもあるから、機械的にできないところもある。手でやるしかないのかー。

しかし、これさえ出来上がれば、PDFのコントロールは完全に我が手に。なるはず。

DropTalk HD申請しました


HMDTでは、障害を持った子供達に向けたアプリとして、DropTalkっていうアプリを開発しています。dropletプロジェクトさんといっしょに作っています。

AAC (Augmentative and Alternative Communication)とかVOCA (Voice Output Communication Aid)とか呼ばれるタイプのアプリで、コミュニケーションを補助してくれるものです。私は、そちらの専門的なことはよく分からないのですが、DropTalkは絵がかわいいのが気に入っています。Googleの画像検索でAACを検索すると、うーん、あんまりかわいくない。

で、そんなDropTalkですが、とうぜんiPad版が欲しいという要求がありました。それはもう、iPadが登場した直後からずっとありまして。確かに欲しいですよね。でも、どうせ出すなら機能的にしっかりしたものをと考えていたら、思ったよりも開発が難しくて、えらいこと時間がかかっちゃいました。

それをどうにか完成させて、先日App Storeに申請する事ができました。最初に手を付けたときから、2年以上が経過しています。長かったー。でも、iOSアプリらしく、シンプルかつ高機能なものができたと思っています。

いま、dropletさんのブログの方で、DropTalk HDの機能紹介をやっているので、興味がある方はのぞいてやってください。iPhone版と比べるとたくさんの機能があるので、紹介も大変みたい。

特に問題がなければ、あと10日ほどで公開されるはずです。本当にお待たせしました。

UIImageからハッシュ値を求めるときのパフォーマンス


画像を開いた2つのUIImageがあるとき、それが同じ画像かどうか判断したいときがある。いちばん負荷が少ないのは、画像を開くときのパスなりURLなりから判断する事だけど、そうもいかなくて、UIImageインスタンスを直接比較するしかない、ってときがある。

こんなときはハッシュを使うのが一般的だ。ハッシュを使えば、大きなバイナリデータも、その特徴を表す16バイトのデータを取得できる。これを比較してやればいい。iOSの場合は、CommonCryptoフレームワークにMD5ハッシュを取得するための関数があるので、これを使う。

となると次の問題は、どうやってバイナリデータを取得するか、ということだ。つまり、UIImageから、その画像を表すデータを取得したい。ざっと思いついたのは、次の3つの方法だ。

1. UIImagePNGRepresentationを使ってPNGデータを取得する

unsigned char   hash[16];
NSData*         data;
data = UIImagePNGRepresentation(image);
CC_MD5([data bytes], [data length], hash);

2. UIImageJPEGRepresentationを使ってJPEGデータを取得する

unsigned char   hash[16];
NSData*         data;
data = UIImageJPEGRepresentation(image, 1.0f);
CC_MD5([data bytes], [data length], hash);

3. CGImageからCGDataProviderを取得してビットマップデータを取得する

unsigned char       hash[16];
CGDataProviderRef   dataProvider;
NSData*             data;
dataProvider = CGImageGetDataProvider(image.CGImage);
data = (NSData*)CFBridgingRelease(CGDataProviderCopyData(dataProvider));
CC_MD5([data bytes], [data length], hash);

どの手法であっても、比較すること自体は問題ない。あとは、パフォーマンスの差だけだ。

ということで実測してみた。iPad 3rdで、1255 x 1322サイズの画像のハッシュ値を求めた。結果は次の通り。

1. PNG 1.647941sec

2. JPEG 0.442495sec

3. Data Provider 0.323576sec

ということで、Data Providerを使う手法がいちばんパフォーマンスが良かった。これを使うのがいいかな。

ちなみに、実行時間のほとんどはバイナリデータを取得する処理にかかっていた。ハッシュを求める計算が占める割合は、とても低かった。PNGへの変換は、エライこと時間がかかるわけね。

Drift Diaryさんで「音楽のある情景」紹介


ご存知Drift Diaryさんで、「音楽のある情景」を紹介してもらいました。ありがとうございます!

日本以外で使ってもらえると、このアプリ、グッと楽しくなります。西海岸で増える事を期待しております。指摘してもらったtypoも、弊社内バグトラッキングシステムに登録しました。というか、登録と同時に修正しました。

drikinさんとは、一緒に仕事した事はないものの、前職の縁でつながっているなんか不思議な関係。去年のWWDCでサンフランシスコに行ったとき、Westin近くの本屋を出たところでバッタリ出会い、その夜中に急遽ホテルのバーでお話しさせてもらったのが、懐かしいです。