Creando archivo PDF desde UIWebView

-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename { // Creates a mutable data object for updating with binary data, like a byte array UIWebView *webView = (UIWebView*)aView; NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"]; int height = [heightStr intValue]; // Get the number of pages needed to print. 9 * 72 = 648 int pages = ceil(height / 648.0); NSMutableData *pdfData = [NSMutableData data]; UIGraphicsBeginPDFContextToData( pdfData, CGRectZero, nil ); CGRect frame = [webView frame]; for (int i = 0; i  height) { CGRect f = [webView frame]; f.size.height -= (((i+1) * 648.0) - height); [webView setFrame: f]; } UIGraphicsBeginPDFPage(); CGContextRef currentContext = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(currentContext, 72, 72); // Translate for 1" margins [[[webView subviews] lastObject] setContentOffset:CGPointMake(0, 648 * i) animated:NO]; [webView.layer renderInContext:currentContext]; } UIGraphicsEndPDFContext(); // Retrieves the document directories from the iOS device NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES); NSString* documentDirectory = [documentDirectories objectAtIndex:0]; NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename]; // instructs the mutable data object to write its context to a file on disk [pdfData writeToFile:documentDirectoryFilename atomically:YES]; [webView setFrame:frame]; NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename); } 

Estoy usando el código anterior para generar un archivo pdf desde una vista web. Está funcionando, sin embargo, el contenido no se recorta correctamente: el contenido en la parte inferior de las páginas se arruina. Creo que podría hacer algo mejor usando los métodos Core Graphics pero no puedo encontrar cómo hacerlo. Algunas ideas ?

Utilice UIPrintPageRenderer desde UIWebView Siga los pasos a continuación:

Agregue Category de UIPrintPageRenderer para obtener datos PDF

 @interface UIPrintPageRenderer (PDF) - (NSData*) printToPDF; @end @implementation UIPrintPageRenderer (PDF) - (NSData*) printToPDF { NSMutableData *pdfData = [NSMutableData data]; UIGraphicsBeginPDFContextToData( pdfData, self.paperRect, nil ); [self prepareForDrawingPages: NSMakeRange(0, self.numberOfPages)]; CGRect bounds = UIGraphicsGetPDFContextBounds(); for ( int i = 0 ; i < self.numberOfPages ; i++ ) { UIGraphicsBeginPDFPage(); [self drawPageAtIndex: i inRect: bounds]; } UIGraphicsEndPDFContext(); return pdfData; } @end 

Agregue estas definiciones para tamaño A4

 #define kPaperSizeA4 CGSizeMake(595.2,841.8) 

Ahora en UIWebView's delegate UIWebView's webViewDidFinishLoad use la property UIWebView de UIWebView .

 - (void)webViewDidFinishLoad:(UIWebView *)awebView { if (awebView.isLoading) return; UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init]; [render addPrintFormatter:awebView.viewPrintFormatter startingAtPageAtIndex:0]; //increase these values according to your requirement float topPadding = 10.0f; float bottomPadding = 10.0f; float leftPadding = 10.0f; float rightPadding = 10.0f; CGRect printableRect = CGRectMake(leftPadding, topPadding, kPaperSizeA4.width-leftPadding-rightPadding, kPaperSizeA4.height-topPadding-bottomPadding); CGRect paperRect = CGRectMake(0, 0, kPaperSizeA4.width, kPaperSizeA4.height); [render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"]; [render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"]; NSData *pdfData = [render printToPDF]; if (pdfData) { [pdfData writeToFile:[NSString stringWithFormat:@"%@/tmp.pdf",NSTemporaryDirectory()] atomically: YES]; } else { NSLog(@"PDF couldnot be created"); } } 

Gracias por tus respuestas Firemarble, me ayudó mucho. Logré obtener resultados algo buenos con este método:

 -(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename { // Creates a mutable data object for updating with binary data, like a byte array UIWebView *webView = (UIWebView*)aView; NSString *heightStr = [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"]; int height = [heightStr intValue]; // CGRect screenRect = [[UIScreen mainScreen] bounds]; // CGFloat screenHeight = (self.contentWebView.hidden)?screenRect.size.width:screenRect.size.height; CGFloat screenHeight = webView.bounds.size.height; int pages = ceil(height / screenHeight); NSMutableData *pdfData = [NSMutableData data]; UIGraphicsBeginPDFContextToData(pdfData, webView.bounds, nil); CGRect frame = [webView frame]; for (int i = 0; i < pages; i++) { // Check to screenHeight if page draws more than the height of the UIWebView if ((i+1) * screenHeight > height) { CGRect f = [webView frame]; f.size.height -= (((i+1) * screenHeight) - height); [webView setFrame: f]; } UIGraphicsBeginPDFPage(); CGContextRef currentContext = UIGraphicsGetCurrentContext(); // CGContextTranslateCTM(currentContext, 72, 72); // Translate for 1" margins [[[webView subviews] lastObject] setContentOffset:CGPointMake(0, screenHeight * i) animated:NO]; [webView.layer renderInContext:currentContext]; } UIGraphicsEndPDFContext(); // Retrieves the document directories from the iOS device NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES); NSString* documentDirectory = [documentDirectories objectAtIndex:0]; NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:aFilename]; // instructs the mutable data object to write its context to a file on disk [pdfData writeToFile:documentDirectoryFilename atomically:YES]; [webView setFrame:frame]; } 

Solución Swift 2.0, cómo guardar el pdf de la vista web a NSData:

 func webViewDidFinishLoad(webView: UIWebView) { let pdfData = createPdfFile(webView.viewPrintFormatter()) pdfData.writeToFile("/path/to/file", atomically: true) } func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSData { let renderer = UIPrintPageRenderer() renderer.addPrintFormatter(printFormatter, startingAtPageAtIndex: 0); let paperSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height) let printableRect = CGRectMake(0, 0, paperSize.width, paperSize.height) let paperRect = CGRectMake(0, 0, paperSize.width, paperSize.height); renderer.setValue(NSValue(CGRect: paperRect), forKey: "paperRect") renderer.setValue(NSValue(CGRect: printableRect), forKey: "printableRect") return renderer.printToPDF() } 

También necesita agregar UIWebViewDelegate a su ViewController y extensión para UIPrintPageRenderer.

 extension UIPrintPageRenderer { func printToPDF() -> NSData { let pdfData = NSMutableData() UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil) self.prepareForDrawingPages(NSMakeRange(0, self.numberOfPages())) let bounds = UIGraphicsGetPDFContextBounds() for i in 0.. 

Swift 3 solución de respuesta @Dan Loewenherz:

 func webViewDidFinishLoad(_ webView: UIWebView) { let pdfData = createPdfFile(printFormatter: webView.viewPrintFormatter()) pdfData.write(toFile: "/path/to/file", atomically: true) } func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSData { let renderer = UIPrintPageRenderer() renderer.addPrintFormatter(printFormatter, startingAtPageAt: 0) let point = CGPoint(x:0,y:0) let paperSize = CGSize(width: self.view.frame.size.width, height: self.view.frame.size.height) let printableRect = CGRect(origin: point, size: CGSize(width:paperSize.width, height: paperSize.height)) let paperRect = CGRect(origin: point, size: CGSize(width: paperSize.width, height: paperSize.height)) renderer.setValue(NSValue(cgRect: paperRect), forKey: "paperRect") renderer.setValue(NSValue(cgRect: printableRect), forKey: "printableRect") return renderer.printToPDF() } extension UIPrintPageRenderer { func printToPDF() -> NSData { let pdfData = NSMutableData() UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil) self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages)) let bounds = UIGraphicsGetPDFContextBounds() for i in 0.. 

Parece que el problema puede provenir de la altura codificada 648. ¿Qué sucede si cambia todas las instancias de 648 para llamar a la pantalla de Windows? Altura ?

// Coge el ancho y el alto de la ventana.

 CGRect screenRect = [[UIScreen mainScreen] bounds]; CGFloat screenWidth = screenRect.size.width; CGFloat screenHeight = screenRect.size.height;