6

I have this code here that takes my UIView in puts it into a PDF. My issue I am having is that my view is a detail view controller and is scrollable and the PDF only gets what inside the detail view controller at that time and not a full view, if I move around in the detail view, it will capture whatever part I am on, not the full thing. Is what I am trying to do possible?

- (IBAction)Share:(id)sender {

    NSMutableData *pdfData = [NSMutableData data];

    // Points the pdf converter to the mutable data object and to the UIView to be converted
    UIGraphicsBeginPDFContextToData(pdfData, spreadSheet.bounds, nil);
    UIGraphicsBeginPDFPage();
    CGContextRef pdfContext = UIGraphicsGetCurrentContext();


    // draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData

    [spreadSheet.layer renderInContext:pdfContext];

    // remove PDF rendering context
    UIGraphicsEndPDFContext();

    // Retrieves the document directories from the iOS device
    NSArray* documentDirectories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);

    NSString* documentDirectory = [documentDirectories objectAtIndex:0];
    NSString* documentDirectoryFilename = [documentDirectory stringByAppendingPathComponent:@"test.pdf"];

    // instructs the mutable data object to write its context to a file on disk
    [pdfData writeToFile:documentDirectoryFilename atomically:YES];
    NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename);


    UIActivityViewController * activityController = [[UIActivityViewController alloc] initWithActivityItems:@[pdfData] applicationActivities:nil];

    UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:activityController];

    [popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width - 36, 60, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

}

UPDATE

I have been really struggling with this, I can't get the full view into a PDF, I have also been thinking of going to route of taking my NSMutableArray and my NSArray which is the data used in my UIView and try to covert that into a PDF but that sounds very time consuming to make format it nicely, unless someone knows of way to do that. I guess I am confused on which route I should take.

user979331
  • 11,039
  • 73
  • 223
  • 418
  • So what you want is actually not the "full UIView", it's a compilation of one UIView in a bunch of different states? What are you using for your detail view controller? Which class? – Tommy Oct 09 '15 at 15:12
  • Have you tried using the content size of the spreadsheet, instead of the bounds? – Sheamus Oct 10 '15 at 02:44
  • What is the hierarchy of "spreadSheet"? if it is a tableview or a collection view than there is no straightforward way to do this because the cells that are not visible are not even rendered yet. – Aris Oct 16 '15 at 08:07
  • @Aris In case of tableView or collection view you can force to rendered all the cells whenever you want. – Imran Oct 16 '15 at 08:51
  • like you can loop thorough and call [self tableView: self.tableView cellForRowAtIndexPath: indexPath]; – Imran Oct 16 '15 at 08:56
  • @Imran You are right there are ways to get around the problem. But imo it's not efficient to do it this way. What if you have 3000 cells (not uncommon for a spreadsheet). There might even be timing issues with the drawing. – Aris Oct 16 '15 at 09:03
  • @Aris I agree with you . Just talking about the possible solution you have to think of a way around to overcome some of the issues like this. – Imran Oct 16 '15 at 09:16

3 Answers3

2

From this

My issue I am having is that my view is a detail view controller and is scrollable and the PDF only gets what inside the detail view controller at that time and not a full view.

Looks like the problem is your content in view is scrollable and you pdf you creating is only capture the visible area.

Here is your problem

UIGraphicsBeginPDFContextToData(pdfData, spreadSheet.bounds, nil);

You need to fix it you need to give it the scrollable view (UITableView,UICollectionView or Scrollview) content size bounds here is how you do it.

    -(NSData*)pdfDataFromTableViewContent
{
   NSMutableData *pdfData = [NSMutableData data];
   //The real size, not only the visible part use your scrollable view ((UITableView,UICollectionView or Scrollview))
   CGSize contentSize = self.tableView.contentSize;
   CGRect tableViewRealFrame = self.tableView.frame;
   //Size tableView to show the whole content
   self.tableView.frame = CGRectMake(0, 0, contentSize.width, contentSize.height);
   //Generate PDF (one page)
   UIGraphicsBeginPDFContextToData(pdfData,self.tableView.frame, nil);
   UIGraphicsBeginPDFPage();
   [self.tableView.layer renderInContext:UIGraphicsGetCurrentContext()];
   UIGraphicsEndPDFContext();
   //Resize frame
   self.tableView.frame = tableViewRealFrame;
   return  pdfData;
}

The above code will generates one page. For more pages use following code

//MultiPage
CGRect mediaBox = self.tableView.frame;
CGSize pageSize = CGSizeMake(self.view.frame.size.width, 800);
UIGraphicsBeginPDFContextToData(pdfData, CGRectZero, nil);
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
NSInteger currentPage = 0;
BOOL done = NO;
do {
    UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0.0, pageSize.width, pageSize.height), nil);
    CGContextTranslateCTM(pdfContext, 0, -(pageSize.height*currentPage));
    [self.view.layer renderInContext:pdfContext];
    if ((pageSize.height*(currentPage+1)) > mediaBox.size.height) done = YES;
    else currentPage++;
} while (!done);
UIGraphicsEndPDFContext();

You can also look into this working project ScrollViewToPDF. It uses same scrollview's layer renderInContext but here PDF is created according to your requirement such as one page PDF or multiple page PDF. It captures all visible as well as invisible part of scrollView

Imran
  • 2,985
  • 19
  • 33
1

Rendering something into a context only renders what is currently in the view hierarchy. That means that if you're using a UITableView or UICollectionView, not every cell that represents your data is in the hierarchy at any given time. If it were me I would try temporarily setting the view to have a massive frame so that everything would be in the hierarchy. If that didn't work I'd be writing a custom view that on request could layout everything for all the data and then reset to a more efficient layout after the rendering was complete.

InkGolem
  • 2,662
  • 1
  • 15
  • 22
0

Try following code to convert UIView to PDF.

Note that the following method creates just a bitmap of the view; it does not create actual typography.

-(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename
{
    // Creates a mutable data object for updating with binary data, like a byte array
    NSMutableData *pdfData = [NSMutableData data];

    // Points the pdf converter to the mutable data object and to the UIView to be converted
    UIGraphicsBeginPDFContextToData(pdfData, aView.bounds, nil);
    UIGraphicsBeginPDFPage();
    CGContextRef pdfContext = UIGraphicsGetCurrentContext();


    // draws rect to the view and thus this is captured by UIGraphicsBeginPDFContextToData

    [aView.layer renderInContext:pdfContext];

    // remove PDF rendering context
    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];
    NSLog(@"documentDirectoryFileName: %@",documentDirectoryFilename);
}

Also make sure you import: QuartzCore/QuartzCore.h

Piyush
  • 1,534
  • 12
  • 32