使用<div class="parent">
<div class="sibling-1">Sibling 1</div>
<div class="sibling-2">Sibling 2</div>
<div class="sibling-3">Sibling 3</div>
</div>
,其中包含2个大流(第1页和第2页),以及一堆其他对象和较小的流。我正试图缩小流,以使用源数据,但我正在努力。我只能得到损坏的输入和无效的校验和错误。
我编写了一个测试脚本来帮助调试,并从文件中抽出较小的流来测试。
以下是来自原始pdf的2个流及其长度对象:
流1 :
2016-W4 pdf
流2
149 0 obj
<< /Length 150 0 R /Filter /FlateDecode /Type /XObject /Subtype /Form /FormType
1 /BBox [0 0 8 8] /Resources 151 0 R >>
stream
x+TT(T0B ,JUWÈS0Ð37±402V(NFJSþ¶
«
endstream
endobj
150 0 obj
42
endobj
我只将142 0 obj
<< /Length 143 0 R /Filter /FlateDecode /Type /XObject /Subtype /Form /FormType
1 /BBox [0 0 0 0] /Resources 144 0 R >>
stream
x+Tçã
endstream
endobj
143 0 obj
11
endobj
内容复制到Vim 中的新文件中(不包括stream
之后和stream
之前的回车)。
我试过了两个:
我已将流转换为compress/zlib
以获取以下内容:
[]byte
我确定我在某处做错了什么,我只是看不到它。
(pdf在观众中打开)
答案 0 :(得分:2)
二进制数据永远不会从文本编辑器中复制出来/保存。可能会出现这样的情况,并且它只是为火焰添加油。
您最终从PDF中“挖掘出来”的数据很可能与PDF中 的实际数据不同。您应该从十六进制编辑器中获取数据(例如,尝试hecate获取新的内容),或编写一个保存它的简单应用程序(严格将文件作为二进制文件处理)。
提示#1:
显示的二进制数据分布在多行中。二进制数据不包含回车符,这是一个文本控件。如果是这样,那意味着编辑器 将其解释为文本,因此一些代码/字符“消耗”以开始新行。多个序列可以被解释为相同的换行符(例如\n
,\r\n
)。通过排除它们,您已经处于数据丢失状态,通过包含它们,您可能已经有了不同的序列。如果数据被解释并显示为文本,则可能会出现更多问题,因为控制字符越多,显示时可能不会显示某些字符。
提示#2:
使用flateReaderFn
时,解码第二个示例成功(完成没有错误)。这意味着“你正在吠叫正确的树”,但成功取决于实际数据是什么以及文本编辑器“扭曲”到什么程度。
答案 1 :(得分:1)
好的,忏悔时间......
我非常想要了解deflate,我完全忽略了Vim没有正确地将流内容保存到新文件中的事实。所以我花了很多时间阅读RFC,并深入研究Go compress/...
软件包的内部结构,假设问题与我的代码有关。
在我发布我的问题后不久,我尝试整体阅读PDF,找到stream
/ endstream
位置,并通过缩小推送。当我看到内容滚动屏幕时,我意识到我的愚蠢错误。
+1 @icza,这正是我的问题。
从那时起它很好,因为我对整个过程有了更好的理解,而不是第一次使用它的时候。
答案 2 :(得分:0)
根据所使用的过滤器,从 PDF 中提取对象可能会很棘手。过滤器还可以有其他需要正确处理的选项。
对于有兴趣提取对象而不关心过程的低级细节的人。
要从 PDF 中获取单个对象并对其进行解码,可以按如下方式进行:
package main
import (
"fmt"
"os"
"strconv"
"github.com/unidoc/unipdf/v3/core"
"github.com/unidoc/unipdf/v3/model"
)
func main() {
objNum := 149 // Get object 149
err := inspectPdfObject("input.pdf", objNum)
if err != nil {
fmt.Printf("Error: %v\n", err)
os.Exit(1)
}
}
func inspectPdfObject(inputPath string, objNum int) error {
f, err := os.Open(inputPath)
if err != nil {
return err
}
defer f.Close()
pdfReader, err := model.NewPdfReader(f)
if err != nil {
return err
}
isEncrypted, err := pdfReader.IsEncrypted()
if err != nil {
return err
}
if isEncrypted {
// If encrypted, try decrypting with an empty one.
// Can also specify a user/owner password here by modifying the line below.
auth, err := pdfReader.Decrypt([]byte(""))
if err != nil {
fmt.Printf("Decryption error: %v\n", err)
return err
}
if !auth {
fmt.Println(" This file is encrypted with opening password. Modify the code to specify the password.")
return nil
}
}
obj, err := pdfReader.GetIndirectObjectByNumber(objNum)
if err != nil {
return err
}
fmt.Printf("Object %d: %s\n", objNum, obj.String())
if stream, is := obj.(*core.PdfObjectStream); is {
decoded, err := core.DecodeStream(stream)
if err != nil {
return err
}
fmt.Printf("Decoded:\n%s", decoded)
} else if indObj, is := obj.(*core.PdfIndirectObject); is {
fmt.Printf("%T\n", indObj.PdfObject)
fmt.Printf("%s\n", indObj.PdfObject.String())
}
return nil
}
完整示例:pdf_get_object.go
披露:我是 UniPDF 的原始开发者。