Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Cocoa勉強会pdf関連

3,661 views

Published on

Published in: Technology
  • Be the first to comment

Cocoa勉強会pdf関連

  1. 1. iOS での PDF 処理あれこれ 越智 修司 @ponpoko1968
  2. 2. 自己紹介越智修司• KLab( くらぶ ) 株式会社• ソシャゲの会社でソシャゲじゃ無いもの作ってます• アプリ・サービスのプロトタイピング• 有名アーティスト・アイドルのファンクラブアプリ開発• 最近はデータ解析 • python,R など
  3. 3. 動機• 自炊始めた• PDF リーダーをいろいろ試してみた• 要望 • 読書内容を残したい・シェア • evernote • facebook • 視力が落ちてきた人 ( つまり自分 ) も 読みやすく
  4. 4. クリップリーダー• PDF リーダー
  5. 5. 苦労したこと• メモリ消費• 目次の抽出• 文字列の抽出
  6. 6. PDF 描画 (1)• CGContextDrawPDFPage() を使えば OK• ビットマップコンテクストに描画して永 続化すればキャッシュできる
  7. 7. PDF 描画 (2)CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url);// ページ番号からページを取得CGPDFPageRef page = CGPDFDocumentGetPage ( pdfDocument, pageNum );CGContextDrawPDFPage( context, page );CGPDFDocumentRelease( pdfDocument );
  8. 8. PDF 描画 (3)• 注意点 • メモリを消費します。 • しかもページを取得して描画するたびに消費量 が増えます。 • 対策 • ページレンダリングの都度 CGPDFDocument を開放して 開き直す。→パフォーマンス劣化 • didReceiveMemoryWarning を受け取ったらいったん閉じ て再開。
  9. 9. 「目次」機能
  10. 10. Core Graphics での PDF の構造• 階層化されたオブジェクトの集合体 • ページ • フォント • コンテントストリーム
  11. 11. Document management — Portabledocument format — Part 1: PDF 1.7 より
  12. 12. PDF 描画 (2)CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url);// ページ番号からページを取得CGPDFPageRef page = CGPDFDocumentGetPage ( pdfDocument, pageNum );CGContextDrawPDFPage( context, page );CGPDFDocumentRelease( pdfDocument );
  13. 13. Core Graphics での PDF の構造• Document Catalog という辞書から文書構 造を取り出す• オブジェクト単位の情報は CGPDFDictionary として扱われる• 配列は CGPDFArray として扱われる場合と 、 First,Next キーから参照できるリンク リストになっている場合がある( Lisp の car と cdr のようなもの )• しかも Composite 構造になっている
  14. 14. リンクリスト NextFirst
  15. 15. Pages
  16. 16. ページ 並びの取得CGPDFDictionaryRef catalog=CGPDFDocumentGetCatalog( document_ );CGPDFDictionaryRef pages =NULL;CGPDFDictionaryGetDictionary(catalog, "Pages", &pages);// 先頭の要素を取得CGPDFArrayRef pagesArray= NULL;CGPDFDictionaryGetDictionary(pages, "Kids", &pagesArray);int cnt = CGPDFArrayGetCount (pagesArray );for ( int i = 0; i < cnt; i++ ){ const char *typeString; CGPDFDictionaryRef pageDict; CGPDFArrayGetDictionary(pagesArray, i, &pageDict ); CGPDFDictionaryGetName(pageDict, "Type", &typeString ); if(strncmp("Page",typeString,strlen("Page"))==0 ){ // pageDict オブジェクトへのポインタと、ページ番号を NSDictionary に保存 [pageNumDict setValue:[NSNumber numberWithInt:pageNum] forKey:[NSString stringWithFormat:@"%p",pageDict] ]; }
  17. 17. 目次構造の取得Document management — Portable documentformat — Part 1: PDF 1.7 より
  18. 18. PDF 文書構造(1)CGPDFDictionaryRef catalog=CGPDFDocumentGetCatalog( document_ );CGPDFDictionaryRef outlines=NULL;CGPDFDictionaryGetDictionary(catalog, "Outlines", &outlines );// 先頭の要素を取得CGPDFDictionaryRef first = NULL;CGPDFDictionaryGetDictionary(outlines, "First", &first );// 見出しを取得CGPDFStringRef title;CGPDFDictionaryGetString ( first, "Title", &title );// 次の章 (cdr 部 ) を取得CGPDFDictionaryRef next = NULL;CGPDFDictionaryGetDictionary(outlines, "Next", &next);// 小見出し( car 部)を取得CGPDFDictionaryRef children;CGPDFDictionaryGetString ( first, "First", &children);
  19. 19. PDF 文書構造(2)// ページオブジェクトを取得CGPDFDictionaryRef page;CGPDFDictionaryDictionary ( first, "D", &title );// 「 D 」キーがなく、ページオブジェクトを直接参照できない場合CGPDFStringRef dest;CGPDFDictionaryGetString(dict, "Dest", &dest );
  20. 20. Document management — Portabledocument format — Part 1: PDF 1.7 より
  21. 21. ページ番号と文書構造のリンクval key 0 1 2 3 ・ ・ ・ n Pages Contents
  22. 22. 文字列抽出機能• コンテントストリームのなかから、文字 列描画命令部分を取り出す
  23. 23. コンテントストリームページ上で表現される一連の描画命令とデータ
  24. 24. PDF のオペレータparam1 param2 param3 param4 op• 後置記法• パラメータは LIFO スタックに積まれる param4 param3 param2 param1
  25. 25. PDF の文字列描画BT % Begin Text/F1 24 Tf % フォント指定 % /F1 がフォントを表現するシンボ ル1 0 0 1 72 648 Tm % 描画位置の指定(Hello World) Tj % 文字列描画 -- (と )が引用符1 0 0 1 72 612 Tm % non-ASCII 文字列<4D53835383568362834E3234837C834383938367> Tj1 0 0 1 72 576 Tm0.5 g % グレイスケール<82BB82EA82F08A44904682C982B582BD82E082CC> TjET % End Text 「 PDF by Hand 」 http://www.kobu.com/doc s/pdf/pdfxhand.htm より
  26. 26. 文字列描画オペレータ• Tj オペレータ
  27. 27. 文字列抽出// コールバック関数を設定するCGPDFOperatorTableRef table_;CGPDFOperatorTableSetCallback(table_, "BT",stringBlockBeginsCallback);CGPDFOperatorTableSetCallback(table_, "ET", stringBlockEndedCallback);CGPDFOperatorTableSetCallback(table_, "TJ", stringArrayCallback);CGPDFOperatorTableSetCallback(table_, "Tj", stringCallback);CGPDFOperatorTableSetCallback(table_, "Tf", fontCallback);// ページに適用CGPDFContentStreamRef contentStream = CGPDFContentStreamCreateWithPage(page);CGPDFScannerRef scanner = CGPDFScannerCreate(contentStream, table_, self); // userinfo として self を指定bool ret = CGPDFScannerScan(scanner);
  28. 28. 文字列抽出コールバックstatic void stringCallback(CGPDFScannerRef inScanner, void *userInfo){ PDFStringExtractor *zelf = (PDFStringExtractor *)userInfo; CGPDFStringRef string=NULL; if(CGPDFScannerPopString(inScanner, &string)) { // ↑LIFO なのでポップする // 座標関連の命令を取り出すときは注意 NSString* s = [zelf stringWithPDFString:string];
  29. 29. 文字列抽出コールバックstatic void stringCallback(CGPDFScannerRef inScanner, void *userInfo){ PDFStringExtractor *zelf = (PDFStringExtractor *)userInfo; CGPDFStringRef string=NULL; if(CGPDFScannerPopString(inScanner, &string)) { // ↑ 全然文字列じゃない!!! NSString* s = [zelf stringWithPDFString:string];
  30. 30. レンダラの気持ちになって考える
  31. 31. CID• PDF における " 文字列 " は、実際には CID の列で あることがある• CID= グリフ ( 字形 ) を一意に識別するための ID• CID と文字コードのマッピングは文字列描画に用 いるフォントによって異なる
  32. 32. フォント指定が重要BT % Begin Text/F1 24 Tf % フォント指定 % /F1 がフォントを表現するシンボ ル1 0 0 1 72 648 Tm % 描画位置の指定(Hello World) Tj % 文字列描画 -- (と )が引用符1 0 0 1 72 612 Tm % non-ASCII 文字列<4D53835383568362834E3234837C834383938367> Tj1 0 0 1 72 576 Tm0.5 g % グレイスケール<82BB82EA82F08A44904682C982B582BD82E082CC> TjET % End Text 「 PDF by Hand 」 http://www.kobu.com/doc s/pdf/pdfxhand.htm より
  33. 33. CGPDFDictionaryRef pageDict = CGPDFPageGetDictionary(page);CGPDFDictionaryRef resourceDict = NULL;CGPDFDictionaryRef fontDict = NULL;// フォント辞書をスキャンif(CGPDFDictionaryGetDictionary(pageDict, "Resources", &resourceDict ) ) { if(CGPDFDictionaryGetDictionary(resourceDict, "Font", &fontDict ) ) { CGPDFDictionaryApplyFunction(fontDict,enumerateFontsInDictionary,se lf); } }static void enumerateFontsInDictionary(const char *key, CGPDFObjectRef value, void *info) { // フォント情報をキャッシュする}
  34. 34. フォントのエンコーディング情報• Encoding • "Identity-H","Identity-V" • DescendantFont • /Registry (Adobe) • /Ordering (Japan-1) • /Supplement (6) • CMAP 名
  35. 35. CID ファイル :EUC-H の例100 begincidrange ← 100 個の区間があることを示す<20> <7e> 231 ← cid231 〜 313 は printable ASCII の区間<8ea0> <8edf> 326<a1a1> <a1fe> 633<a2a1> <a2ae> 727<a2ba> <a2c1> 741 . . .endcidrange
  36. 36. 課題• 対応できてないパターンがある• テキスト領域認識• 全文検索
  37. 37. 参考文献• Life is Beautiful ( 中島聡氏 ) • CloudReaders の開発 • PDF レンダリングのメモリ消費の問題 を指摘 • 超巨大ページにも対応• 木下誠氏のマイコミジャーナルの記事 • Core Text を用いた CID→Unicode の簡便 な解決案が提示されています • http://news.mynavi.jp/column/iphone/03 9/index.html
  38. 38. 参考文献 (2) • 通称フグ本 • CID などアドビ社の多国 語対応の情報 • 鈍器としても使えます
  39. 39. 参考文献 (3) • もっと早く出ていれ ば。。。
  40. 40. PDF Voyeurhttps://github.com/below/PDF-Voyeur.git

×