从NSAttributedString swift 3生成多页PDF

时间:2017-06-13 09:17:22

标签: ios pdf swift3

我有一段很长NSAttributedString,我试图绘制为PDF,使用绘图功能制作单页PDF非常简单:

func createPDFFilea(atext: NSAttributedString) -> NSMutableData {

    let pdfData = NSMutableData()
    let paperRect = CGRect(x: 0, y: 0, width: 595.2, height: 841.8);
    UIGraphicsBeginPDFContextToData(pdfData, paperRect, nil)
    UIGraphicsBeginPDFPage()

    atext.draw(in: paperRect)
    UIGraphicsEndPDFContext()

    return pdfData
}

但如果文字超过paperRect则会丢失,如何管理?

PS。这里有一个类似的解决方案,对于obj-C只有一个简单的NSString http://www.coderzheaven.com/2016/09/07/create-pdf-in-ios/ 但我无法弄清楚在Swift中得到它,似乎官方的苹果文档也只适用于obj-C https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GeneratingPDF/GeneratingPDF.html

1 个答案:

答案 0 :(得分:1)

我终于设法将obj-C代码转换为swift3

    func createPDFwithAttributedString(_ currentText: NSAttributedString) -> NSMutableData {

    let pdfData = NSMutableData()

    // Create the PDF context using the default page size of 612 x 792.
    UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)

    let framesetter = CTFramesetterCreateWithAttributedString(currentText)

    var currentRange = CFRangeMake(0, 0);
    var currentPage = 0;
    var done = false;

    repeat {
        // Mark the beginning of a new page.
        UIGraphicsBeginPDFPageWithInfo(CGRect(x: 0, y: 0, width: 612, height: 792), nil);

        // Draw a page number at the bottom of each page.
        currentPage += 1;

        // Render the current page and update the current range to
        // point to the beginning of the next page.
        renderPagewithTextRange(currentRange: &currentRange, framesetter: framesetter)

        // If we're at the end of the text, exit the loop.
        if (currentRange.location == CFAttributedStringGetLength(currentText)){
            done = true;
        }
    } while (!done);

    // Close the PDF context and write the contents out.
    UIGraphicsEndPDFContext();
    return pdfData
}

func renderPagewithTextRange (currentRange: inout CFRange,  framesetter: CTFramesetter) {
    // Get the graphics context.
    if let currentContext = UIGraphicsGetCurrentContext(){

        // Put the text matrix into a known state. This ensures
        // that no old scaling factors are left in place.
        currentContext.textMatrix = CGAffineTransform.identity;

        // Create a path object to enclose the text. Use 72 point
        // margins all around the text.
        let frameRect = CGRect(x: 72, y: 72, width: 468, height: 648);
        let framePath = CGMutablePath();
        framePath.addRect(frameRect)

        // Get the frame that will do the rendering.
        // The currentRange variable specifies only the starting point. The framesetter
        // lays out as much text as will fit into the frame.
        let frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, nil);

        // Core Text draws from the bottom-left corner up, so flip
        // the current transform prior to drawing.
        currentContext.translateBy(x: 0, y: 792);
        currentContext.scaleBy(x: 1.0, y: -1.0);

        // Draw the frame.
        CTFrameDraw(frameRef, currentContext);

        // Update the current range based on what was drawn.
        currentRange = CTFrameGetVisibleStringRange(frameRef);
        currentRange.location += currentRange.length;
        currentRange.length = 0;
    }
}