如何解压缩/压缩PDF流
使用如何解压缩/压缩PDF流,pdf,go,gzip,zlib,Pdf,Go,Gzip,Zlib,使用2016-W4 pdf,它有两个大数据流(第1页和第2页),以及一组其他对象和较小的数据流。我正在尝试对流进行放气,以处理源数据,但我正在努力。我只能得到损坏的输入和无效的校验和错误 我已经编写了一个测试脚本来帮助调试,并从文件中提取了较小的流来进行测试 以下是原始pdf中的两个流及其长度对象: 流1: 149 0 obj << /Length 150 0 R /Filter /FlateDecode /Type /XObject /Subtype /Form /FormType
2016-W4 pdf
,它有两个大数据流(第1页和第2页),以及一组其他对象和较小的数据流。我正在尝试对流进行放气,以处理源数据,但我正在努力。我只能得到损坏的输入和无效的校验和错误
我已经编写了一个测试脚本来帮助调试,并从文件中提取了较小的流来进行测试
以下是原始pdf中的两个流及其长度对象:
流1:
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
我肯定我在什么地方做错了什么,我只是看不太清楚
(pdf确实在查看器中打开)好的,忏悔时间 我忙于理解deflate,以至于完全忽略了一个事实,即Vim没有将流内容正确地保存到新文件中。因此,我花了相当多的时间阅读RFC,并深入研究Go
compress/…
包的内部,假设问题出在我的代码上
在我发布我的问题后不久,我试着将PDF作为一个整体阅读,找到流
/尾流
位置,并将其通过deflate。当我看到内容在屏幕上滚动时,我意识到我犯了一个愚蠢的错误
+1@icza,这正是我的问题
这最终还是很好的,因为我对整个过程的理解要比第一次尝试时的理解要好得多。绝不能从文本编辑器中复制或保存二进制数据。在某些情况下,这种方法可能会成功,只会给火焰添上一层油
您最终从PDF中“挖掘”出来的数据很可能与PDF中的实际数据不完全相同。您应该从十六进制编辑器(例如尝试新的东西)获取数据,或者编写一个简单的应用程序,将其保存(严格地将文件处理为二进制文件)
提示#1:
显示的二进制数据分布在多行中。二进制数据不包含回车,这是一个文本控件。如果是,这意味着编辑器确实将其解释为文本,因此一些代码/字符在“已使用”的位置开始新行。多个序列可以解释为同一换行符(例如,\n
,\r\n
)。通过排除它们,您已经处于数据丢失状态,通过包含它们,您可能已经拥有了不同的序列。如果数据被解释并显示为文本,则可能会出现更多的问题,因为有更多的控制字符,并且某些字符在显示时可能不会出现
提示#2:
使用
flateReaderFn
时,第二个示例的解码成功(完成时没有错误)。这意味着“你找到了正确的树”,但成功与否取决于实际数据是什么,以及文本编辑器“扭曲”的程度。从PDF中提取对象可能很棘手,具体取决于所使用的过滤器。过滤器还可以有其他需要正确处理的选项
对于那些对提取对象感兴趣的人来说,不需要考虑过程的低级细节
要从PDF中获取单个对象并对其进行解码,可以按以下步骤进行:
主程序包
进口(
“fmt”
“操作系统”
“strconv”
“github.com/unidoc/unipdf/v3/core”
“github.com/unidoc/unipdf/v3/model”
)
func main(){
objNum:=149//获取对象149
err:=inspectPdfObject(“input.pdf”,objNum)
如果错误!=零{
fmt.Printf(“错误:%v\n”,错误)
操作系统退出(1)
}
}
func InspectPdfoObject(inputPath字符串,对象int)错误{
f、 错误:=操作系统打开(inputPath)
如果错误!=零{
返回错误
}
延迟f.关闭()
pdfReader,err:=model.NewPdfReader(f)
如果错误!=零{
返回错误
}
isEncrypted,err:=pdfReader.isEncrypted()
如果错误!=零{
返回错误
}
如果我加密了{
//如果已加密,请尝试使用空密码解密。
//也可以通过修改下面的行在此处指定用户/所有者密码。
auth,err:=pdfReader.Decrypt([]字节(“”)
如果错误!=零{
fmt.Printf(“解密错误:%v\n”,错误)
返回错误
}
如果{
fmt.Println(“此文件使用打开密码加密。修改代码以指定密码。”)
归零
}
}
obj,err:=pdfReader.GetIndirectObjectByNumber(objNum)
如果错误!=零{
返回错误
}
fmt.Printf(“对象%d:%s\n”,objNum,obj.String())
如果是流,则为:=obj(*core.PdfObjectStream);为{
已解码,错误:=core.DecodeStream(流)
如果错误!=零{
返回错误
}
fmt.Printf(“已解码:\n%s”,已解码)
}否则,如果indObj为:=obj(*core.PdfIndirectObject);则为{
fmt.Printf(“%T\n”,indObj.PdfObject)
fmt.Printf(“%s\n”,indObj.PdfObject.String())
}
归零
}
一个完整的例子:
披露:我是UniPDF的原始开发人员。您确定vim显示了您并复制了正确的字节吗?你应该从十六进制编辑器中获取数据(例如check)。@icza-如果你想将其作为答案发布,我会给你分数=)
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
package main
import (
"bytes"
"compress/flate"
"compress/gzip"
"compress/zlib"
"fmt"
"io"
"os"
)
var (
flateReaderFn = func(r io.Reader) (io.ReadCloser, error) { return flate.NewReader(r), nil }
zlibReaderFn = func(r io.Reader) (io.ReadCloser, error) { return zlib.NewReader(r) }
)
func deflate(b []byte, skip, length int, newReader func(io.Reader) (io.ReadCloser, error)) {
// rfc-1950
// --------
// First 2 bytes
// [120, 1] - CMF, FLG
//
// CMF: 120
// 0111 1000
// ↑ ↑
// | CM(8) = deflate compression method
// CINFO(7) = 32k LZ77 window size
//
// FLG: 1
// 0001 ← FCHECK
// (CMF*256 + FLG) % 31 == 0
// 120 * 256 + 1 = 30721
// 30721 % 31 == 0
stream := bytes.NewReader(b[skip:length])
r, err := newReader(stream)
if err != nil {
fmt.Println("\nfailed to create reader,", err)
return
}
n, err := io.Copy(os.Stdout, r)
if err != nil {
if n > 0 {
fmt.Print("\n")
}
fmt.Println("\nfailed to write contents from reader,", err)
return
}
fmt.Printf("%d bytes written\n", n)
r.Close()
}
func main() {
//readerFn, skip := flateReaderFn, 2 // compress/flate RFC-1951, ignore first 2 bytes
readerFn, skip := zlibReaderFn, 0 // compress/zlib RFC-1950, ignore nothing
// ⤹ This is where the error occurs: `flate: corrupt input before offset 19`.
stream1 := []byte{120, 1, 43, 84, 8, 84, 40, 84, 48, 0, 66, 11, 32, 44, 74, 85, 8, 87, 195, 136, 83, 48, 195, 144, 51, 55, 194, 177, 52, 48, 50, 86, 40, 78, 70, 194, 150, 74, 83, 8, 4, 0, 195, 190, 194, 182, 10, 194, 171, 10}
stream2 := []byte{120, 1, 43, 84, 8, 4, 0, 1, 195, 167, 0, 195, 163, 10}
fmt.Println("----------------------------------------\nStream 1:")
deflate(stream1, skip, 42, readerFn) // flate: corrupt input before offset 19
fmt.Println("----------------------------------------\nStream 2:")
deflate(stream2, skip, 11, readerFn) // invalid checksum
}