2016-11-01 50 views
21

Bazı HTML'den benim Swift uygulamamda bir PDF oluşturuyorum. UIMarkupTextPrintFormatter kullanıyorum ve this gist'a benzer bir kod kullanıyorum. PDF'yi NSData olarak aldım ve bir e-postaya ekledim. Uygulama, eklemeden önce PDF'yi kullanıcıya göstermez.Baskı arayüzünü görüntülemeden Swift'de HTML ile görüntülerle PDF oluşturun

Bazı görseller eklemek istiyorum. Mevcut PDF oluşturma stratejim ile HTML'de NSURL eklemek işe yaramıyor. Eklenen resimlerle HTML’ye karşılık gelen bir PDF’in NSData’unu nasıl alabilirim? İşte ben denedim bazı şeyler şunlardır:

  1. This answer HTML base64 resim dahil ve UIPrintInteractionController kullanarak önerir. Bu bana doğru şekilde yerleştirilmiş görüntülerle bir baskı önizlemesi sunuyor, ancak buradan PDF çıktısına karşılık gelen NSData'a nasıl giderim?

  2. UIWebView ile ilgili bazı benzer öneriler gördüm, ancak bunlar aynı soruna neden oluyor - kullanıcıya önizleme göstermek istemiyorum.

+0

Ben bir kaç sorum var. Görüntüler yerel mi, yoksa html belgesinde referanslar mı var? Görüntüleri pdf belgenize eklemek ister misiniz? Mevcut pdf çıktınızı istediğiniz zaman gönderebilir/gönderebilir misiniz? –

+0

@fragilecat Resimler telefonda dosyalardır. Bunları

cevap

17

UIMarkupTextPrintFormatter HTML img etiketini desteklemek için görünmüyor. Apple'ın belgeleri burada çok bilgilendirici değil, sadece başlatma parametresinin "Baskı formatı için HTML biçimlendirme metni" olduğunu belirtiyor. Baskı biçimlendirici tarafından hangi etiketlerin desteklendiğine dair bir gösterge yoktur.

Birçok testten sonra çizebileceğim tek sonuç, görüntülerin görüntülenmesini 'un NOT desteklemesidir.

Peki bu, HTML içeriklerinden PDF oluşturmanın kolaylığını isteyen kullanıcıları nerede bırakıyor?

Bu işi yapmak için bulduğum tek yol, html içeriğinizi yüklediğiniz gizli web görünümünü kullanmak ve ardından web görünümünün UIViewPrintFormatter kullanımını kullanmaktır. Bu çalışır ama gerçekten bir kesmek gibi geliyor.

PDF belgenize iş yükler ve görüntüler yerleştirir, ancak eğer ben olsaydım, pdf oluşturma sürecinin daha fazla kontrolüne sahip olacağından, CoreText ve Quartz 2D'u kullanmayı tercih ederim. overkill, html içeriğinizin boyutunu veya karmaşıklığını bilmiyorum. Çalışan bir örneğe Öyleyse

...

Kur

O ben sadece kullanmak istedi görüntülerin Dosya adlarında geçebileceği şekilde bir taban URL tanımlamak için faydalı oldu. Temel URL, görüntülerin bulunduğu uygulama paketindeki bir dizine eşlendi. Kendi konumunuzu da tanımlayabilirsiniz.

Copy Files Build Phase

Bundle.main.resourceURL + "www/" 

Sonra belge ile ilgili işlevselliği işlemek için bir protokol oluşturdu. Varsayılan uygulamalar, aşağıdaki kodda görebileceğiniz gibi bir uzantı tarafından sağlanır.

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 
    } 

} 

Sonra bir görünüm denetleyicisi tarafından benimsenen bu protokolü vardı. Bu işi yapmanın anahtarı görünümünüzü kontrolör UIWebViewDelegate kabul etmesi gerekmektedir ve func webViewDidFinishLoad(_ webView: UIWebView) size pdf oluşturulur görebilirsiniz burada. Onun cevabını fragilecat, üç viewcontrollers birlikte örnek bir proje koyduk parçaları kullanarak

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

Bir hack olmadan HTML kullanılan bir şekilde isteyen oldu ama bence en iyi stratejiyi buldunuz! –

+0

Bu dersin örnek projesi, http: // www.appcoda.com/pdf-generation-ios/'img etiketini kullanır, projemde aynı kodu kullanır ve işe yaramıyor. – Hakim

+0

Kodunuz neredeyse mükemmel çalışıyor ancak benim için ilk PDF'yi resimsiz ve ikincisi doğru şekilde üretiyor. Herhangi bir fikir? –

5

:

  • birincisi bir görüntü PDF
  • sonra, ihracatını WKWebView kullanarak yerel HTML işler
  • ikincisi üçüncüsü ise yazdırma iletişim
gösterir başka WKWebView
  • ile PDF vermektedir Bu konuda boşa

    https://github.com/bvankuik/TestMakeAndPrintPDF

  • +1

    Ben de benzer bir sorunla karşılaşıp css uygulamak için uğraşıyordum. Örneğiniz nihayet çözmeme yardımcı oldu. Çok teşekkürler! – pbuchheit

    4

    Benim kaç saat UIMarkupTextPrintFormatter destek görüntülerini yapar söylüyor. Bunun iki nedeni:

    Dediğiniz gibi
    1. , bir UIMarkupTextPrintFormatter ile UIPrintInteractionController gösterdiği PDF doğru resimler gösterir.
    2. tutorial (ayrıca yorum olarak bahsedilen) aslında UIMarkupTextPrintFormatter kullanarak görüntülerle bir PDF oluşturmak için yönetir aşağıdaki. Araştırdım ve bunun nedeninin, HTML kodunun önceden UIWebView numaralı telefona yüklenmiş olduğudur. UIMarkupTextPrintFormatter onun görüntüleri işlemek için bazı WebKit bileşeni dayanır gibi görünüyor.

    Herhangi bir çözüm sağlamadığımı bildiğim ama bana göre bu bir iOS hatasıdır. IOS 11'im yok, belki bu yeni sürümde çözülmüştür.

    farklı baskı biçemleyicileri mevcut kullanarak PDF'leri oluşturulmasını sağlayan bir örnek uygulaması ile birlikte detaylı here hatasından tarif ettik.

    NB: Ben sadece Base64 ve çalışma "harici" (yani http://example.com/my-image.png) görüntüleri almak başardınız.

    +0

    Çok ilginç analiz!Paylaştığın için çok teşekkürler. IOS 11'de bulduğumuz şeyi görmek ilginç olacak, ben de denemedim. @ pete-hornsby'nin çözümü kısa vadeli sorunumu çözdü, ancak bunu yapmak için daha doğrudan bir yol olması gerektiğini düşünüyor. –

    +0

    @ HélèneMartin Teşekkürler! Eh, iOS 11'i kurdum ve hata hala burada! Apple ile bir hata raporu hazırladım ... http://www.openradar.me/radar?id=6067400759836672 – nyg

    +0

    Henüz çok kötü değil, hata raporunu doldurduğunuz için teşekkürler! –