【问题标题】:Best way to generate PDF from UIWebView/UIView in iOS [duplicate]在 iOS 中从 UIWebView/UIView 生成 PDF 的最佳方法 [重复]
【发布时间】:2015-04-19 01:42:30
【问题描述】:

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

PS:呈现的 PDF 中的图像应与 UIWebView 中的位置相同。

我能够从 UIWebView 创建 PDF,但它缺乏 PDF 清晰度并产生边框问题。

任何人都可以为从 UIWebView(包括子视图)呈现 PDF 提供一个清晰的解决方案吗?

编辑内容

以上是 UIWebView 的截图。 Signature(test) 是子视图中的图像。我想将其呈现为清晰的 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 kit/SDK。

【问题讨论】:

  • 任何建议,请发表您的答案。
  • @Daij-Djan 在 UIWebView 上方手动添加子视图。
  • 你应该解释一下你所说的“边界问题”是什么意思

标签: ios objective-c iphone pdf uiwebview


【解决方案1】:

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

添加CategoryUIPrintPageRenderer 以获取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 propertyUIWebView

- (void)webViewDidFinishLoad:(UIWebView *)awebView
{
  if (awebView.isLoading)
    return;

  UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
  [render addPrintFormatter:awebView.viewPrintFormatter startingAtPageAtIndex:0];
  //increase these values according to your requirement
  float topPadding = 10.0f;
  float bottomPadding = 10.0f;
  float leftPadding = 10.0f;
  float rightPadding = 10.0f;
  CGRect printableRect = CGRectMake(leftPadding,
                                  topPadding,
                                  kPaperSizeA4.width-leftPadding-rightPadding,
                                  kPaperSizeA4.height-topPadding-bottomPadding);
  CGRect paperRect = CGRectMake(0, 0, kPaperSizeA4.width, kPaperSizeA4.height);
  [render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"];
  [render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"];
  NSData *pdfData = [render printToPDF];
  if (pdfData) {
    [pdfData writeToFile:[NSString stringWithFormat:@"%@/tmp.pdf",NSTemporaryDirectory()] atomically: YES];
  }
  else
  {
    NSLog(@"PDF couldnot be created");
  }
}

【讨论】:

  • 是的。我之前试过你的代码。它从 UIWebView 渲染 PDF。但我不包括 UIWebView 上面的子视图。我在上面的代码中遇到了这个问题。只需在 awebView.Scrollview 添加一个子视图。然后使用上面的代码渲染 pdf。它只会渲染 UIWebView(不包括子视图)
  • @prince UIPrintPageRenderer 将接受并处理子视图?
  • 只有 UIWebView 而不是它的子视图....
  • 太棒了!非常感谢!
  • 这是横向渲染,还是纵向渲染?
【解决方案2】:
-(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];
 }

【讨论】:

  • 谢谢。已经尝试过这种方法。此渲染代码会出现数据丢失和边框问题。
猜你喜欢
  • 1970-01-01
  • 2013-09-05
  • 2016-07-29
  • 1970-01-01
  • 2020-07-17
  • 2012-09-15
  • 2013-11-26
  • 2011-04-20
  • 1970-01-01
相关资源
最近更新 更多