iOS SDK - プログラムでPDFファイルを生成する
質問
を使用して コアグラフィックス フレームワークを使用することは、プログラムで PDF ファイルを描画する場合、正直なところ面倒な作業です。
をプログラム的に作成したいのですが PDF を作成したいのですが、アプリ全体のビューから様々なオブジェクトを使用しています。
iOS SDK のための良い PDF チュートリアルがあるかどうか、おそらくドロップインライブラリについて知りたいです。
このチュートリアルを見たことがあります。 PDF 作成チュートリアル しかし、それはほとんど C で書かれていました。もっと Objective-C スタイルのものを探しています。これはまた、PDF ファイルに書き込むには、線や他のオブジェクトが配置される場所を計算しなければならない、ばかげた方法のように思えます。
void CreatePDFFile (CGRect pageRect, const char *filename)
{
// This code block sets up our PDF Context so that we can draw to it
CGContextRef pdfContext;
CFStringRef path;
CFURLRef url;
CFMutableDictionaryRef myDictionary = NULL;
// Create a CFString from the filename we provide to this method when we call it
path = CFStringCreateWithCString (NULL, filename,
kCFStringEncodingUTF8);
// Create a CFURL using the CFString we just defined
url = CFURLCreateWithFileSystemPath (NULL, path,
kCFURLPOSIXPathStyle, 0);
CFRelease (path);
// This dictionary contains extra options mostly for 'signing' the PDF
myDictionary = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
// Create our PDF Context with the CFURL, the CGRect we provide, and the above defined dictionary
pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary);
// Cleanup our mess
CFRelease(myDictionary);
CFRelease(url);
// Done creating our PDF Context, now it's time to draw to it
// Starts our first page
CGContextBeginPage (pdfContext, &pageRect);
// Draws a black rectangle around the page inset by 50 on all sides
CGContextStrokeRect(pdfContext, CGRectMake(50, 50, pageRect.size.width - 100, pageRect.size.height - 100));
// This code block will create an image that we then draw to the page
const char *picture = "Picture";
CGImageRef image;
CGDataProviderRef provider;
CFStringRef picturePath;
CFURLRef pictureURL;
picturePath = CFStringCreateWithCString (NULL, picture,
kCFStringEncodingUTF8);
pictureURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), picturePath, CFSTR("png"), NULL);
CFRelease(picturePath);
provider = CGDataProviderCreateWithURL (pictureURL);
CFRelease (pictureURL);
image = CGImageCreateWithPNGDataProvider (provider, NULL, true, kCGRenderingIntentDefault);
CGDataProviderRelease (provider);
CGContextDrawImage (pdfContext, CGRectMake(200, 200, 207, 385),image);
CGImageRelease (image);
// End image code
// Adding some text on top of the image we just added
CGContextSelectFont (pdfContext, "Helvetica", 16, kCGEncodingMacRoman);
CGContextSetTextDrawingMode (pdfContext, kCGTextFill);
CGContextSetRGBFillColor (pdfContext, 0, 0, 0, 1);
const char *text = "Hello World!";
CGContextShowTextAtPoint (pdfContext, 260, 390, text, strlen(text));
// End text
// We are done drawing to this page, let's end it
// We could add as many pages as we wanted using CGContextBeginPage/CGContextEndPage
CGContextEndPage (pdfContext);
// We are done with our context now, so we release it
CGContextRelease (pdfContext);
}
EDITです。 以下は libHaru を使った GitHub の例です。 をiPhoneのプロジェクトで使っています。
どのように解決するのですか?
いくつかあるのですが...
まず、iOS での CoreGraphics PDF 生成には、破損した PDF を生成するバグがあります。 この問題は、iOS 4.1 までとそれ以降に存在することがわかっています (iOS 4.2 ではテストしていません)。 この問題はフォントに関連しており、PDFにテキストが含まれている場合のみ表示されます。 症状は、PDF を生成するときに、デバッグ コンソールに次のようなエラーが表示されることです。
<Error>: can't get CIDs for glyphs for 'TimesNewRomanPSMT'
厄介な点は、作成されたPDFはいくつかのPDFリーダーではうまく表示されますが、他の場所では表示されないということです。 したがって、PDF を開くために使用するソフトウェアを制御できる場合は、この問題を無視できます (たとえば、PDF を iPhone や Mac のデスクトップで表示するだけの場合は、CoreGraphics を使用して問題ないでしょう)。 しかし、どこでも動作するPDFを作成する必要がある場合は、この問題をよく見ておく必要があります。 以下は追加情報です。
回避策として、私は iPhone で CoreGraphics PDF 生成の代わりとして libHaru をうまく使っています。 最初に libHaru を私のプロジェクトと一緒にビルドするのは少し厄介でしたが、いったん私のプロジェクトを適切にセットアップすると、私のニーズに対して問題なく機能しました。
次に、PDF のフォーマットやレイアウトによっては、Interface Builder を使用して、PDF 出力のテンプレートとなるビューを作成することを検討することができます。 次に、PDFのフォーマットやレイアウトによっては、Interface Builderを使って、PDF出力のテンプレートとなるビューを作成することもできます。 言い換えれば、IBを使用して座標、フォント、画像などを指定し、様々な要素をレンダリングするコードを書きます (例,
UILabel
,
UIImageView
など)を汎用的に使用することで、すべてをハードコードする必要がありません。 私はこの方法を使いましたが、私のニーズにはぴったりでした。 繰り返しますが、これは、PDFのフォーマット/レイアウトのニーズに応じて、あなたの状況にとって意味をなすかもしれませんし、そうでないかもしれません。
編集。 (1番目のコメントへの返答)
私の実装は商用製品の一部であるため、完全なコードを共有することはできませんが、大まかな概要を説明することはできます。
私はビューを持つ .xib ファイルを作成し、ビューのサイズを 850 x 1100 にしました (私の PDF は 8.5 x 11 インチをターゲットにしていたので、これは設計時の座標に/から変換するのが簡単です)。
コードで、私はビューをロードします。
- (UIView *)loadTemplate
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"ReportTemplate" owner:self options:nil];
for (id view in nib) {
if ([view isKindOfClass: [UIView class]]) {
return view;
}
}
return nil;
}
それから、いろいろな要素を埋めていく。 私はタグを使って適切な要素を探しましたが、これは他の方法でも可能です。 例を挙げます。
UILabel *label = (UILabel *)[templateView viewWithTag:TAG_FIRST_NAME];
if (label != nil) {
label.text = (firstName != nil) ? firstName : @"None";
それから、ビューをPDFファイルにレンダリングするための関数を呼び出します。 この関数は、ビュー階層を再帰的に走査し、各サブビューをレンダリングします。 私のプロジェクトでは、Label、ImageView、View (ネストされたビューの場合) のみをサポートする必要があります。
- (void)addObject:(UIView *)view
{
if (view != nil && !view.hidden) {
if ([view isKindOfClass:[UILabel class]]) {
[self addLabel:(UILabel *)view];
} else if ([view isKindOfClass:[UIImageView class]]) {
[self addImageView:(UIImageView *)view];
} else if ([view isKindOfClass:[UIView class]]) {
[self addContainer:view];
}
}
}
例として、私が実装したaddImageViewを紹介します(HPDF_の関数はlibHaruのものです)。
- (void)addImageView:(UIImageView *)imageView
{
NSData *pngData = UIImagePNGRepresentation(imageView.image);
if (pngData != nil) {
HPDF_Image image = HPDF_LoadPngImageFromMem(_pdf, [pngData bytes], [pngData length]);
if (image != NULL) {
CGRect destRect = [self rectToPDF:imageView.frame];
float x = destRect.origin.x;
float y = destRect.origin.y - destRect.size.height;
float width = destRect.size.width;
float height = destRect.size.height;
HPDF_Page page = HPDF_GetCurrentPage(_pdf);
HPDF_Page_DrawImage(page, image, x, y, width, height);
}
}
}
これでお分かりいただけたでしょうか?
関連
-
[解決済み] iOSでNSDictionaryからJSON文字列を生成する
-
[解決済み] iOSまたはmacOSで、インターネット接続が有効かどうかを確認するにはどうすればよいですか?
-
[解決済み] プロジェクト内の単一ファイルのARCを無効にするにはどうしたらいいですか?
-
[解決済み] iOSのステータスバーの文字色を変更する方法
-
[解決済み] iOSのバージョンを確認する方法を教えてください。
-
[解決済み] iOS 8 UITableViewのセパレータインセット0が機能しない件
-
[解決済み】iOSアプリの名前を変更する方法は?
-
[解決済み】iOSでプログラムにより自分の電話番号を取得する方法
-
[解決済み] リンカーフラグ -ObjC は何をするのですか?
-
[解決済み] Xcodeは私のiOSデバイスを見ませんが、iTunesは見ます。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】@try - Objective-Cのcatchブロック
-
[解決済み] UIScrollViewでスクロールの方向を見つける?
-
[解決済み] iOSシミュレータでファイルシステムを確認する方法はありますか?
-
[解決済み] ITunesのレビューURLとiOS 7(ユーザーにアプリを評価してもらう)AppStoreに空白のページが表示される。
-
[解決済み] UISearchDisplayController/UISearchBarでNSFetchedResultsController(CoreData)をフィルタリングする方法
-
[解決済み] UITableViewのセクション間のスペースを小さくする
-
[解決済み] drawRectを使うか使わないか(drawRect/Core Graphicsとsubview/imagesをいつ使うか、なぜ使うか)?
-
[解決済み] UIScrollViewをコンテンツに合わせて自動サイズ調整する方法
-
[解決済み] AppDelegate.mで画面上に現在表示されているUIViewControllerを取得する。
-
[解決済み] CALayersを使ったUIViewの丸め方 - 角の一部だけ - How?