How can I parse content from a PDF page with Swift

时间:2022-02-18 00:39:59

The documentation is not really clear to me. So far I reckon I need to set up a CGPDFOperatorTable and then create a CGPDFContentStreamCreateWithPage and CGPDFScannerCreate per PDF page.

文档对我来说并不是很清楚。到目前为止,我认为我需要设置一个CGPDFOperatorTable,然后为每个PDF页面创建一个CGPDFContentStreamCreateWithPage和CGPDFScannerCreate。

The documentation refers to setting up Callbacks, but it's unclear to me how. How to actually obtain the content from a page?

文档是指设置回调,但我不清楚如何。如何从页面实际获取内容?

This is my code so far.

到目前为止这是我的代码。

    let pdfURL = NSBundle.mainBundle().URLForResource("titleofdocument", withExtension: "pdf")

    // Create pdf document
    let pdfDoc = CGPDFDocumentCreateWithURL(pdfURL)

    // Nr of pages in this PF
    let numberOfPages = CGPDFDocumentGetNumberOfPages(pdfDoc) as Int

    if numberOfPages <= 0 {
        // The number of pages is zero
        return
    }

    let myTable = CGPDFOperatorTableCreate()

    // lets go through every page
    for pageNr in 1...numberOfPages {

        let thisPage = CGPDFDocumentGetPage(pdfDoc, pageNr)
        let myContentStream = CGPDFContentStreamCreateWithPage(thisPage)
        let myScanner = CGPDFScannerCreate(myContentStream, myTable, nil)

        CGPDFScannerScan(myScanner)

        // Search for Content here?
        // ??

        CGPDFScannerRelease(myScanner)
        CGPDFContentStreamRelease(myContentStream)

    }

    // Release Table
    CGPDFOperatorTableRelease(myTable)

It's a similar question to: PDF Parsing with SWIFT but has no answers yet.

这是一个类似的问题:PDF解析SWIFT但尚无答案。

3 个解决方案

#1


4  

Here is an example of the callbacks implemented in Swift:

以下是Swift中实现的回调示例:

    let operatorTableRef = CGPDFOperatorTableCreate()

    CGPDFOperatorTableSetCallback(operatorTableRef, "BT") { (scanner, info) in
        print("Begin text object")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "ET") { (scanner, info) in
        print("End text object")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "Tf") { (scanner, info) in
        print("Select font")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "Tj") { (scanner, info) in
        print("Show text")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "TJ") { (scanner, info) in
        print("Show text, allowing individual glyph positioning")
    }

    let numPages = CGPDFDocumentGetNumberOfPages(pdfDocument)
    for pageNum in 1...numPages {
        let page = CGPDFDocumentGetPage(pdfDocument, pageNum)
        let stream = CGPDFContentStreamCreateWithPage(page)
        let scanner = CGPDFScannerCreate(stream, operatorTableRef, nil)
        CGPDFScannerScan(scanner)
        CGPDFScannerRelease(scanner)
        CGPDFContentStreamRelease(stream)
    }

#2


1  

You've actually specified exactly how to do it, all you need to do is put it together and try until it works.

您实际上已经确切地指定了如何操作,您需要做的就是将它放在一起并尝试直到它工作。

First of all, you need to setup a a table with callbacks as you state yourself in the beginning of your question (all code in Objective C, NOT Swift):

首先,你需要设置一个带回调的表,当你在问题的开头陈述自己时(Objective C中的所有代码,不是Swift):

CGPDFOperatorTableRef operatorTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback(operatorTable, "q", &op_q);
CGPDFOperatorTableSetCallback(operatorTable, "Q", &op_Q);

This table contains a list of the PDF operators you want to get called for and associates a callback with them. Those callbacks are simply functions you define elsewhere:

此表包含要调用的PDF运算符列表,并将回调与它们关联。那些回调只是你在别处定义的函数:

static void op_q(CGPDFScannerRef s, void *info) {
    // Do whatever you have to do in here
    // info is whatever you passed to CGPDFScannerCreate
}

static void op_Q(CGPDFScannerRef s, void *info) {
    // Do whatever you have to do in here
    // info is whatever you passed to CGPDFScannerCreate
}

And then you create the scanner and get it going, while passing it the information you just defined.

然后你创建扫描仪并开始运行,同时传递你刚才定义的信息。

// Passing "self" is just an example, you can pass whatever you want and it will be provided to your callback whenever it is called by the scanner.
CGPDFScannerRef contentStreamScanner = CGPDFScannerCreate(contentStream, operatorTable, self);

CGPDFScannerScan(contentStreamScanner);

If you want to see a complete example with sourcecode on how to find and process images, check this website.

如果您想查看有关如何查找和处理图像的源代码的完整示例,请查看此网站。

#3


-1  

To understand why a parser works this way, you need to read the PDF specification a bit better. A PDF file contains something close to printing instructions. Such as "move to this coordinate, print this character, move there, change the color, print the character number 23 from the font #23", etc.

要理解解析器为何以这种方式工作,您需要更好地阅读PDF规范。 PDF文件包含与打印说明相近的内容。例如“移动到此坐标,打印此字符,移动到那里,更改颜色,从字体#23打印字符编号23”等。

The parser gives you callbacks for each instructions, with the possibility to retrieve the instruction parameters. That's all.

解析器为每条指令提供回调,并可以检索指令参数。就这样。

So, in order to get the content from a file, you need to rebuild its state manually. Which means, recompute the frames for all characters, and try to reverse-engineer the page layout. This is clearly not an easy task, and that's why people have created libraries to do so.

因此,为了从文件中获取内容,您需要手动重建其状态。这意味着,重新计算所有字符的帧,并尝试对页面布局进行反向工程。这显然不是一件容易的事,这也是人们创建库的原因。

You may want to have a look at PDFKitten , or PDFParser which is a Swift port with some improvement that i did.

你可能想看看PDFKitten,或者PDFParser这是一个Swift端口,我做了一些改进。

#1


4  

Here is an example of the callbacks implemented in Swift:

以下是Swift中实现的回调示例:

    let operatorTableRef = CGPDFOperatorTableCreate()

    CGPDFOperatorTableSetCallback(operatorTableRef, "BT") { (scanner, info) in
        print("Begin text object")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "ET") { (scanner, info) in
        print("End text object")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "Tf") { (scanner, info) in
        print("Select font")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "Tj") { (scanner, info) in
        print("Show text")
    }
    CGPDFOperatorTableSetCallback(operatorTableRef, "TJ") { (scanner, info) in
        print("Show text, allowing individual glyph positioning")
    }

    let numPages = CGPDFDocumentGetNumberOfPages(pdfDocument)
    for pageNum in 1...numPages {
        let page = CGPDFDocumentGetPage(pdfDocument, pageNum)
        let stream = CGPDFContentStreamCreateWithPage(page)
        let scanner = CGPDFScannerCreate(stream, operatorTableRef, nil)
        CGPDFScannerScan(scanner)
        CGPDFScannerRelease(scanner)
        CGPDFContentStreamRelease(stream)
    }

#2


1  

You've actually specified exactly how to do it, all you need to do is put it together and try until it works.

您实际上已经确切地指定了如何操作,您需要做的就是将它放在一起并尝试直到它工作。

First of all, you need to setup a a table with callbacks as you state yourself in the beginning of your question (all code in Objective C, NOT Swift):

首先,你需要设置一个带回调的表,当你在问题的开头陈述自己时(Objective C中的所有代码,不是Swift):

CGPDFOperatorTableRef operatorTable = CGPDFOperatorTableCreate();
CGPDFOperatorTableSetCallback(operatorTable, "q", &op_q);
CGPDFOperatorTableSetCallback(operatorTable, "Q", &op_Q);

This table contains a list of the PDF operators you want to get called for and associates a callback with them. Those callbacks are simply functions you define elsewhere:

此表包含要调用的PDF运算符列表,并将回调与它们关联。那些回调只是你在别处定义的函数:

static void op_q(CGPDFScannerRef s, void *info) {
    // Do whatever you have to do in here
    // info is whatever you passed to CGPDFScannerCreate
}

static void op_Q(CGPDFScannerRef s, void *info) {
    // Do whatever you have to do in here
    // info is whatever you passed to CGPDFScannerCreate
}

And then you create the scanner and get it going, while passing it the information you just defined.

然后你创建扫描仪并开始运行,同时传递你刚才定义的信息。

// Passing "self" is just an example, you can pass whatever you want and it will be provided to your callback whenever it is called by the scanner.
CGPDFScannerRef contentStreamScanner = CGPDFScannerCreate(contentStream, operatorTable, self);

CGPDFScannerScan(contentStreamScanner);

If you want to see a complete example with sourcecode on how to find and process images, check this website.

如果您想查看有关如何查找和处理图像的源代码的完整示例,请查看此网站。

#3


-1  

To understand why a parser works this way, you need to read the PDF specification a bit better. A PDF file contains something close to printing instructions. Such as "move to this coordinate, print this character, move there, change the color, print the character number 23 from the font #23", etc.

要理解解析器为何以这种方式工作,您需要更好地阅读PDF规范。 PDF文件包含与打印说明相近的内容。例如“移动到此坐标,打印此字符,移动到那里,更改颜色,从字体#23打印字符编号23”等。

The parser gives you callbacks for each instructions, with the possibility to retrieve the instruction parameters. That's all.

解析器为每条指令提供回调,并可以检索指令参数。就这样。

So, in order to get the content from a file, you need to rebuild its state manually. Which means, recompute the frames for all characters, and try to reverse-engineer the page layout. This is clearly not an easy task, and that's why people have created libraries to do so.

因此,为了从文件中获取内容,您需要手动重建其状态。这意味着,重新计算所有字符的帧,并尝试对页面布局进行反向工程。这显然不是一件容易的事,这也是人们创建库的原因。

You may want to have a look at PDFKitten , or PDFParser which is a Swift port with some improvement that i did.

你可能想看看PDFKitten,或者PDFParser这是一个Swift端口,我做了一些改进。