Проблемы Objective-C с UIWebView в PDF
У меня есть этот метод, который берет мой UIWebView и конвертировать в PDF, и он работает хорошо. Но когда я распечатываю этот PDF-файл или отправляю по электронной почте, он обрезается Это все равно, что генерировать только размер UIWebView, который я установил (это ширина: 688 и высота: 577). Если я увеличу размер UIWebView, скажем, 900 или 1024, мой PDF будет пустым. Мой UIWebView больше 577, но в моем приложении я могу прокрутить.
Вот метод....
-(void)webViewDidFinishLoad:(UIWebView *)webViewPDF
{
CGRect origframe = webViewPDF.frame;
NSString *heightStr = [webViewPDF stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"]; // Get the height of our webView
int height = [heightStr intValue];
CGFloat maxHeight = kDefaultPageHeight - 2*kMargin;
int pages = floor(height / maxHeight);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
self.pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"Purchase Order.pdf"]];
UIGraphicsBeginPDFContextToFile(self.pdfPath, CGRectZero, nil);
for (int i = 0; i < pages; i++)
{
if (maxHeight * (i+1) > height) {
CGRect f = [webViewPDF frame];
f.size.height -= (((i+1) * maxHeight) - height);
[webViewPDF setFrame: f];
}
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, kDefaultPageWidth, kDefaultPageHeight), nil);
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(currentContext, kMargin, kMargin);
[webViewPDF.layer renderInContext:currentContext];
}
UIGraphicsEndPDFContext();
[webViewPDF setFrame:origframe];
[[[webViewPDF subviews] lastObject] setContentOffset:CGPointMake(0, 0) animated:NO];
}
Я надеюсь, что это имеет смысл.... У кого-нибудь есть какие-либо предложения о том, как это исправить, чтобы PDF не обрезался?
Я забыл упомянуть эти переменные:
#define kDefaultPageHeight 850
#define kDefaultPageWidth 850
#define kMargin 50
Вот моя кнопка "Поделиться":
- (IBAction)Share:(id)sender {
NSData *pdfData = [NSData dataWithContentsOfFile:self.pdfPath];
UIActivityViewController * activityController = [[UIActivityViewController alloc] initWithActivityItems:@[pdfData] applicationActivities:nil];
UIPopoverController *popup = [[UIPopoverController alloc] initWithContentViewController:activityController];
[popup presentPopoverFromRect:CGRectMake(self.view.frame.size.width - 36, 60, 0, 0)inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
2 ответа
Я делал это в прошлом, используя UIPrintPageRenderer. Это более удобный способ создания PDF из UIWebView, и до сих пор он работал хорошо для меня. Я протестировал это решение с Xcode 6 и iOS 8.2. Также попробовал распечатать полученный PDF и все распечаталось нормально.
Когда я прочитал OP, я провел некоторое тестирование с различными размерами страниц, чтобы посмотреть, смогу ли я получить чистый PDF. Есть несколько ключевых моментов, которые я определила, и которые могли бы внести свой вклад в пустой файл PDF. Я идентифицировал их в коде.
Когда вызывается webViewDidFinishLoad(), представление может быть не загружено на 100%. Необходима проверка, чтобы увидеть, загружается ли представление. Это важно, так как это может быть источником вашей проблемы. Если это не так, то нам пора. Здесь есть очень важное замечание. Некоторые веб-страницы загружаются динамически (определяется в самой странице). Взять хотя бы youtube.com. Страница отображается почти сразу, с экраном "загрузки". Это обманет наше веб-представление, и его свойство isLoading будет установлено в значение "false", в то время как веб-страница все еще загружает контент динамически. Это довольно редкий случай, и в общем случае это решение будет работать хорошо. Если вам нужно сгенерировать файл PDF из такой динамически загружаемой веб-страницы, вам может потребоваться переместить фактическую генерацию в другое место. Даже при динамической загрузке веб-страницы вы получите PDF-файл с экраном загрузки, а не пустой PDF-файл.
Другим ключевым аспектом является установка printableRect и pageRect. Обратите внимание, что они устанавливаются отдельно. Если printableRect меньше, чем paperRect, у вас получится заполнение содержимого - см., Например, код. Вот ссылка на документ API Apple с кратким описанием обоих.
Приведенный ниже пример кода добавляет категорию в UIPrintPageRenderer для создания фактических данных PDF. Код в этом примере был составлен с использованием различных онлайн-ресурсов в прошлом, и я не смог найти, какие из них были использованы для правильного зачисления.
@interface UIPrintPageRenderer (PDF)
- (NSData*) createPDF;
@end
@implementation UIPrintPageRenderer (PDF)
- (NSData*) createPDF
{
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
И вот что у меня есть в webViewDidFinishLoad()
- (void)webViewDidFinishLoad:(UIWebView *)webViewIn {
NSLog(@"web view did finish loading");
// webViewDidFinishLoad() could get called multiple times before
// the page is 100% loaded. That's why we check if the page is still loading
if (webViewIn.isLoading)
return;
UIPrintPageRenderer *render = [[UIPrintPageRenderer alloc] init];
[render addPrintFormatter:webViewIn.viewPrintFormatter startingAtPageAtIndex:0];
// Padding is desirable, but optional
float padding = 10.0f;
// Define the printableRect and paperRect
// If the printableRect defines the printable area of the page
CGRect paperRect = CGRectMake(0, 0, PDFSize.width, PDFSize.height);
CGRect printableRect = CGRectMake(padding, padding, PDFSize.width-(padding * 2), PDFSize.height-(padding * 2));
[render setValue:[NSValue valueWithCGRect:paperRect] forKey:@"paperRect"];
[render setValue:[NSValue valueWithCGRect:printableRect] forKey:@"printableRect"];
// Call the printToPDF helper method that will do the actual PDF creation using values set above
NSData *pdfData = [render createPDF];
// Save the PDF to a file, if creating one is successful
if (pdfData) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
NSString *pdfPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"Purchase Order.pdf"]];
[pdfData writeToFile:pdfPath atomically:YES];
}
else
{
NSLog(@"error creating PDF");
}
}
PDFSize определяется как константа со стандартным размером страницы A4. Его можно редактировать в соответствии с вашими потребностями.
#define PDFSize CGSizeMake(595.2,841.8)
Чтобы создать PDF-файл в памяти, вам нужно нарисовать слой UIWebBrowserView
экземпляр, который лежит под UIWebView
"s scrollView
, Чтобы сделать это, попробуйте изменить renderInContext:
позвоните следующим образом:
UIView* contentView = webViewPDF.scrollView.subviews.firstObject;
[contentView.layer renderInContext:currentContext];
Кроме того, если вы нацелены на iOS >= 7.0, тогда вы можете избежать использования renderInContext:
и использовать один из snapshotViewAfterScreenUpdates:
или же drawViewHierarchyInRect:afterScreenUpdates:
методы.