Fast and Lean PDF Viewer для iPhone / iPad / iOs - советы и подсказки?
в последнее время было много вопросов о рисовании PDF-файлов.
Да, вы можете сделать PDF очень легко с UIWebView
но это не может дать производительность и функциональные возможности, которые вы ожидаете от хорошего просмотра PDF.
вы можете нарисовать страницу PDF к CALayer или к UIImage. Apple даже есть пример кода, чтобы показать, как рисовать большой PDF в масштабируемом UIScrollview
но те же проблемы продолжают обрезать вверх.
UIImage Метод:
- PDF в A
UIImage
не оптически масштабирование, а также подход слоя. - процессор и память попали на генерацию
элемент
UIImages
СPDFcontext
ограничивает/запрещает использовать его для создания рендеринг новых уровней масштабирования в реальном времени.
Метод CATiledLayer:
- Theres значительные накладные расходы (время)
рисование полной страницы PDF в
CALayer
: индивидуальные плитки можно увидеть рендеринга (даже с tileSize твик) -
CALayers
не могу быть готовым заранее время (отображается за пределами экрана).
как правило, PDF-зрители тоже довольно тяжелы по памяти. Даже контролировать использование памяти пример зумирования от Apple в формате PDF.
в моем текущем проекте, я разрабатываю PDF viewer и рендеринга UIImage
страницы в отдельном потоке (вопросы здесь тоже!) и представляя его в то время как масштаб x1. CATiledLayer
рендеринг срабатывает, как только масштаб >1. iBooks использует аналогичный подход double take, как если бы вы прокручивали страницы, вы можете увидеть более низкую версию страницы менее чем за секунду до появления четкой версии.
Im рендеринг 2 страницы с каждой стороны страницы в фокусе, так что PDF-изображение готово, чтобы замаскировать слой, прежде чем он начнет рисовать.Страницы снова уничтожаются, когда они находятся на расстоянии +2 страницы от сфокусированной страницы.
есть ли у кого-нибудь идеи, независимо от того насколько мала или очевидным, чтобы улучшить производительность/ управление памятью чертежа в формате PDF? или любые другие вопросы, обсуждаемые здесь?
EDIT: Некоторые Советы (Кредит-Люк Макнейс, Вдесмедт, Мэтт Галлахер, Иоганн):
сохранить любой носитель на диск, когда вы можете.
используйте большие размеры плитки, если рендеринг на TiledLayers
init часто используемые массивы с заполнителем объекты, альтернативно другой подход к дизайну этот
обратите внимание, что изображения будут отображаться быстрее, чем
CGPDFPageRef
использовать
NSOperations
или GCD & блоки для подготовки страниц вперед времени.вызов
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);
доCGContextDrawPDFPage
чтобы уменьшить использование памяти при рисованииинит оснащение вашей
NSOperations
С docRef это плохая идея (память), оберните docRef в синглтон.отменить излишне
NSOperations
когда вы можете, особенно если они будут использовать память, не оставляй контекстах открыт!утилизация объектов страницы и уничтожение неиспользуемых представлений
закройте все открытые контексты, как только они вам не нужны
при получении предупреждений памяти отпустите и перезагрузите DocRef и любую страницу Тайники
другие функции PDF:
-
получение ссылок внутри PDF (а здесь и здесь)
понимание PDF Rect для позиционирования ссылок
преобразование PDF annot datestrings
получение цели ссылки (получение номера страницы из
/Dest
массив)
получение оглавления
заголовок документа и ключевые слова
получение необработанного текста (и здесь, и здесь, и здесь (позиционирование сфокусировано))
Поиск(и здесь) (не работает со всеми PDF-файлами (некоторые просто показывают странные символы, я думаю, что это проблема с кодировкой, но я не уверен) - кредит BrainFeeder)
CALayer и закадровый рендеринг-рендеринг следующей страницы для быстрого / плавного отображения
документация
- Quartz PDFObjects (используется для мета-информации, аннотаций, больших пальцев)
- Abobe PDF Spec
примеры проектов
-
Apple / ZoomingPDF - масштабирование,
UIScrollView
,CATiledLayer
-
vfr / reader - масштабирование, листание,
UIScrollView
,CATiledView
- чела/ листья - пейджинг с хорошими переходами
- / skim - все, что кажется (PDF reader / editor для OSX)
4 ответа:
Я построил такое приложение, используя примерно тот же подход, за исключением :
- я кэширую сгенерированное изображение на диске и всегда генерирую два-три изображения заранее в отдельном потоке.
- Я не накладываю с
UIImage
но вместо этого нарисуйте изображение в слое, когда масштабирование равно 1. Эти плитки будут освобождены автоматически, когда выдаются предупреждения памяти.всякий раз, когда пользователь начинает масштабирование, я получаю
CGPDFPage
и визуализировать его с помощью соответствующего CTM. Код в- (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context
как :CGAffineTransform currentCTM = CGContextGetCTM(context); if (currentCTM.a == 1.0 && baseImage) { //Calculate ideal scale CGFloat scaleForWidth = baseImage.size.width/self.bounds.size.width; CGFloat scaleForHeight = baseImage.size.height/self.bounds.size.height; CGFloat imageScaleFactor = MAX(scaleForWidth, scaleForHeight); CGSize imageSize = CGSizeMake(baseImage.size.width/imageScaleFactor, baseImage.size.height/imageScaleFactor); CGRect imageRect = CGRectMake((self.bounds.size.width-imageSize.width)/2, (self.bounds.size.height-imageSize.height)/2, imageSize.width, imageSize.height); CGContextDrawImage(context, imageRect, [baseImage CGImage]); } else { @synchronized(issue) { CGPDFPageRef pdfPage = CGPDFDocumentGetPage(issue.pdfDoc, pageIndex+1); pdfToPageTransform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, layer.bounds, 0, true); CGContextConcatCTM(context, pdfToPageTransform); CGContextDrawPDFPage(context, pdfPage); } }
проблема-это объект, содержащий
CGPDFDocumentRef
. Я синхронизирую часть, где я получаю доступ кpdfDoc
свойство, потому что я освобождаю его и воссоздаю его при получении memoryWarnings. Кажется, чтоCGPDFDocumentRef
объект делает некоторое внутреннее кэширование, которое я не нашел, как избавиться.
для простого и эффективного просмотра PDF, когда вам требуется только ограниченная функциональность, теперь вы можете (iOS 4.0+) использовать QuickLook framework:
во-первых, вам нужно связать против
QuickLook.framework
и#import <QuickLook/QuickLook.h>;
затем в
viewDidLoad
или любой из ленивых способов инициализации:QLPreviewController *previewController = [[QLPreviewController alloc] init]; previewController.dataSource = self; previewController.delegate = self; previewController.currentPreviewItemIndex = indexPath.row; [self presentModalViewController:previewController animated:YES]; [previewController release];
С iOS 11, вы можете использовать собственный фреймворк под названием PDFKit для отображения и управления PDF-файлами.
после импорта PDFKit, вы должны инициализировать
PDFView
с локальным или удаленным URL и отображать его в вашем представлении.if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") { let pdfView = PDFView(frame: view.frame) pdfView.document = PDFDocument(url: url) view.addSubview(pdfView) }
подробнее о PDFKit читайте в документации разработчика Apple.
CGAffineTransform currentCTM = CGContextGetCTM(context); if (currentCTM.a == 1.0 && baseImage) { //Calculate ideal scale CGFloat scaleForWidth = baseImage.size.width/self.bounds.size.width; CGFloat scaleForHeight = baseImage.size.height/self.bounds.size.height; CGFloat imageScaleFactor = MAX(scaleForWidth, scaleForHeight); CGSize imageSize = CGSizeMake(baseImage.size.width/imageScaleFactor, baseImage.size.height/imageScaleFactor); CGRect imageRect = CGRectMake((self.bounds.size.width-imageSize.width)/2, (self.bounds.size.height-imageSize.height)/2, imageSize.width, imageSize.height); CGContextDrawImage(context, imageRect, [baseImage CGImage]); } else { @synchronized(issue) { CGPDFPageRef pdfPage = CGPDFDocumentGetPage(issue.pdfDoc, pageIndex+1); pdfToPageTransform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, layer.bounds, 0, true); CGContextConcatCTM(context, pdfToPageTransform); CGContextDrawPDFPage(context, pdfPage); } }