How to create paginated PDF from NSTextView?

If I use -[NSView dataWithPDFInsideRect:] to create a PDF from an NSTextView, I get a single-page PDF with stuff past the bottom cut off. What do I need to do to get pagination to happen? Would embedding the NSTextView in an NSScrollView help?

Replies

I tried this

	NSMutableData* pdfData = [[NSMutableData alloc] init];
	NSPrintOperation* printOp = [NSPrintOperation
		PDFOperationWithView: textView
		insideRect: pageBounds
		toData: pdfData
		printInfo: NSPrintInfo.sharedPrintInfo];
	[printOp runOperation];

and it still creates only one page.

I also tried making a subclass of NSTextView that overrides rectForPage: and knowsPageRange:, but those methods never got called.

Creating a PDF with multiple pages isn't easy. You are going to have use Quartz (CoreGraphics). Create a PDF context. Do the following until you reach the end of the text:

  1. Determine how much text can fit on a page.
  2. Call the PDF context's beginPage function.
  3. Draw the page of text.
  4. Call the PDF context's endPage function.
  5. Update the location in the text to start drawing the next page.

The following article explains what you have to do to create a multiple page PDF with Quartz and Core Text:

https://www.meandmark.com/blog/2016/08/creating-pdfs-with-core-text-and-quartz/

The TPPDF Swift package can be used to create PDF files. You will probably find it easier to use than to create a PDF with Quartz.

https://github.com/techprimate/TPPDF

Thanks for writing, and I don’t doubt that your approach would work, but I don’t get why creating PDF should be fundamentally harder than any other multi page print job, since it’s just a special case.

By the way, I tried making a non-PDF NSPrintOperation, and that produced multiple pages that were all blank. Apple’s docs gave me the impression that it shouldn’t be so hard to print a view.

I came up with yet another approach: I inserted the text view in an NSClipView, which I inserted in a printing-aware container view, and then printed to a temporary PDF file, like this:

NSPrintInfo* printInfo = [[NSPrintInfo alloc] init];
printInfo.paperSize = pageBounds.size;
printInfo.topMargin = 0.0;
printInfo.bottomMargin = 0.0;
printInfo.leftMargin = 0.0;
printInfo.rightMargin = 0.0;
printInfo.horizontallyCentered = NO;
printInfo.verticallyCentered = NO;
printInfo.verticalPagination = NSPrintingPaginationModeAutomatic;
printInfo.horizontalPagination = NSPrintingPaginationModeClip;
printInfo.jobDisposition = NSPrintSaveJob;
printInfo.dictionary[NSPrintJobSavingURL] = tempPDFURL;
NSPrintOperation* printOp = [NSPrintOperation
    printOperationWithView: container
    printInfo: printInfo];
printOp.showsProgressPanel = NO;
printOp.showsPrintPanel = NO;
[printOp runOperation];

It works, except for one thing. My text contains some link attributes. When creating PDF using the PDF-specific methods like dataWithPDFInsideRect:, those links turn into PDF annotations. When printing this way, the links just go away. Aargh.