2016-11-01 26 views
21

私はSwiftのアプリケーションでいくつかのHTMLからPDFを生成します。私はUIMarkupTextPrintFormatterを使用し、コードはthis gistに似ています。私はNSDataとしてPDFを入手し、それを電子メールに添付します。このアプリは、添付する前にPDFをユーザーに表示しません。プリントインターフェイスを表示せずにHTMLから画像をPDFに生成

私は今いくつかの画像を入れたいと思います。私の現在のPDF生成戦略でHTMLにNSURLを追加することはできません。画像が追加されたHTMLに対応するPDFのNSDataを取得するにはどうすればよいですか?ここで私が試したいくつかのものがあります:

  1. This answerはHTMLでbase64で画像を埋め込むとUIPrintInteractionControllerを使用することを提案しています。これにより、正しく埋め込まれた画像を含む印刷プレビューが表示されますが、そこからPDF出力に対応するNSDataに移動するにはどうすればよいですか?

  2. 私はUIWebViewを経由する類似の提案を見たことがありますが、それらは同じ問題につながります。私はユーザーにプレビューを表示したくありません。

+0

私にはいくつか質問があります。画像はローカルであるか、html文書のURL参照ですか?あなたはあなたの作成のPDF文書に画像を追加したいですか?あなたはあなたの現在のpdfの出力をあなたの望むものと比べて投稿/モックアップできますか? –

+0

@fragilecat画像は電話機のファイルです。私は

答えて

17

UIMarkupTextPrintFormatterは、HTML imgタグをサポートしていないようです。 Appleのマニュアルはあまり有益ではありません。初期設定パラメータは"印刷フォーマッタのHTMLマークアップテキスト"です。印刷フォーマッタによってサポートされているタグが正確に示されていません。

多くのテストの結果、私が描くことができる唯一の結論は、UIMarkupTextPrintFormatterになります。イメージの表示がサポートされています。

ここで、HTMLコンテンツからPDFを作成する利便性を望む人はいますか?

この作業を行うために私が見つけた唯一の方法は、HTMLコンテンツを読み込んでからWebビューのUIViewPrintFormatterを使用する非表示のWebビューを使用することです。これは動作しますが、実際にハックのように感じます。

それはあなたのPDF文書に画像を埋め込みますが、もし私がCoreTextQuartz 2Dを使用すると、私はそれが私が理解できると言っているように、あなたのHTMLコンテンツのサイズや複雑さはわかりません。実施例のように

...

セットアップ

私はちょうど私が使用したい画像のファイル名を渡すことができるようにベースURLを定義することが有用でした。ベースURLは、画像が配置されているアプリバンドル内のディレクトリにマップされます。独自の場所も定義できます。

Bundle.main.resourceURL + "www/" 

Copy Files Build Phase

それから私は、ドキュメント関連機能を処理するためのプロトコルを作成しました。デフォルトの実装は、以下のコードで見られるように、拡張によって提供されます。

protocol DocumentOperations { 

    // Takes your image tags and the base url and generates a html string 
    func generateHTMLString(imageTags: [String], baseURL: String) -> String 

    // Uses UIViewPrintFormatter to generate pdf and returns pdf location 
    func createPDF(html: String, formmatter: UIViewPrintFormatter, filename: String) -> String 

    // Wraps your image filename in a HTML img tag 
    func imageTags(filenames: [String]) -> [String] 
} 


extension DocumentOperations { 

    func imageTags(filenames: [String]) -> [String] { 

     let tags = filenames.map { "<img src=\"\($0)\">" } 

     return tags 
    } 


    func generateHTMLString(imageTags: [String], baseURL: String) -> String { 

     // Example: just using the first element in the array 
     var string = "<!DOCTYPE html><head><base href=\"\(baseURL)\"></head>\n<html>\n<body>\n" 
     string = string + "\t<h2>PDF Document With Image</h2>\n" 
     string = string + "\t\(imageTags[0])\n" 
     string = string + "</body>\n</html>\n" 

     return string 
    } 


    func createPDF(html: String, formmatter: UIViewPrintFormatter, filename: String) -> String { 
     // From: https://gist.github.com/nyg/b8cd742250826cb1471f 

     print("createPDF: \(html)") 

     // 2. Assign print formatter to UIPrintPageRenderer 
     let render = UIPrintPageRenderer() 
     render.addPrintFormatter(formmatter, startingAtPageAt: 0) 

     // 3. Assign paperRect and printableRect 
     let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi 
     let printable = page.insetBy(dx: 0, dy: 0) 

     render.setValue(NSValue(cgRect: page), forKey: "paperRect") 
     render.setValue(NSValue(cgRect: printable), forKey: "printableRect") 

     // 4. Create PDF context and draw 
     let pdfData = NSMutableData() 
     UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil) 

     for i in 1...render.numberOfPages { 

      UIGraphicsBeginPDFPage(); 
      let bounds = UIGraphicsGetPDFContextBounds() 
      render.drawPage(at: i - 1, in: bounds) 
     } 

     UIGraphicsEndPDFContext(); 

     // 5. Save PDF file 
     let path = "\(NSTemporaryDirectory())\(filename).pdf" 
     pdfData.write(toFile: path, atomically: true) 
     print("open \(path)") 

     return path 
    } 

} 

次に、このプロトコルをビューコントローラで採用しました。この作業を行うための鍵はここにあり、あなたのView ControllerはUIWebViewDelegateを採用し、 func webViewDidFinishLoad(_ webView: UIWebView)にはpdfが作成されているのがわかります。彼の答えfragilecat、私は3 viewcontrollersと一緒にサンプルプロジェクトを入れているから部品を使用して

class ViewController: UIViewController, DocumentOperations {  
    @IBOutlet private var webView: UIWebView! 

    override func viewWillAppear(_ animated: Bool) { 
     super.viewWillAppear(animated) 

     webView.delegate = self 
     webView.alpha = 0 

     if let html = prepareHTML() { 
      print("html document:\(html)") 
      webView.loadHTMLString(html, baseURL: nil) 

     } 
    } 

    fileprivate func prepareHTML() -> String? { 

     // Create Your Image tags here 
     let tags = imageTags(filenames: ["PJH_144.png"]) 
     var html: String? 

     // html 
     if let url = Bundle.main.resourceURL { 

      // Images are stored in the app bundle under the 'www' directory 
      html = generateHTMLString(imageTags: tags, baseURL: url.absoluteString + "www/") 
     } 

     return html 
    } 
} 


extension ViewController: UIWebViewDelegate { 

    func webViewDidFinishLoad(_ webView: UIWebView) { 
     if let content = prepareHTML() { 
      let path = createPDF(html: content, formmatter: webView.viewPrintFormatter(), filename: "MyPDFDocument") 
      print("PDF location: \(path)") 
     } 


    } 


} 
+0

ハッキングなくHTMLを使用する方法を願っていましたが、最高の戦略を見つけたと思います! –

+0

このチュートリアルのサンプルプロジェクトでは、imgタグhttp:// www.appcoda.com/pdf-generation-ios /を使用しています。私のプロジェクトでは同じコードを使用していますが、動作しません。 – Hakim

+0

あなたのコードはほとんど完璧に動作しますが、私にとってはイメージなしの最初のPDFと2番目のPDFを正しく生成します。何か案は? –

5

  • 最初のものは、一つの画像はPDF
  • に、その後、 輸出をWKWebViewを使用してローカルのHTMLをレンダリング
  • もう一つは第三の一つは、印刷ダイアログ
を示す別のWKWebView
  • 付きPDFをレンダリングこの問題に浪費

    https://github.com/bvankuik/TestMakeAndPrintPDF

  • +1

    私はCSSを適用するのに苦労していました。あなたの例はついにそれを解決するのを助けました。本当にありがとう! – pbuchheit

    4

    私の多くの時間支援画像を行いUIMarkupTextPrintFormatter私に語りました。これには2つの理由:あなたが言うように

    1. UIMarkupTextPrintFormatterUIPrintInteractionControllerで示されるPDFは正しく画像を示します。
    2. 次のtutorial(コメントにも記載されています)は、実際にはUIMarkupTextPrintFormatterを使用して画像を含むPDFを作成します。調査したところ、HTMLコードがUIWebViewにあらかじめロードされていたという理由がわかりました。 UIMarkupTextPrintFormatterは、画像をレンダリングするために一部のWebKitコンポーネントに依存しています。

    私は解決策を提供していませんが、これは明らかにiOSのバグです。私はiOS 11を持っていないので、多分それはこの次のバージョンで解決されています。

    バグについては、hereと、さまざまな印刷フォーマットを使用してPDFを作成できるサンプルアプリケーションについて説明しました。

    NB:Base64と「外部」(つまりhttp://example.com/my-image.png)の画像を処理することしかできませんでした。

    +0

    非常に興味深い分析!共有に感謝します。私がiOS 11で見つけたものを見て興味深いですが、私はそれも試していません。 @ pete-hornsbyのソリューションは私の短期的な問題を解決しましたが、より直接的なやり方が必要なように感じます。 –

    +0

    @HélèneMartinありがとう!さて、iOS 11をインストールしましたが、バグはまだここにあります!私はアップルにバグレポートを提出しました... http://www.openradar.me/radar?id=6067400759836672 – nyg

    +0

    これはまだ解決されていませんが、バグレポートを提出してくれてありがとう! –

    関連する問題