Извлечение одной страницы (или диапазона страниц) из данных PDF без загрузки всего PDF (иногда это занимает слишком много ОЗУ) - PullRequest
0 голосов
/ 01 сентября 2018

Используя PDFKit в swift, вы можете использовать PDFDocument для открытия PDF-файлов. Это легко и хорошо работает. Но я создаю пользовательский просмотрщик PDF (для PDF-книг комиксов), который соответствует моим потребностям, и у меня есть одна проблема. В программе просмотра мне не нужно иметь весь файл PDF в памяти. Мне нужно всего лишь несколько страниц за раз.

Кроме того, PDF-файлы состоят только из изображений. Там нет текста или что-нибудь.

При создании экземпляра PDFDocument все данные PDF загружаются в память. Если у вас действительно огромные PDF-файлы (более 1 ГБ), это не оптимально (и может привести к сбою на некоторых устройствах). Насколько я знаю, в PDFKit нет способа загружать только части документа PDF.

Что я могу с этим поделать? Я не нашел библиотеки swift / obj-c, которая могла бы сделать это (хотя я не знаю, какие ключевые слова нужны для ее поиска).

Мой обходной путь - предварительная обработка PDF-файлов и сохранение каждой страницы в виде изображения в директории .documents (или аналогичной) с использованием FileManager. Это приведет к огромному количеству файлов, но решит проблему с памятью. Я не уверен, что мне нравится такой подход.

Обновление:

Итак, я сделал то, что предложили @Prcela и @Sahil Manchanda. Кажется, сейчас работает.

@ yms: Хм, это действительно может быть проблемой. Это даже случается, когда есть только изображения? Без чего-либо еще в PDF.

@ Carpsen90: они локальны (сохраняются в каталоге документов).

РЕДАКТИРОВАТЬ: Я не принял ответ ниже, или дал ему награду. Это было автоматически. Это не решает проблему. Он по-прежнему загружает весь PDF в память!

1 Ответ

0 голосов
/ 15 сентября 2018

У меня есть идея, как этого добиться в PDFKit. После прочтения документации есть функция, которая позволяет выбирать определенные страницы. Что, вероятно, решит вашу проблему, если вы добавите ее в collectionFlowView.

func selection(from startPage: PDFPage, atCharacterIndex startCharacter: Int, to endPage: PDFPage, atCharacterIndex endCharacter: Int) -> PDFSelection?

Однако, как я прочитал, что у вас в основном есть изображения, есть еще одна функция, которая позволяет извлекать части PDF-файла на основе CGPoints:

func selection(from startPage: PDFPage, at startPoint: CGPoint, to endPage: PDFPage, at endPoint: CGPoint) -> PDFSelection?

Также взгляните на это: https://developer.apple.com/documentation/pdfkit/pdfview

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

Я также подготовил небольшой код для извлечения одной страницы ниже. Надеюсь, это поможет.

import PDFKit
import UIKit

class PDFViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let url = Bundle.main.url(forResource: "myPDF", withExtension: "pdf") else {fatalError("INVALID URL")}
        let pdf = PDFDocument(url: url)
        let page = pdf?.page(at: 10) // returns a PDFPage instance
        // now you have one page extracted and you can play around with it.
    }
}

РЕДАКТИРОВАТЬ 1: Посмотрите на это извлечение кода. Я понимаю, что весь PDF-файл загружается, однако этот подход может быть более эффективным с точки зрения памяти, так как, возможно, iOS справится с этим лучше в PDFView:

func readBook() {

if let oldBookView = self.view.viewWithTag(3) {
    oldBookView.removeFromSuperview()
    // This removes the old book view when the user chooses a new book language
}

if #available(iOS 11.0, *) {
    let pdfView: PDFView = PDFView()
    let path = BookManager.getBookPath(bookLanguageCode: book.bookLanguageCode)
    let url = URL(fileURLWithPath: path)
    if let pdfDocument = PDFDocument(url: url) {
        pdfView.displayMode = .singlePageContinuous
        pdfView.autoScales = true
        pdfView.document = pdfDocument
        pdfView.tag = 3 // I assigned a tag to this view so that later on I can easily find and remove it when the user chooses a new book language
        let lastReadPage = getLastReadPage()

        if let page = pdfDocument.page(at: lastReadPage) {
            pdfView.go(to: page)
            // Subscribe to notifications so the last read page can be saved
            // Must subscribe after displaying the last read page or else, the first page will be displayed instead
            NotificationCenter.default.addObserver(self, selector: #selector(self.saveLastReadPage),name: .PDFViewPageChanged, object: nil)
        }
    }

    self.containerView.addSubview(pdfView)
    setConstraints(view: pdfView)
    addTapGesture(view: pdfView)
}

РЕДАКТИРОВАТЬ 2: это не тот ответ, который искал ОП. Это также загружает весь PDF в память. Читать комментарии

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