More Related Content
Similar to Cocoa勉強会pdf関連 (20)
Cocoa勉強会pdf関連
- 2. 自己紹介
越智修司
• KLab( くらぶ ) 株式会社
• ソシャゲの会社でソシャゲじゃ無いもの作ってます
• アプリ・サービスのプロトタイピング
• 有名アーティスト・アイドルのファンクラブアプリ開発
• 最近はデータ解析
• python,R など
- 3. 動機
• 自炊始めた
• PDF リーダーをいろいろ試してみた
• 要望
• 読書内容を残したい・シェア
• evernote
• facebook
• 視力が落ちてきた人 ( つまり自分 ) も
読みやすく
- 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 を受け取ったらいったん閉じ
て再開。
- 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 構造になっている
- 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] ];
}
- 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);
- 22. 文字列抽出機能
• コンテントストリームのなかから、文字
列描画命令部分を取り出す
- 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
- 37. 課題
• 対応できてないパターンがある
• テキスト領域認識
• 全文検索
- 38. 参考文献
• Life is Beautiful ( 中島聡氏 )
• CloudReaders の開発
• PDF レンダリングのメモリ消費の問題
を指摘
• 超巨大ページにも対応
• 木下誠氏のマイコミジャーナルの記事
• Core Text を用いた CID→Unicode の簡便
な解決案が提示されています
• http://news.mynavi.jp/column/iphone/03
9/index.html
- 39. 参考文献 (2)
• 通称フグ本
• CID などアドビ社の多国
語対応の情報
• 鈍器としても使えます