Использование встроенного в память UIWebView для создания PDF в PhoneGap - PullRequest
4 голосов
/ 07 февраля 2012

Я пытаюсь понять, как это сделать.

ПРИМЕЧАНИЕ: я не опытный разработчик объективных программ (поэтому я в первую очередь использую PhoneGap)

Короче говоря : Мой UIWebView (нет, не PhoneGap, который отображает веб-приложение, а второй UIWebView, созданный в памяти и не видимый), не отображается в PDF.Я просто получаю пустой PDF.Я опубликую некоторые из моих мыслей и кода, и, надеюсь, кто-то узнает, что я делаю не так.


Я начну с того, что здесь уже есть плагин для печати PhoneGap:

https://github.com/phonegap/phonegap-plugins/tree/master/iPhone/PrintPlugin

Этот плагин создает UIWebView на лету, передает ему некоторый HTML-код через JavaScript, а затем вызывает некоторый контроллер печати для печати. ​​

Поэтому я позаимствовал некоторые идеи из этого.Затем я обратил внимание на этот замечательный пост в блоге о создании PDF

http://www.ioslearner.com/convert-html-uiwebview-pdf-iphone-ipad/

Так что я пытаюсь объединить их в свой собственный плагин PhoneGap для получения некоторого HTML (из моего веб-приложения) и генерацииPDF-файл на лету.

HEADER:

#import <Foundation/Foundation.h>
#import <QuartzCore/QuartzCore.h>

#ifdef PHONEGAP_FRAMEWORK
#import <PhoneGap/PGPlugin.h>
#else
#import "PGPlugin.h"
#endif


@interface ExportPlugin : PGPlugin <UIWebViewDelegate> {
    NSString* exportHTML;
}

@property (nonatomic, copy) NSString* exportHTML;

//This gets called from my HTML5 app (Javascript):
- (void) exportPdf:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options;

@end

MAIN:

#import "ExportPlugin.h"

@interface ExportPlugin (Private)
-(void) doExport;
-(void) drawPdf;
@end

@implementation ExportPlugin

@synthesize exportHTML;

- (void) exportPdf:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options{
    NSUInteger argc = [arguments count];

    if (argc < 1) {
        return; 
    }
    self.exportHTML = [arguments objectAtIndex:0];

    [self doExport];
}

int imageName = 0;
double webViewHeight = 0.0;

- (void) doExport{
    //Set the base URL to be the www directory.
    NSString *dbFilePath = [[NSBundle mainBundle] pathForResource:@"www" ofType:nil ];
    NSURL *baseURL = [NSURL fileURLWithPath:dbFilePath];

    //Load custom html into a webview 
    UIWebView *webViewExport = [[UIWebView alloc] init];
    webViewExport.delegate = self;
    //[webViewExport loadHTMLString:exportHTML baseURL:baseURL];
    [webViewExport loadHTMLString:@"<html><body><h1>testing</h1></body></html>" baseURL:baseURL];
}

- (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    return YES;
}

- (void)webViewDidFinishLoad:(UIWebView *)webViewExport
{        
    webViewHeight = [[webViewExport stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"] integerValue];

    CGRect screenRect = webViewExport.frame;

    //WHY DO I HAVE TO SET THE SIZE? OTHERWISE IT IS 0
    screenRect.size.width = 768;
    screenRect.size.height = 1024;

    double currentWebViewHeight = webViewHeight;
    while (currentWebViewHeight > 0)
    {
        imageName ++;

        UIGraphicsBeginImageContext(screenRect.size);
        CGContextRef ctx = UIGraphicsGetCurrentContext();

        //[[UIColor blackColor] set];
        //CGContextFillRect(ctx, screenRect);

        [webViewExport.layer renderInContext:ctx];

        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *pngPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.png",imageName]];

        if(currentWebViewHeight < 960)
        {
            CGRect lastImageRect = CGRectMake(0, 960 - currentWebViewHeight, webViewExport.frame.size.width, currentWebViewHeight);
            CGImageRef imageRef = CGImageCreateWithImageInRect([newImage CGImage], lastImageRect);    

            newImage = [UIImage imageWithCGImage:imageRef];
            CGImageRelease(imageRef);
        }
        [UIImagePNGRepresentation(newImage) writeToFile:pngPath atomically:YES];

        [webViewExport stringByEvaluatingJavaScriptFromString:@"window.scrollBy(0,960);"];

        currentWebViewHeight -= 960;
    }

    [self drawPdf];
}

- (void) drawPdf
{
    CGSize pageSize = CGSizeMake(612, webViewHeight);
    NSString *fileName = @"Demo.pdf";
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *pdfFileName = [documentsDirectory stringByAppendingPathComponent:fileName];

    UIGraphicsBeginPDFContextToFile(pdfFileName, CGRectZero, nil);

    // Mark the beginning of a new page.
    UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, pageSize.width, pageSize.height), nil);

    double currentHeight = 0.0;
    for (int index = 1; index  <= imageName ; index++)
    {
        NSString *pngPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%d.png", index]];
        UIImage *pngImage = [UIImage imageWithContentsOfFile:pngPath];

        [pngImage drawInRect:CGRectMake(0, currentHeight, pageSize.width, pngImage.size.height)];
        currentHeight += pngImage.size.height;
    }

    UIGraphicsEndPDFContext();
}

@end

Первое указание, что-то не так, выше, я должен установитьразмер UIWebView.frame:

screenRect.size.width = 768;
screenRect.size.height = 1024;

Но почему?PhoneGap PrintPlugin не должен делать это.Если я не установлю его, размер будет 0, а затем я получаю много контекстных ошибок.

И тогда следующая проблема заключается в том, что UIWebView ничего не рендерит.Возможно, симптом первой проблемы?

Как мне отладить эту проблему и выяснить, в чем проблема?


ОБНОВЛЕНИЕ

Я почти уверен, что может быть невозможно отобразить слой UIWebView в контекст изображения, если только этот UIWebView фактически не виден.

Я не уверен, как тогда работает PhoneGap PrintPlugin.Похоже, что это делает его UIWebView вполне нормальным, так как его не видно.

В настоящее время я экспериментирую с рендерингом реального PhoneGap UIWebView в PDF (в отличие от моего собственного UIWebView).Но это не идеально.

  • Это означает, что мне нужно скрыть все панели инструментов и еще много чего, а затем панорамировать UIWebView вокруг, чтобы я захватывал все, что находится вне области просмотра.Это не идеально, потому что пользователь визуально увидит это!

  • Точка 1 выше, похоже, не работает в любом случае, потому что iPad слишком медленно обновляет экран при динамическом переключении срасположение.На iPad, если вы делаете визуальные вещи очень быстро (например, панорамирование экрана), iPad слишком медленный и просто не показывает его.В итоге вы видите только конечное состояние.Поэтому, когда я делаю скриншоты, экран визуально не панорамируется (даже если DOM говорит, что это так).(Надеюсь, что это имеет смысл).

Ах, расстраивает.

Ответы [ 3 ]

1 голос
/ 13 февраля 2012

Сейчас у меня есть рабочее решение, но оно не идеальное.

То, что я делаю, это рендеринг телефонного промежутка UIWebView в PDF.

Сделать это довольно сложно.У меня есть пара функций target-c

- (void) takeScreenshot;

- (void) renderPdf;

, которые я вызываю из Javascript.

Затем я должен написать рекурсивный алгоритм JS, который перемещается по экрану во всех направлениях при вызове takeScreenshot.

Между вызовами на takeScreenshot я использую setTimeout, что дает 20-миллисекундный перерыв в обработке JS - у iPad достаточно времени для обновления экрана, чтобы можно было сделать следующий снимок экрана.

Это была королевская боль в заднице.Баунти по-прежнему открыт на тот случай, если кто-то знает, как лучше с этим справиться - мне было бы очень интересно узнать!

0 голосов
/ 16 февраля 2012

Если вы хотите визуализировать UIWebView в PDF, я думаю, вы могли бы пойти на это:

1 / использовать метод convertRect: fromView, реализованный вашим объектом UIWebView, чтобы получить CGRect

2 / см. Справочник классов UIPrintPageRenderer , чтобы сделать предварительный просмотр печати

3 / Используйте UIGraphicsGetCurrentContext, чтобы извлечь из него CGContextRef

4 / создать PDF изCGRect и CGContextRef (вы можете использовать справку, предоставленную в Apple образец кода zoomPDFViewer для построения PDF с использованием CGPdf

0 голосов
/ 15 февраля 2012

Вот как для рендеринга PDF в UIWebView (webPage является вашим UIWebView), ваш делегат (здесь «сам») может реализовать протокол UIWebViewDelegate:

- (void)loadingPDFwithURL:(NSURL *)anURL {
    CGRect appFrame = [[UIScreen mainScreen] applicationFrame];
    appFrame.origin.y = 0;
    [self.webPage initWithFrame:appFrame];
    [self.webPage setScalesPageToFit:YES];
    [self.webPage setDelegate:self];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:anURL];
    [self.webPage loadRequest:requestObj];
    [self.view addSubview:self.webPage];
}

Итак, вы даете URL-адрес PDF-файла (если он находится в памяти, просто напишите файл в приложении, поскольку URL-адрес может быть путем к файлу).

Другая возможность - погрузиться в CGPdf, но это становится все труднее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...