Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/email/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何解压缩/压缩PDF流_Pdf_Go_Gzip_Zlib - Fatal编程技术网

如何解压缩/压缩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
}