Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C Full UIView to PDF

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.

like image 395
user979331 Avatar asked Oct 06 '15 19:10

user979331


2 Answers

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

like image 72
Imran Avatar answered Sep 30 '22 14:09

Imran


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.

like image 32
InkGolem Avatar answered Sep 30 '22 12:09

InkGolem