在iOS中从UIWebView / UIView生成PDF的最佳方法

时间:2015-02-18 06:10:58

标签: ios objective-c iphone pdf uiwebview

在我的iOS应用程序中,我想从UIWebView / UIView(包括子视图)创建PDF。在我的应用程序中,我将首先在UIWebView中加载原始传入的PDF,然后在UIWebView上添加图像作为子视图。我想从UIWebview创建一个带有此图像(子视图)的PDF,原始清晰度并且没有数据丢失。

PS:渲染PDF中的图像应与UIWebView中的图像位于同一位置。

我可以从UIWebView创建PDF,但它缺乏PDF清晰度并且会产生边框问题。

任何人都可以为UIWebView(包括子视图)的PDF渲染提供清晰的解决方案吗?

已编辑内容

enter image description here

以上是UIWebView的屏幕截图。签名(测试)是子视图中的图像。我希望将其呈现为PDF,清晰且没有任何数据丢失。

在下面的答案中,UIPrintPageRenderer从UIWebView渲染PDF,但忽略了UIWebView上方的子视图。这是此选项的主要问题。

使用createPDFfromUIView方法的另一个答案缺乏原始的清晰度:

   -(void)createPDFfromUIView:(UIView*)aView saveToDocumentsWithFileName:(NSString*)aFilename;

此方法也会出现边框问题。

我还尝试使用this引用中的以下代码直接在PDF上编写,而不使用屏幕截图。

- (void) drawCustomPDFContent
{
    //  Put your drawing calls here
    //  Draw a red box
    [[UIColor redColor] set];
    UIRectFill(CGRectMake(20, 20, 100, 100));

    //  Example of drawing your view into PDF, note that this will be a rasterized bitmap, including the text.
    //  To get smoother text you'll need to use the NSString draw methods
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [view.layer renderInContext:ctx];
}

- (void) createCustomPDF
{
    NSURL* pdfURL = ... /* URL to pdf file */;
    CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfURL);

    const size_t numberOfPages = CGPDFDocumentGetNumberOfPages(pdf);

    NSMutableData* data = [NSMutableData data];
    UIGraphicsBeginPDFContextToData(data, CGRectZero, nil);

    for(size_t page = 1; page <= numberOfPages; page++)
    {
        //  Get the current page and page frame
        CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdf, page);
        const CGRect pageFrame = CGPDFPageGetBoxRect(pdfPage, kCGPDFMediaBox);

        UIGraphicsBeginPDFPageWithInfo(pageFrame, nil);

        //  Draw the page (flipped)
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextSaveGState(ctx);
        CGContextScaleCTM(ctx, 1, -1);
        CGContextTranslateCTM(ctx, 0, -pageFrame.size.height);
        CGContextDrawPDFPage(ctx, pdfPage);
        CGContextRestoreGState(ctx);

        if(page == 1)
        {
            [self drawCustomPDFContent];
        }
    }

    UIGraphicsEndPDFContext();

    CGPDFDocumentRelease(pdf);
    pdf = nil;

    //  Do something with data here
    [data writeToFile:... atomically:YES];
}

它完成了这项工作。但是,UIWebView中的(x,y)坐标与原始PDF坐标不同,因此我无法映射要在PDF上绘制的精确坐标以进行渲染。

希望这能解决我的问题。请建议一种方法来解决我的问题。 如果可能无法做到,请推荐符合我要求的iOS PDF套件/ SDK。

2 个答案:

答案 0 :(得分:2)

使用UIPrintPageRenderer中的UIWebView按照以下步骤操作:

添加Category UIPrintPageRenderer以获取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

为A4尺寸添加这些定义

#define kPaperSizeA4 CGSizeMake(595.2,841.8)

现在UIWebView's webViewDidFinishLoad delegate使用UIPrintPageRenderer的{​​{1}} property

UIWebView

答案 1 :(得分:0)

-(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];
 }