tutorial open example crear ios pdf uiwebview core-graphics crop

ios - open - Creando un archivo PDF desde UIWebView



web view swift 4 (6)

-(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 < pages; i++) { // Check to see if page draws more than the height of the UIWebView if ((i+1) * 648 > 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 de arriba 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 desordena. Creo que podría hacer algo mejor usando los métodos Core Graphics pero no puedo encontrar cómo hacerlo. Algunas ideas ?


Gracias por sus respuestas, Firemarble, me ayudó mucho. Logré obtener resultados bastante atractivos 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]; }


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

// Agarra las ventanas de ancho y alto.

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


Solución Swift 2.0, cómo guardar pdf desde webview 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 debe agregar UIWebViewDelegate a su ViewController y la 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..<self.numberOfPages() { UIGraphicsBeginPDFPage(); self.drawPageAtIndex(i, inRect: bounds) } UIGraphicsEndPDFContext(); return pdfData; } }


Use UIPrintPageRenderer de UIWebView Siga los pasos a continuación:

Agregar 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

Añadir estos definir para el 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"); } }


La solución Swift 3 de @Dan Loewenherz responde:

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..<self.numberOfPages { UIGraphicsBeginPDFPage(); self.drawPage(at: i, in: bounds) } UIGraphicsEndPDFContext(); return pdfData; } }


UIWebView está en desuso ahora. Use la extensión WKWebView para crear PDF desde WKWebView

Crédito: http://www.swiftdevcenter.com/create-pdf-from-uiview-wkwebview-and-uitableview/

Swift 4.2

extension WKWebView { // Call this function when WKWebView finish loading func exportAsPdfFromWebView() -> String { let pdfData = createPdfFile(printFormatter: self.viewPrintFormatter()) return self.saveWebViewPdf(data: pdfData) } func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSMutableData { let originalBounds = self.bounds self.bounds = CGRect(x: originalBounds.origin.x, y: bounds.origin.y, width: self.bounds.size.width, height: self.scrollView.contentSize.height) let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.scrollView.contentSize.height) let printPageRenderer = UIPrintPageRenderer() printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0) printPageRenderer.setValue(NSValue(cgRect: UIScreen.main.bounds), forKey: "paperRect") printPageRenderer.setValue(NSValue(cgRect: pdfPageFrame), forKey: "printableRect") self.bounds = originalBounds return printPageRenderer.generatePdfData() } // Save pdf file in document directory func saveWebViewPdf(data: NSMutableData) -> String { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let docDirectoryPath = paths[0] let pdfPath = docDirectoryPath.appendingPathComponent("webViewPdf.pdf") if data.write(to: pdfPath, atomically: true) { return pdfPath.path } else { return "" } } } extension UIPrintPageRenderer { func generatePdfData() -> NSMutableData { let pdfData = NSMutableData() UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil) self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages)) let printRect = UIGraphicsGetPDFContextBounds() for pdfPage in 0..<self.numberOfPages { UIGraphicsBeginPDFPage() self.drawPage(at: pdfPage, in: printRect) } UIGraphicsEndPDFContext(); return pdfData } }

Guardará el archivo PDF en el directorio y devolverá la ruta del archivo pdf.