Recentemente, houve muitas perguntas sobre o desenho de PDFs.
Sim, você pode renderizar PDF facilmente com um UIWebView
, mas isso não dá o desempenho e a funcionalidade que você esperaria de um bom visualizador PDF.
Você pode desenhar uma página PDF para um CALayer ou para um UIImage . Apple ainda tem código de exemplo para mostrar como desenhar um grande PDF em um UIScrollview do Zoomable
Mas os mesmos problemas continuam surgindo.
Método UIImage:
UIImage
não são escalados opticamente, assim como a abordagem Layer.UIImages
a partir de um limite PDFcontext
/evitam usá-lo para criar uma renderização em tempo real de novos níveis de zoom.Método CATiledLayer:
CALayer
: blocos individuais podem ser vistos renderizados (mesmo com um tileSize Tweak)CALayers
não pode ser preparado antes do tempo (renderizado fora da tela).Geralmente, os visualizadores PDF também são muito pesados na memória. Até mesmo monitore o uso de memória do exemplo de zoom da Apple PDF.
No meu projeto atual, estou desenvolvendo um visualizador PDF e estou processando um UIImage
de uma página em um thread separado (problemas aqui também!) E apresentando-o enquanto a escala é x1. O processamento de CATiledLayer
entra em ação assim que a escala é> 1. O iBooks adota uma abordagem dupla semelhante, como se você rolasse as páginas e pudesse ver uma versão de baixa resolução da página por menos de um segundo antes de uma versão nítida aparecer.
Im renderizando 2 páginas em cada lado da página em foco para que a imagem PDF esteja pronta para mascarar a camada antes de começar a desenhar. As páginas são destruídas novamente quando estão a +2 páginas da página em foco.
Alguém tem algum insight, não importa quão pequeno ou óbvio para melhorar o desempenho/manuseio de memória do Drawing PDF's? ou quaisquer outras questões discutidas aqui?
EDIT: Algumas Dicas (Crédito: Luke Mcneice, VdesmedT, Matt Gallagher, Johann):
Salve qualquer mídia no disco quando puder.
Use tilesSizes maiores se renderizando em TiledLayers
iniciar matrizes freqüentemente usadas com objetos de espaço reservado, alternativamente outra abordagem de design é este
Observe que as imagens serão renderizadas mais rapidamente que um CGPDFPageRef
Use NSOperations
ou GCD & Blocks para preparar as páginas antes do tempo.
chame CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);
antes de CGContextDrawPDFPage
para reduzir o uso de memória ao desenhar
iniciar seu NSOperations
com um docRef é uma má idéia (memória), coloque o docRef em um singleton.
Cancelar desnecessário NSOperations
Quando você puder, especialmente se eles estiverem usando memória, tenha cuidado para deixar contextos abertos!
Reciclar objetos de página e destruir vistas não utilizadas
Feche todos os contextos abertos assim que você não precisar deles
ao receber avisos de memória, libere e recarregue o DocRef e qualquer página Caches
Outros recursos PDF:
Obtendo Links dentro de um PDF (e aqui e aqui )
Obtendo o alvo do link (Obtendo o número da página do array /Dest
)
Obtendo texto bruto (e aqui e aqui e aqui (posicionamento focado))
Pesquisando (e aqui ) (não funciona com todos os PDFs (alguns apenas mostram caracteres estranhos, eu acho que é um problema de codificação, mas não tenho certeza) -Credit BrainFeeder )
CALayer e Renderização Fora da Tela - renderiza a próxima página para exibição rápida/suave
Documentação
Projetos de exemplo
UIScrollView
, CATiledLayer
UIScrollView
, CATiledView
Eu construí esse tipo de aplicativo usando aproximadamente a mesma abordagem, exceto:
UIImage
mas em vez disso, desenho a imagem na camada quando o zoom é 1. Esses blocos serão liberados automaticamente quando os avisos de memória forem emitidos.Sempre que o usuário começar a aplicar zoom, eu adquiro o CGPDFPage
e o renderizo usando o CTM apropriado. O código em - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context
é como:
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);
}
}
issue é o objeto que contém o CGPDFDocumentRef
. Eu sincronizo a parte onde eu acesso a propriedade pdfDoc
porque eu libero-o e recrio-o ao receber memoryWarnings. Parece que o objeto CGPDFDocumentRef
faz algum cache interno que eu não encontrei como me livrar.
Para um visualizador PDFsimples e eficaz, quando você precisa de apenas uma funcionalidade limitada, agora você pode (iOS 4.0+) usar a estrutura do QuickLook:
Primeiro, você precisa vincular QuickLook.framework
e #import <QuickLook/QuickLook.h>;
Depois, em viewDidLoad
ou em qualquer um dos métodos de inicialização lenta:
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];
Desde iOS 11 , você pode usar o framework nativo chamado PDFKit para exibir e manipulando PDFs.
Depois de importar o PDFKit, você deve inicializar um PDFView
com um URL local ou remoto e exibi-lo na sua visualização.
if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") {
let pdfView = PDFView(frame: view.frame)
pdfView.document = PDFDocument(url: url)
view.addSubview(pdfView)
}
Leia mais sobre o PDFKit na Apple documentação do desenvolvedor.