I have created pdf with specific layout. The problem is that When the contents of text view is very long, Pdf will not automatically generate new page and I can not predefine how many pages will be created at run time. Can anyone please help me?
You can try by using this code this may help you Keep a textview and a button in Interface builder and use the button action method and generate pdf import these frameworks
#import <QuartzCore/QuartzCore.h>
#import <CoreText/CoreText.h>
-(NSString*)getPDFFileName
{
NSString* fileName = @"sample.PDF";
NSArray *arrayPaths =
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *path = [arrayPaths objectAtIndex:0];
NSString* pdfFileName = [path stringByAppendingPathComponent:fileName];
return pdfFileName;
}
-(IBAction)PdfGeneration:(id)sender{
// Prepare the text using a Core Text Framesetter.
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (__bridge CFStringRef)txtObj.text, NULL);
if (currentText) {
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);
if (framesetter) {
NSString *pdfFileName = [self getPDFFileName];
// Create the PDF context using the default page size of 612 x 792.
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);
CFRange currentRange = CFRangeMake(0, 0);
NSInteger currentPage = 0;
BOOL done = NO;
do {
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
currentPage++;
[self drawPageNumber:currentPage];
currentRange = [self renderPage:currentPage withTextRange:currentRange andFramesetter:framesetter];
if (currentRange.location == CFAttributedStringGetLength((CFAttributedStringRef)currentText))
done = YES;
} while (!done);
UIGraphicsEndPDFContext();
CFRelease(framesetter);
} else {
NSLog(@"Could not create the framesetter needed to lay out the atrributed string.");
}
// Release the attributed string.
CFRelease(currentText);
} else {
NSLog(@"Could not create the attributed string for the framesetter");
}
}
// Use Core Text to draw the text in a frame on the page.
- (CFRange)renderPage:(NSInteger)pageNum withTextRange:(CFRange)currentRange
andFramesetter:(CTFramesetterRef)framesetter
{
// Get the graphics context.
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);
CGRect frameRect = CGRectMake(72, 72, 468, 648);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);
CGContextTranslateCTM(currentContext, 0, 792);
CGContextScaleCTM(currentContext, 1.0, -1.0);
CTFrameDraw(frameRef, currentContext);
currentRange = CTFrameGetVisibleStringRange(frameRef);
currentRange.location += currentRange.length;
currentRange.length = 0;
CFRelease(frameRef);
return currentRange;
}
- (void)drawPageNumber:(NSInteger)pageNum
{
NSString *pageString = [NSString stringWithFormat:@"Page %d", pageNum];
UIFont *theFont = [UIFont systemFontOfSize:12];
CGSize maxSize = CGSizeMake(612, 72);
CGSize pageStringSize = [pageString sizeWithFont:theFont constrainedToSize:maxSize lineBreakMode:UILineBreakModeClip];
CGRect stringRect = CGRectMake(((612.0 - pageStringSize.width) / 2.0),720.0 + ((72.0 - pageStringSize.height) / 2.0),pageStringSize.width,pageStringSize.height);
[pageString drawInRect:stringRect withFont:theFont];
}
//StartNewPage
UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);
Find the height of text in textview entered if it exceeds your page frame setting call this method PageFrame is the new page frame of the pdf
SO MANY USERS ARE SEARCHING FOR THIS CODE TO BE COMPATIBLE FOR SWIFT VERSION. so here it is for swift 4 & 5.
// PDF name and generate on local path:
func writeToPDF(filenameStr:String)
{
pageSize = CGSize.init(width: 768, height: 10000)
// let fileName: NSString = "test.pdf"
let fileName = String.init(format: "%@.pdf", filenameStr)
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let pdfPathWithFileName = documentDirectory.appending("/" + fileName)// documentDirectory.appending(fileName as String)
self.PdfGeneration(filePath: pdfPathWithFileName)
//lines written to get the document directory path for the generated pdf file.
if let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.path {
print("documentsPath",documentsPath)
// “var/folder/…/documents ” copy the full path
}
}
// method to generate pdf file to display the text and image in pdf file.
func PdfGeneration(filePath: String)
{
// Prepare the text using a Core Text Framesetter.
//CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, (__bridge CFStringRef)txtObj.text, NULL);
let currentText = CFAttributedStringCreate(nil, (self.textVW_file.text as? CFString?)!, nil)
if(currentText != nil)
{
let framesetter = CTFramesetterCreateWithAttributedString(currentText!)
if (framesetter != nil) {
UIGraphicsBeginPDFContextToFile(filePath, .zero, nil)
var currentRange = CFRangeMake(0, 0)
var currentPage = 0
var done = false
repeat {
repeat {
UIGraphicsBeginPDFPageWithInfo(CGRect.init(x:0, y:0, width:612, height:792), nil)
currentPage = currentPage + 1
self.drawPageNumber(currentPage)
currentRange = self.renderPage(currentPage, withTextRange: currentRange, andFramesetter: framesetter)
let aText:CFAttributedString = currentText!
print("currentText %@",currentText!)
print("currentRange.location %@ and %@",currentRange.location,CFAttributedStringGetLength(aText))
if (currentRange.location == CFAttributedStringGetLength(aText)) {
done = true
}
}while (!done)
UIGraphicsEndPDFContext()
}
else
{
print("Could not create the framesetter needed to lay out the atrributed string.")
}
}
else
{
print("Could not create the framesetter needed to lay out the atrributed string.")
}
}
// Use Core Text to draw the text in a frame on the page.
func renderPage(_ pageNum: Int, withTextRange currentRange: CFRange, andFramesetter framesetter: CTFramesetter?) -> CFRange {
var currentRangeIn:CFRange
let currentContext = UIGraphicsGetCurrentContext()
currentContext?.textMatrix = .identity
let frameRect = CGRect(x: 72, y: 72, width: 468, height: 648)
let framePath = CGMutablePath()
framePath.addRect(frameRect, transform: .identity)
let frameRef = CTFramesetterCreateFrame(framesetter!, currentRange, framePath, nil)
currentContext?.translateBy(x: 0, y: 792)
currentContext?.scaleBy(x: 1.0, y: -1.0)
CTFrameDraw(frameRef, currentContext!)
currentRangeIn = currentRange
currentRangeIn = CTFrameGetVisibleStringRange(frameRef)
currentRangeIn.location += currentRange2.length
currentRangeIn.length = 0
return currentRangeIn
}
//And draw page number at bottom
func drawPageNumber(_ pageNum: Int) {
let pageString = "Page \(pageNum)"
let theFont = UIFont.systemFont(ofSize: 12)
let maxSize = CGSize(width: 612, height: 72)
let pageStringSize: CGSize = pageString.size(withAttributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 14.0)])
//let pageStringSize = pageString.size(with: theFont, constrainedTo: maxSize, lineBreakMode: [])
let stringRect = CGRect(x: (612.0 - pageStringSize.width) / 2.0, y: 720.0 + ((72.0 - pageStringSize.height) / 2.0), width: pageStringSize.width, height: pageStringSize.height)
pageString.draw(in: stringRect, withAttributes: [NSAttributedString.Key.font : theFont])
}
来源:https://stackoverflow.com/questions/15066231/create-multipage-pdf-directly-from-uitextview-in-ipad