从 UIScrollView + iphone 生成 PDF

Posted

技术标签:

【中文标题】从 UIScrollView + iphone 生成 PDF【英文标题】:PDF Generation From UIScrollView + iphone 【发布时间】:2011-03-11 04:26:22 【问题描述】:

我想生成一个 UIScrollView 的 pdf,其内容大小接近 320*2000。如果我使用当前图形图像上下文来捕获滚动视图层,那么它只会捕获滚动视图的可见部分,而不是该滚动视图的整个层。

我正在使用以下代码:

-(void)CreatePdf:(id)sender


    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *saveDirectory = [paths objectAtIndex:0];
    NSString *saveFileName = @"myPDF.pdf";
    [self writePDFAma];
    CGRect arect=CGRectMake(0, 0, 768, 1024);

    CreatePDFFileAma(arect, nil);




-(void) writePDFAma

    UIImage *image;
    NSData *data;
    UIAlertView *successAlert;
    UIAlertView *failureAlert;
    //  
    NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    //  // This should be our documents directory
    NSString *saveDiirectory = [documentPath objectAtIndex:0];
    //  // Our PDF is named 'Example.pdf'
    NSString *saveFileName = @"FormImage2.JPG";
    //  // Create the full path using our saveDirectory and saveFileName
    NSString *finalPath = [saveDiirectory stringByAppendingPathComponent:saveFileName];
    //NSLog(@"%@",finalPath);
    CGSize asize=CGSizeMake(_scrollview.frame.size.width, _scrollview.frame.size.height);
    //NSLog(@"%d..%d",mainViewAma.frame.size.width, mainViewAma.frame.size.height);
    UIGraphicsBeginImageContext(asize);
        [[_scrollview layer] renderInContext:UIGraphicsGetCurrentContext()];
image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    data = UIImageJPEGRepresentation(image, 1.0);

    BOOL catch;
    if(!catch)
        if ([[NSFileManager defaultManager] createFileAtPath:finalPath contents:data attributes:nil])
        
            successAlert = [[UIAlertView alloc] initWithTitle:@"Success" message:@"Doodle was successfully saved to the Photo Library." delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil];
            //[successAlert show];
            [successAlert release];
         else 
            failureAlert = [[UIAlertView alloc] initWithTitle:@"Failure" message:@"Failed to save doodle to the Photo Library." delegate:self cancelButtonTitle:@"Close" otherButtonTitles:nil];
            //[failureAlert show];
            [failureAlert release];
        

    




void CreatePDFFileAma (CGRect pageRect, const char *filename)

    // This code block sets up our PDF Context so that we can draw to it
    //some code here
    CGContextRef pdfContext;
    CFURLRef url;
    CFMutableDictionaryRef myDictionary = NULL;
    NSArray *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    //  // This should be our documents directory
    NSString *saveDirectory = [documentPath objectAtIndex:0];
    //  // Our PDF is named 'Example.pdf'



    //NSString *saveFileName = @"PDFForm2.pdf";



    //  // Create the full path using our saveDirectory and saveFileName
    NSString *finalPath = [saveDirectory stringByAppendingPathComponent:saveFileName];
    NSURL * aurl=[[NSURL alloc]initFileURLWithPath:finalPath];
    url=(CFURLRef)aurl;
    // This dictionary contains extra options mostly for 'signing' the PDF
    myDictionary = CFDictionaryCreateMutable(NULL, 0,
                                             &kCFTypeDictionaryKeyCallBacks,
                                             &kCFTypeDictionaryValueCallBacks);
    CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("AMA FORM PDF"));
    CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name2"));
    // Create our PDF Context with the CFURL, the CGRect we provide, and the above defined dictionary
    pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary);
    // Cleanup our mess
    CFRelease(myDictionary);
    CFRelease(url);
    // Starts our first page
    CGContextBeginPage (pdfContext, &pageRect);

    // Draws a black rectangle around the page inset by 50 on all sides
    CGContextStrokeRect(pdfContext, CGRectMake(50, 50, 768, 1024));

    // This code block will create an image that we then draw to the page
    CGImageRef image;
    CGDataProviderRef provider;
    CFURLRef pictureURL;
    documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    //  // This should be our documents directory
    saveDirectory = [documentPath objectAtIndex:0];
    NSString *saveFileName2 = @"FormImage2.JPG";
    //  // Create the full path using our saveDirectory and saveFileName
    NSString *finalPath2 = [saveDirectory stringByAppendingPathComponent:saveFileName2];
    NSURL * aurl2=[[NSURL alloc]initFileURLWithPath:finalPath2];
    pictureURL=(CFURLRef)aurl2;
    provider = CGDataProviderCreateWithURL (pictureURL);
    CFRelease (pictureURL);
    image = CGImageCreateWithJPEGDataProvider(provider, NULL, TRUE, kCGRenderingIntentDefault); //DataProvider (, NULL, true, kCGRenderingIntentDefault);
    CGDataProviderRelease (provider);
    CGContextDrawImage (pdfContext, CGRectMake(0, 0,768, 1024),image);
    CGImageRelease (image);
    CGContextEndPage (pdfContext);
    // We are done with our context now, so we release it
    CGContextRelease (pdfContext);

【问题讨论】:

【参考方案1】:

嘿伙计们,我准备了一些代码库,使用网上提供的示例从 UIScrollView 创建 PDF 我们应该清楚两件事

1) 页数 2) 内容大小 滚动视图

我创建了一个内容大小(10 * 910)的滚动视图。所以它有 10 页。。这是为 iPad 准备的。

这里是代码库

- (void) createPDF

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *directroyPath = nil;
    directroyPath = [documentsDirectory stringByAppendingPathComponent:@"PDF"];
    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:myScrollView.bounds path:(CFStringRef)filePath];
    NSLog(@"PDF Context created");

    for (int i = 0 ; i< 10 ; i++)
    

        // page 1
        CGContextBeginPage (pdfContext,nil); 

        //turn PDF upsidedown   
        CGAffineTransform transform = CGAffineTransformIdentity;    
        transform = CGAffineTransformMakeTranslation(0, (i+1) * 910);   
        transform = CGAffineTransformScale(transform, 1.0, -1.0);   
        CGContextConcatCTM(pdfContext, transform);  

        //Draw view into PDF
        [myScrollView.layer renderInContext:pdfContext];    
        CGContextEndPage (pdfContext);          
        [myScrollView setContentOffset:CGPointMake(0, (i+1) * 910) 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;

【讨论】:

嗨,Nikesh,我试用了您的代码,但我创建的 pdf 显然已损坏,因为预览和 Acrobat 都无法打开它……您有什么想法吗? @UrbanSeifert 您是否使用 .pdf 文件扩展名命名了您的 pdf 文件名? @Nikesh..感谢您的代码。它工作得很好,但是有一个问题,因为我的页面没有改变,而不是显示的控制器也坏了。例如。我在第2页,有一个按钮,在第1页显示一半,在第2页显示一半。有什么解决办法吗? @Abha 你得到解决方案了吗?【参考方案2】:

我想出了一个不同的解决方案:

-(NSData*)pdfDataFromTableViewContent
   NSMutableData *pdfData = [NSMutableData data];
   //The real size, not only the visible part
   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;

调整框架大小以适应 scrollView 的全部内容,在 graphicsContext 中捕获它,调整框架大小。

上面的代码生成一页。 对于更多页面,我基本上使用这个:

//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();

【讨论】:

【参考方案3】:

是否可以查看您的示例代码,我正在尝试做同样的事情。

你可以在这里发送源代码,谢谢你会非常慷慨 dott.marco@mac.com

无论如何,对于您的问题,这可能会有所帮助:

您捕获可见内容只是因为您的滚动视图的大小仅匹配可见内容,它应该是。在开始绘制代码之前,您需要调整滚动视图的大小以匹配您需要捕获的内容:

代码: self.scrollView.frame = CGRectMake(0, 0, "你的内容宽度", "你的内容高度"); 完成绘图后,请确保将滚动视图的大小调整为向后,在本例中为容器视图:

代码: self.scrollView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height);

【讨论】:

嗨,Marco,我尝试过执行您的逻辑,但它对我不起作用。

以上是关于从 UIScrollView + iphone 生成 PDF的主要内容,如果未能解决你的问题,请参考以下文章

iphone- UIScrollview 对角线滑动意外行为

UIScrollView 和约束的问题

(iphone) uiscrollview 触摸。取消内容触摸并开始滚动

iPhone - 知道UIScrollView是否达到顶部或底部

iPhone中的UIScrollView控制器[关闭]

iPhone + UIScrollView