0

I'm trying to save all of the contents of a UIScrollView to a .pdf. I found some tutorials for saving the current view, and they all rely on creating a CGContextRef using UIGraphicsGetCurrentContext(). Right now, I capture my view with just

CGContextRef context = UIGraphicsGetCurrentContext();
[myView.layer renderInContext:context];

And that works fine for a plain UIView. However, when I try to pass a UIScrollView as myView, it passes the visible part of the UIScrollView fine, but anything offscreen is just white space. Is there a way I can expand context somehow to get all of the content in my UIScrollView, and not just what is currently visible? I suspect that I can't use UIGraphicsGetCurrentContext() for a UIScrollView, but I don't know what to use instead, and the Apple docs on this aren't really very helpful.

GeneralMike
  • 2,951
  • 3
  • 28
  • 56

4 Answers4

4

If you have a subview taking the whole content size of the scrollView with the scrolling content you can do it like this:

CGContextRef context = UIGraphicsGetCurrentContext();
UIView *contentView = [scrollView subviews][0];
[contentView.layer renderInContext:context];

If there are multiple views in the scrollView you can do it like this:

UIView *contentView = [[UIView alloc] initWithFrame:CGRectMake(
                                                          scrollView.frame.origin.x,
                                                          scrollView.frame.origin.y, 
                                                          scrollView.contentSize.width, 
                                                          scrollView.contentSize.height)];
for(UIView *view in [scrollView subviews]){
 [contentView addSubview: view];
}

CGContextRef context = UIGraphicsGetCurrentContext();
[contentView.layer renderInContext:context];

Then you need to get the views back into the scrollView. Probably there is a way to copy them but I am not sure how. Anyhow here is what should work:

for(UIView *view in [contentView subviews]){
 [view removeFromSuperView];
 [scrollView addSubview:view];
}
Petar
  • 2,241
  • 1
  • 24
  • 38
  • So close! This creates the .pdf perfectly, but after I create it, my whole screen is wiped clean. Do I have to do something to preserve the original scroll view? I am using the multiple views part btw. – GeneralMike Mar 21 '13 at 18:26
  • ah, of course. That works. There also may have been an issue with some conflicting names, so I patched that up and with the loop to add the views back, this works seemlessly. Thanks! – GeneralMike Mar 21 '13 at 18:54
  • @GeneralMike This may work but copying the entirety of the `UIScrollView`s content into a new `UIView` and then back again cannot be very performant. – Elliott Mar 21 '13 at 18:57
  • Yes I agree, its not very efficient. Therefore you can have a containerView in your scrollView which will contain all your views, and it wont be needed to copy them. – Petar Mar 21 '13 at 19:02
  • @ElliottPerry, pe60t0: ah, that's something to keep an eye on. For the view I'm using this on right now, there is no noticeable impact on performance, but I suppose it could be an issue if there was more content than I am currently dealing with. Thanks for all the help guys. – GeneralMike Mar 21 '13 at 19:23
0

You can set frame of UIScrollView equal to content size of it and content offset to 0 before calling renderInContext. After that revert frame to original.

myView.frame = CGRectMake(myView.frame.origin.x,myView.frame.origin.y,myView.contentSize.with,myView.contentSize.height);
msk
  • 8,885
  • 6
  • 41
  • 72
  • How do I set the frame of my scroll view? I tried doing `myView.frame.size = myView.contentSize;`, but I get an error saying "Expression is not assignable". Am I doing this wrong? – GeneralMike Mar 21 '13 at 18:29
  • check my updated answer, though seems like the problem is already solved for you =) – msk Mar 22 '13 at 09:28
0

This code i used to make pdf from uiscrollview and it does help but it will not be as good as if we draw on pdf -- please have look -- Pdf from UIScrollView

- (void) createPDF
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *directroyPath = nil;
    directroyPath = [documentsDirectory stringByAppendingPathComponent:@"temp"];
    NSString *filePath = [directroyPath stringByAppendingPathComponent:@"test.pdf"];
    // check for the "PDF" directory
    NSError *error;
    if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {

    } else {
        [[NSFileManager defaultManager] createDirectoryAtPath:directroyPath
                                  withIntermediateDirectories:NO
                                                   attributes:nil
                                                        error:&error];
    }

    CGContextRef pdfContext = [self createPDFContext:_scrollView2.bounds path:(CFStringRef)filePath];
    NSLog(@"PDF Context created");

    /*
     Here limit of i is no of pages in your uiscrollview or
     you can use hit and trial here because there is a
     length of page is going to be equal to 
     the visible size of uiscrollView in your application 
   */

    for (int i = 0 ; i< 2 ; i++)
    {

        // page 1
        CGContextBeginPage (pdfContext,nil);

        //turn PDF upsidedown
        CGAffineTransform transform = CGAffineTransformIdentity;

       //here 365 is equal to the height of myScrollView.frame.size.height

        transform = CGAffineTransformMakeTranslation(0, (i+1) * 365);
        transform = CGAffineTransformScale(transform, 1.0, -1.0);
        CGContextConcatCTM(pdfContext, transform);

        //Draw view into PDF
        [_scrollView2.layer renderInContext:pdfContext];
        CGContextEndPage (pdfContext);
        [_scrollView2 setContentOffset:CGPointMake(0, (i+1) * 365) animated:NO];

    }
    CGContextRelease (pdfContext);
}

- (CGContextRef) createPDFContext:(CGRect)inMediaBox path:(CFStringRef) path
{
    CGContextRef myOutContext = NULL;
    CFURLRef url;
    url = CFURLCreateWithFileSystemPath (NULL, path,
                                         kCFURLPOSIXPathStyle,
                                         false);

    if (url != NULL) {
        myOutContext = CGPDFContextCreateWithURL (url,
                                                  &inMediaBox,
                                                  NULL);
        CFRelease(url);
    }
    return myOutContext;
}
kshitij godara
  • 1,523
  • 18
  • 30
0

Check ScrollViewToPDF example and understand it.

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

Note : It captures all visible as well as invisible part of scrollView

Community
  • 1
  • 1
Paresh Navadiya
  • 38,095
  • 11
  • 81
  • 132