SlideShare a Scribd company logo
1 of 41
iOS での PDF 処理あれこれ

       越智 修司

     @ponpoko1968
自己紹介
越智修司

•       KLab( くらぶ ) 株式会社

•       ソシャゲの会社でソシャゲじゃ無いもの作ってます

•       アプリ・サービスのプロトタイピング

•       有名アーティスト・アイドルのファンクラブアプリ開発

•       最近はデータ解析

    •     python,R など
動機
•   自炊始めた
•   PDF リーダーをいろいろ試してみた
•   要望
    •       読書内容を残したい・シェア
        •    evernote
        •    facebook


    •       視力が落ちてきた人 ( つまり自分 ) も
            読みやすく
クリップリーダー
•   PDF リーダー
苦労したこと
•   メモリ消費
•   目次の抽出
•   文字列の抽出
PDF 描画 (1)
•   CGContextDrawPDFPage() を使えば OK
•   ビットマップコンテクストに描画して永
    続化すればキャッシュできる
PDF 描画 (2)
CGPDFDocumentRef pdfDocument
    = CGPDFDocumentCreateWithURL(url);

// ページ番号からページを取得
CGPDFPageRef page
    = CGPDFDocumentGetPage ( pdfDocument, pageNum );
CGContextDrawPDFPage( context, page );
CGPDFDocumentRelease( pdfDocument );
PDF 描画 (3)

•       注意点
    •       メモリを消費します。
    •       しかもページを取得して描画するたびに消費量
            が増えます。
    •       対策
        •    ページレンダリングの都度 CGPDFDocument を開放して
             開き直す。→パフォーマンス劣化
        •    didReceiveMemoryWarning を受け取ったらいったん閉じ
             て再開。
「目次」機能
Core Graphics での PDF の構造
•    階層化されたオブジェクトの集合体
    • ページ
    • フォント
    • コンテントストリーム
Document management — Portable
document format — Part 1: PDF 1.7 より
PDF 描画 (2)
CGPDFDocumentRef pdfDocument
    = CGPDFDocumentCreateWithURL(url);

// ページ番号からページを取得
CGPDFPageRef page
    = CGPDFDocumentGetPage ( pdfDocument, pageNum );
CGContextDrawPDFPage( context, page );
CGPDFDocumentRelease( pdfDocument );
Core Graphics での PDF の構造
•   Document Catalog という辞書から文書構
    造を取り出す

•   オブジェクト単位の情報は
    CGPDFDictionary として扱われる

• 配列は CGPDFArray として扱われる場合と
  、 'First','Next' キーから参照できるリンク
  リストになっている場合がある( Lisp の
  car と cdr のようなもの )
• しかも Composite 構造になっている
リンクリスト



        Next



First
Pages
ページ 並びの取得
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] ];

  }
目次構造の取得




Document management — Portable document
format — Part 1: PDF 1.7 より
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);
PDF 文書構造(2)
// ページオブジェクトを取得
CGPDFDictionaryRef page;
CGPDFDictionaryDictionary ( first, "D", &title );

// 「 D 」キーがなく、ページオブジェクトを直接参照できない場合
CGPDFStringRef dest;
CGPDFDictionaryGetString(dict, "Dest", &dest );
Document management — Portable
document format — Part 1: PDF 1.7 より
ページ番号と文書構造のリンク

val       key

 0

  1

 2

 3

      ・
      ・
      ・

  n             Pages   Contents
文字列抽出機能




•   コンテントストリームのなかから、文字
    列描画命令部分を取り出す
コンテントストリーム




ページ上で表現される一連の描画命令とデータ
PDF のオペレータ

param1 param2 param3 param4 op


•   後置記法
•   パラメータは LIFO スタックに積まれる

           param4

           param3

           param2

           param1
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> Tj
1 0 0 1 72 576 Tm
0.5 g                            % グレイスケール
<82BB82EA82F08A44904682C982B582BD82E082CC> Tj
ET                               % End Text




                                      「 PDF by Hand 」
                                      http://www.kobu.com/doc s/pdf/pdfxhand.htm
                                      より
文字列描画オペレータ




•   Tj オペレータ
文字列抽出
// コールバック関数を設定する
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);
文字列抽出コールバック
static void stringCallback(CGPDFScannerRef inScanner, void *userInfo)
{
  PDFStringExtractor *zelf = (PDFStringExtractor *)userInfo;
  CGPDFStringRef string=NULL;

 if(CGPDFScannerPopString(inScanner, &string)) {

    // ↑LIFO なのでポップする
    // 座標関連の命令を取り出すときは注意

   NSString* s   =   [zelf stringWithPDFString:string];
文字列抽出コールバック
static void stringCallback(CGPDFScannerRef inScanner, void *userInfo)
{
  PDFStringExtractor *zelf = (PDFStringExtractor *)userInfo;
  CGPDFStringRef string=NULL;

 if(CGPDFScannerPopString(inScanner, &string)) {


      // ↑ 全然文字列じゃない!!!
   NSString* s   =   [zelf stringWithPDFString:string];
レンダラの気持ちになって考える
CID


•   PDF における " 文字列 " は、実際には CID の列で
    あることがある

•   CID= グリフ ( 字形 ) を一意に識別するための ID

•   CID と文字コードのマッピングは文字列描画に用
    いるフォントによって異なる
フォント指定が重要
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> Tj
1 0 0 1 72 576 Tm
0.5 g                            % グレイスケール
<82BB82EA82F08A44904682C982B582BD82E082CC> Tj
ET                               % End Text




                                      「 PDF by Hand 」
                                      http://www.kobu.com/doc s/pdf/pdfxhand.htm
                                      より
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) {
   // フォント情報をキャッシュする

}
フォントのエンコーディング情報
•   Encoding
    •   "Identity-H","Identity-V"
        •   DescendantFont
            •   /Registry (Adobe)
            •   /Ordering (Japan-1)
            •   /Supplement (6)
    •   CMAP 名
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
課題




•   対応できてないパターンがある
•   テキスト領域認識
•   全文検索
参考文献
•   Life is Beautiful ( 中島聡氏 )
    •   CloudReaders の開発
    •   PDF レンダリングのメモリ消費の問題
        を指摘
    •   超巨大ページにも対応
•   木下誠氏のマイコミジャーナルの記事
    •   Core Text を用いた CID→Unicode の簡便
        な解決案が提示されています
    •   http://news.mynavi.jp/column/iphone/03
        9/index.html
参考文献 (2)
     •   通称フグ本

     •   CID などアドビ社の多国
         語対応の情報

     •   鈍器としても使えます
参考文献 (3)
     •   もっと早く出ていれ
         ば。。。
PDF Voyeur




https://github.com/below/PDF-Voyeur.git

More Related Content

Viewers also liked

スペースハルク
スペースハルクスペースハルク
スペースハルク
OCHI Shuji
 
第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析
第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析
第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析
OCHI Shuji
 
ソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LT
ソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LTソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LT
ソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LT
OCHI Shuji
 

Viewers also liked (9)

Core Animation 使って見た
Core Animation 使って見たCore Animation 使って見た
Core Animation 使って見た
 
スペースハルク
スペースハルクスペースハルク
スペースハルク
 
Manual en
Manual enManual en
Manual en
 
第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析
第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析
第3回関西ソーシャルゲーム勉強会 アクセス時間帯の分析
 
第4回関西ソーシャルゲーム勉強会 ソーシャルゲームのビジネスインテリジェンス
第4回関西ソーシャルゲーム勉強会 ソーシャルゲームのビジネスインテリジェンス第4回関西ソーシャルゲーム勉強会 ソーシャルゲームのビジネスインテリジェンス
第4回関西ソーシャルゲーム勉強会 ソーシャルゲームのビジネスインテリジェンス
 
デブサミ関西2013 「ソーシャルゲームのデータサイエンス」
デブサミ関西2013 「ソーシャルゲームのデータサイエンス」デブサミ関西2013 「ソーシャルゲームのデータサイエンス」
デブサミ関西2013 「ソーシャルゲームのデータサイエンス」
 
2012 05-19第44回cocoa勉強会発表資料
2012 05-19第44回cocoa勉強会発表資料2012 05-19第44回cocoa勉強会発表資料
2012 05-19第44回cocoa勉強会発表資料
 
第1回関西ソーシャルゲーム勉強会 kpi発表
第1回関西ソーシャルゲーム勉強会 kpi発表第1回関西ソーシャルゲーム勉強会 kpi発表
第1回関西ソーシャルゲーム勉強会 kpi発表
 
ソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LT
ソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LTソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LT
ソーシャルゲームのデータ分析基盤としてのAWS Jaws ug三都物語LT
 

Similar to Cocoa勉強会pdf関連

Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門
cocopon
 
2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk
mitamex4u
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
kikairoya
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
Takeshi Komiya
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
土岐 孝平
 

Similar to Cocoa勉強会pdf関連 (20)

卒研発表
卒研発表卒研発表
卒研発表
 
コミケの取りまとめをしたので
コミケの取りまとめをしたのでコミケの取りまとめをしたので
コミケの取りまとめをしたので
 
【関東GPGPU勉強会#4】GTX 1080でComputer Vision アルゴリズムを色々動かしてみる
【関東GPGPU勉強会#4】GTX 1080でComputer Visionアルゴリズムを色々動かしてみる【関東GPGPU勉強会#4】GTX 1080でComputer Visionアルゴリズムを色々動かしてみる
【関東GPGPU勉強会#4】GTX 1080でComputer Vision アルゴリズムを色々動かしてみる
 
Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門Core Graphicsでつくる自作UIコンポーネント入門
Core Graphicsでつくる自作UIコンポーネント入門
 
2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk2008.10.18 L4u Tech Talk
2008.10.18 L4u Tech Talk
 
組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由組み込みでこそC++を使う10の理由
組み込みでこそC++を使う10の理由
 
計算機理論入門09
計算機理論入門09計算機理論入門09
計算機理論入門09
 
20141017 introduce razor
20141017 introduce razor20141017 introduce razor
20141017 introduce razor
 
Programming camp 2008, Codereading
Programming camp 2008, CodereadingProgramming camp 2008, Codereading
Programming camp 2008, Codereading
 
TreeFrog Frameworkの紹介
TreeFrog Frameworkの紹介TreeFrog Frameworkの紹介
TreeFrog Frameworkの紹介
 
仮想記憶の構築法
仮想記憶の構築法仮想記憶の構築法
仮想記憶の構築法
 
Tide - SmalltalkでSPA
Tide - SmalltalkでSPATide - SmalltalkでSPA
Tide - SmalltalkでSPA
 
Cocoa勉強会201208
Cocoa勉強会201208Cocoa勉強会201208
Cocoa勉強会201208
 
C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1C# 7.2 with .NET Core 2.1
C# 7.2 with .NET Core 2.1
 
Inside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfesInside of excel 方眼紙撲滅委員会 #pyfes
Inside of excel 方眼紙撲滅委員会 #pyfes
 
条件式評価器の実装による管理ツールの抽象化
条件式評価器の実装による管理ツールの抽象化条件式評価器の実装による管理ツールの抽象化
条件式評価器の実装による管理ツールの抽象化
 
(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話(ゲームじゃない方の)switchで遊びたい話
(ゲームじゃない方の)switchで遊びたい話
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
HTML5
HTML5HTML5
HTML5
 
Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理Spring3.1概要 データアクセスとトランザクション処理
Spring3.1概要 データアクセスとトランザクション処理
 

Recently uploaded

Recently uploaded (7)

Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 

Cocoa勉強会pdf関連

  • 1. iOS での PDF 処理あれこれ 越智 修司 @ponpoko1968
  • 2. 自己紹介 越智修司 • KLab( くらぶ ) 株式会社 • ソシャゲの会社でソシャゲじゃ無いもの作ってます • アプリ・サービスのプロトタイピング • 有名アーティスト・アイドルのファンクラブアプリ開発 • 最近はデータ解析 • python,R など
  • 3. 動機 • 自炊始めた • PDF リーダーをいろいろ試してみた • 要望 • 読書内容を残したい・シェア • evernote • facebook • 視力が落ちてきた人 ( つまり自分 ) も 読みやすく
  • 4. クリップリーダー • PDF リーダー
  • 5. 苦労したこと • メモリ消費 • 目次の抽出 • 文字列の抽出
  • 6. PDF 描画 (1) • CGContextDrawPDFPage() を使えば OK • ビットマップコンテクストに描画して永 続化すればキャッシュできる
  • 7. PDF 描画 (2) CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url); // ページ番号からページを取得 CGPDFPageRef page = CGPDFDocumentGetPage ( pdfDocument, pageNum ); CGContextDrawPDFPage( context, page ); CGPDFDocumentRelease( pdfDocument );
  • 8. PDF 描画 (3) • 注意点 • メモリを消費します。 • しかもページを取得して描画するたびに消費量 が増えます。 • 対策 • ページレンダリングの都度 CGPDFDocument を開放して 開き直す。→パフォーマンス劣化 • didReceiveMemoryWarning を受け取ったらいったん閉じ て再開。
  • 10. Core Graphics での PDF の構造 • 階層化されたオブジェクトの集合体 • ページ • フォント • コンテントストリーム
  • 11. Document management — Portable document format — Part 1: PDF 1.7 より
  • 12. PDF 描画 (2) CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(url); // ページ番号からページを取得 CGPDFPageRef page = CGPDFDocumentGetPage ( pdfDocument, pageNum ); CGContextDrawPDFPage( context, page ); CGPDFDocumentRelease( pdfDocument );
  • 13. Core Graphics での PDF の構造 • Document Catalog という辞書から文書構 造を取り出す • オブジェクト単位の情報は CGPDFDictionary として扱われる • 配列は CGPDFArray として扱われる場合と 、 'First','Next' キーから参照できるリンク リストになっている場合がある( Lisp の car と cdr のようなもの ) • しかも Composite 構造になっている
  • 14. リンクリスト Next First
  • 15. Pages
  • 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. 目次構造の取得 Document management — Portable document format — Part 1: PDF 1.7 より
  • 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. PDF 文書構造(2) // ページオブジェクトを取得 CGPDFDictionaryRef page; CGPDFDictionaryDictionary ( first, "D", &title ); // 「 D 」キーがなく、ページオブジェクトを直接参照できない場合 CGPDFStringRef dest; CGPDFDictionaryGetString(dict, "Dest", &dest );
  • 20. Document management — Portable document format — Part 1: PDF 1.7 より
  • 21. ページ番号と文書構造のリンク val key 0 1 2 3 ・ ・ ・ n Pages Contents
  • 22. 文字列抽出機能 • コンテントストリームのなかから、文字 列描画命令部分を取り出す
  • 24. PDF のオペレータ param1 param2 param3 param4 op • 後置記法 • パラメータは LIFO スタックに積まれる param4 param3 param2 param1
  • 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> Tj 1 0 0 1 72 576 Tm 0.5 g % グレイスケール <82BB82EA82F08A44904682C982B582BD82E082CC> Tj ET % End Text 「 PDF by Hand 」 http://www.kobu.com/doc s/pdf/pdfxhand.htm より
  • 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. 文字列抽出コールバック 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. 文字列抽出コールバック static void stringCallback(CGPDFScannerRef inScanner, void *userInfo) { PDFStringExtractor *zelf = (PDFStringExtractor *)userInfo; CGPDFStringRef string=NULL; if(CGPDFScannerPopString(inScanner, &string)) { // ↑ 全然文字列じゃない!!! NSString* s = [zelf stringWithPDFString:string];
  • 31. CID • PDF における " 文字列 " は、実際には CID の列で あることがある • CID= グリフ ( 字形 ) を一意に識別するための ID • CID と文字コードのマッピングは文字列描画に用 いるフォントによって異なる
  • 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> Tj 1 0 0 1 72 576 Tm 0.5 g % グレイスケール <82BB82EA82F08A44904682C982B582BD82E082CC> Tj ET % End Text 「 PDF by Hand 」 http://www.kobu.com/doc s/pdf/pdfxhand.htm より
  • 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. フォントのエンコーディング情報 • Encoding • "Identity-H","Identity-V" • DescendantFont • /Registry (Adobe) • /Ordering (Japan-1) • /Supplement (6) • CMAP 名
  • 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.
  • 37. 課題 • 対応できてないパターンがある • テキスト領域認識 • 全文検索
  • 38. 参考文献 • Life is Beautiful ( 中島聡氏 ) • CloudReaders の開発 • PDF レンダリングのメモリ消費の問題 を指摘 • 超巨大ページにも対応 • 木下誠氏のマイコミジャーナルの記事 • Core Text を用いた CID→Unicode の簡便 な解決案が提示されています • http://news.mynavi.jp/column/iphone/03 9/index.html
  • 39. 参考文献 (2) • 通称フグ本 • CID などアドビ社の多国 語対応の情報 • 鈍器としても使えます
  • 40. 参考文献 (3) • もっと早く出ていれ ば。。。