Cannot Create PDF Document with 400+ Pages on iOS

iOS - How to overwrite a single page of PDF files?

Very similar :Merge PDF files on iOS

It's not possible to reopen and continue editing a PDF file . Only read and redraw whole PDF again .

Cannot add image and save to pdf file using PDFKit

I have to also draw that image on PDFPage to make them appear in the saved pdf file

final private class ImagePDFPage: PDFPage {

/// A flag indicates whether to draw image on a page
///
/// - Note: Set this to `true` before write pdf to file otherwise the image will not be appeared in pdf file
var saveImageToPDF: Bool = false

private var imageAnnotation: EkoPDFImageAnnotation? = nil

func addImageAnnotation(_ annotation: EkoPDFImageAnnotation) {
imageAnnotation = annotation
addAnnotation(annotation)
}

func removeImageAnnotation() {
guard let imageAnnotation = imageAnnotation else { return }
self.imageAnnotation = nil
removeAnnotation(imageAnnotation)
}

override func draw(with box: PDFDisplayBox, to context: CGContext) {
super.draw(with: box, to: context)

guard saveImageToPDF,
let annotation = imageAnnotation,
let cgImage = annotation.image?.cgImage else { return }
context.draw(cgImage, in: annotation.bounds)
}
}

and update PDFDocument.delegate to tell to use ImagePDFPage as a class for pdf page

extension PDFEditorViewController: PDFDocumentDelegate {
func classForPage() -> AnyClass {
return ImagePDFPage.self
}
}

The result

Sample Image

How can I lower memory climb when generating large PDF's

In general, memory is finite and your generated output isn't, so the way to make it work is to ensure that:

  • you're not accumulating the entire PDF in memory as you generate it
  • you're not unnecessarily keeping around byproducts of the rendering for each page

In your case, using UIGraphicsBeginPDFContextToData means that you're rendering the whole PDF to an ever-expanding NSData. When that data gets too big, you'll get killed. Instead, try UIGraphicsBeginPDFContextToFile. Also in your inner loop for rendering pages, consider inserting an @autoreleasepool { ... } block to prevent objects from building up unnecessarily during a long run. I'm not sure how big your pagesArray bunch of stuff actually is, and whether that's something you might consider "paging in" one page at a time as you generate.

Create PDF file with BIG html CODE

Try taking a look at this: https://pdfmerger.codeplex.com/

Then, divide the html, render each part into a separate file, and then merge them afterwards..

Create dynamic pdf documents on iOS

To draw some text in our PDF, we’re going to need to use the Core Text framework. To do this, select the project target and go to the Build Phases tab. Click the + sign below the Link Binaries With Libraries option, and then select the CoreText framework.

Then open ViewController.h and import the CoreText header:

#import <CoreText/CoreText.h>

Add a new method to ViewController.m to create a “hello world” PDF.

-(void)drawText
{
NSString* fileName = @"Invoice.PDF";

NSArray *arrayPaths =
NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory,
NSUserDomainMask,
YES);
NSString *path = [arrayPaths objectAtIndex:0];
NSString* pdfFileName = [path stringByAppendingPathComponent:fileName];

NSString* textToDraw = @"Hello World";
CFStringRef stringRef = (__bridge CFStringRef)textToDraw;

// Prepare the text using a Core Text Framesetter.
CFAttributedStringRef currentText = CFAttributedStringCreate(NULL, stringRef, NULL);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(currentText);

CGRect frameRect = CGRectMake(0, 0, 300, 50);
CGMutablePathRef framePath = CGPathCreateMutable();
CGPathAddRect(framePath, NULL, frameRect);

// Get the frame that will do the rendering.
CFRange currentRange = CFRangeMake(0, 0);
CTFrameRef frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, NULL);
CGPathRelease(framePath);

// Create the PDF context using the default page size of 612 x 792.
UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);

// Mark the beginning of a new page.
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);

// Get the graphics context.
CGContextRef currentContext = UIGraphicsGetCurrentContext();

// Put the text matrix into a known state. This ensures
// that no old scaling factors are left in place.
CGContextSetTextMatrix(currentContext, CGAffineTransformIdentity);

// Core Text draws from the bottom-left corner up, so flip
// the current transform prior to drawing.
CGContextTranslateCTM(currentContext, 0, 100);
CGContextScaleCTM(currentContext, 1.0, -1.0);

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

CFRelease(frameRef);
CFRelease(stringRef);
CFRelease(framesetter);

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

}

References

1. How to create a pdf with quartz-2d in ios part-1

2. How to create a pdf with quartz 2d in ios part-2

For More on CoreText framework

1. Core text tutorial for ios making a magazine app

2. About Core Text - Apple Doc

when export to pdf i got extra one empty page

I suspect that one of your images is too large, but without access to the images I can't tell for sure. I created three images with SF Symbols and played with resizing the images. I can create the problem by setting the images too large.

    let images = [NSImage(systemSymbolName: "xmark", accessibilityDescription: "xmark")!,
NSImage(systemSymbolName: "pencil.slash", accessibilityDescription: "pencil")!,
NSImage(systemSymbolName: "pencil.and.outline", accessibilityDescription: "pencil")!]
let document = PDFDocument(format: .a4)
document.add(.footerLeft, textObject: PDFSimpleText(text: "Generated from Pdf Scanner"))
for eachImage in images {
// eachImage.size = NSSize(width: 400, height: 380)
// above works
eachImage.size = NSSize(width: 790, height: 760)
let imageElement = PDFImage(image: eachImage)
imageElement.sizeFit = .height
document.add(.contentCenter ,image: imageElement)
}

let generator = PDFGenerator(document: document)
generator.debug = true
let pdfUrl = (try? generator.generateURL(filename: "Example.pdf"))!
print("pdf location: \(pdfUrl)")

Note: generator.debug = true might be useful.

PDF specification for appending

As others have already mentioned, merging two PDF files together will be a large undertaking, if you don't use a PDF library. You will need a solid understanding of the internal PDF structure. Here is a link to the PDF specification. It's a good place to get started - PDF Reference.

Before I go into detail, here is a little experiment in merging two very simple PDF files, and the result. The two files are 34kb each. The resulting file was 35kb, and it contained the pages of each of the input files. That alone shows that there is more going on under the hood than merging the code for the two input documents. Comparing the code for the input and output documents, also showed that they have been completely re-created, with different object IDs for each object.

A usual PDF document contains a header, body, cross-reference table and a trailer.
When a PDF document is read, the library starts from the top, and then jumps to the end of the document, moving back, until it hits the cross-reference table. In this table, the library looks for the objects, and byte offsets in a particular document. This table is updated, or re-created when new objects are added to the document.

To merge two documents manually, you will have to move the objects from the body of the second document into the first document. Then you can update the metadata of the first document if necessary. The difficult task here is updating, and possibly re-creating the cross-reference table. You will need to implement a significant portion of the PDF spec to be able to do that.

If you decide to use a library in your project, there are some fairly lightweight libraries out there that will do the trick. The PDFtk library is fairly lightweight, and can do PDF merging with 1 command. It has a free version, as well as command line capabilities. You should be able to set up a simple server to host it in your environment, and then call it via Java Script.

In case your project requires more than a free library, then there is APDFL, which is a commercial PDF processing library. It has a .NET or a Java interface, so you can easily create a server app that will merge PDF files for you.



Related Topics



Leave a reply



Submit