iOS print NSAttributedString with images as NSTextAttachement to PDF

400 Views Asked by At

I'm trying to convert the content of an UITextView to PDF. The UITextView uses an NSAttributedString that contains text and images. The images are instances of NSTextAttachment.

I went through the UIPrintPageRenderer way passing the UIPrintFormatter that I get from the UITextView through its viewPrintFormatter() function and it works perfectly for the text but I can't see any of the images. It looks like the images are actually taking up space as I can see the empty space between text lines, but no image is being rendered.

I suspect it might be the formatter, but I don't know how to work around it. Any help is greatly appreciated.

The code I'm using to create the PDF from the NSAttributedString is the following:

public func createPDF(text: NSAttributedString, documentPath: URL, customPrintFormatter: UIPrintFormatter? = nil) {
    let printFormatter = customPrintFormatter == nil ? UISimpleTextPrintFormatter(attributedText: text) : customPrintFormatter!

    let renderer = UIPrintPageRenderer()
    renderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)

    // A4 size
    let pageSize = CGSize(width: 595.2, height: 841.8)

    // create some sensible margins
    let pageMargins = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)

    // calculate the printable rect from the above two
    let printableRect = CGRect(x: pageMargins.left, y: pageMargins.top, width: pageSize.width - pageMargins.left - pageMargins.right, height: pageSize.height - pageMargins.top - pageMargins.bottom)

    // and here's the overall paper rectangle
    let paperRect = CGRect(x: 0, y: 0, width: pageSize.width, height: pageSize.height)

    renderer.setValue(NSValue(cgRect: paperRect), forKey: "paperRect")
    renderer.setValue(NSValue(cgRect: printableRect), forKey: "printableRect")

    let pdfData = NSMutableData()

    UIGraphicsBeginPDFContextToData(pdfData, paperRect, nil)
    renderer.prepare(forDrawingPages: NSMakeRange(0, renderer.numberOfPages))

    let bounds = UIGraphicsGetPDFContextBounds()

    for i in 0  ..< renderer.numberOfPages {
        UIGraphicsBeginPDFPage()

        renderer.drawPage(at: i, in: bounds)
    }

    UIGraphicsEndPDFContext()

    do {
        try pdfData.write(to: documentPath)
    } catch {
        print(error.localizedDescription)
    }
}

The following is the code that creates the NSTextAttachment

        let attachment = NSTextAttachment()
        attachment.image = UIImage.init(named: "1.png")
        attachment.bounds = CGRect.init(x: 0, y: 0, width: 200, height: 100)
        let img = NSMutableAttributedString.init(attachment: attachment)

        let imgRange = NSRange.init(location: match.range(at: 0).location + match.range(at: 0).length, length: img.length)
        self.beginEditing()
        backingStore.insert(img, at: match.range(at: 0).location + match.range(at: 0).length)
        let r = NSMakeRange(match.range(at: 0).location + match.range(at: 0).length, img.length)
        self.edited([.editedCharacters, .editedAttributes], range: range, changeInLength: img.length)
        self.endEditing()
0

There are 0 best solutions below