/
stream.go
133 lines (112 loc) · 3.8 KB
/
stream.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.md', which is part of this source code package.
*/
package core
import (
"fmt"
"../common"
)
// NewEncoderFromStream creates a StreamEncoder based on the stream's dictionary.
func NewEncoderFromStream(streamObj *PdfObjectStream) (StreamEncoder, error) {
filterObj := TraceToDirectObject(streamObj.PdfObjectDictionary.Get("Filter"))
if filterObj == nil {
// No filter, return raw data back.
return NewRawEncoder(), nil
}
if _, isNull := filterObj.(*PdfObjectNull); isNull {
// Filter is null -> raw data.
return NewRawEncoder(), nil
}
// The filter should be a name or an array with a list of filter names.
method, ok := filterObj.(*PdfObjectName)
if !ok {
array, ok := filterObj.(*PdfObjectArray)
if !ok {
return nil, fmt.Errorf("Filter not a Name or Array object")
}
if len(*array) == 0 {
// Empty array -> indicates raw filter (no filter).
return NewRawEncoder(), nil
}
if len(*array) != 1 {
menc, err := newMultiEncoderFromStream(streamObj)
if err != nil {
common.Log.Error("Failed creating multi encoder: %v", err)
return nil, err
}
common.Log.Trace("Multi enc: %s\n", menc)
return menc, nil
}
// Single element.
filterObj = (*array)[0]
method, ok = filterObj.(*PdfObjectName)
if !ok {
return nil, fmt.Errorf("Filter array member not a Name object")
}
}
if *method == StreamEncodingFilterNameFlate {
return newFlateEncoderFromStream(streamObj, nil)
} else if *method == StreamEncodingFilterNameLZW {
return newLZWEncoderFromStream(streamObj, nil)
} else if *method == StreamEncodingFilterNameDCT {
return newDCTEncoderFromStream(streamObj, nil)
} else if *method == StreamEncodingFilterNameRunLength {
return newRunLengthEncoderFromStream(streamObj, nil)
} else if *method == StreamEncodingFilterNameASCIIHex {
return NewASCIIHexEncoder(), nil
} else if *method == StreamEncodingFilterNameASCII85 || *method == "A85" {
return NewASCII85Encoder(), nil
} else if *method == StreamEncodingFilterNameCCITTFax {
return NewCCITTFaxEncoder(), nil
} else if *method == StreamEncodingFilterNameJBIG2 {
return NewJBIG2Encoder(), nil
} else if *method == StreamEncodingFilterNameJPX {
return NewJPXEncoder(), nil
} else {
common.Log.Debug("ERROR: Unsupported encoding method!")
return nil, fmt.Errorf("Unsupported encoding method (%s)", *method)
}
}
// DecodeStream decodes the stream data and returns the decoded data.
// An error is returned upon failure.
func DecodeStream(streamObj *PdfObjectStream) ([]byte, error) {
common.Log.Trace("Decode stream")
encoder, err := NewEncoderFromStream(streamObj)
if err != nil {
common.Log.Debug("Stream decoding failed: %v", err)
return nil, err
}
common.Log.Trace("Encoder: %#v\n", encoder)
decoded, err := encoder.DecodeStream(streamObj)
if err != nil {
common.Log.Debug("Stream decoding failed: %v", err)
return nil, err
}
return decoded, nil
}
// EncodeStream encodes the stream data using the encoded specified by the stream's dictionary.
func EncodeStream(streamObj *PdfObjectStream) error {
common.Log.Trace("Encode stream")
encoder, err := NewEncoderFromStream(streamObj)
if err != nil {
common.Log.Debug("Stream decoding failed: %v", err)
return err
}
if lzwenc, is := encoder.(*LZWEncoder); is {
// If LZW:
// Make sure to use EarlyChange 0.. We do not have write support for 1 yet.
lzwenc.EarlyChange = 0
streamObj.PdfObjectDictionary.Set("EarlyChange", MakeInteger(0))
}
common.Log.Trace("Encoder: %+v\n", encoder)
encoded, err := encoder.EncodeBytes(streamObj.Stream)
if err != nil {
common.Log.Debug("Stream encoding failed: %v", err)
return err
}
streamObj.Stream = encoded
// Update length
streamObj.PdfObjectDictionary.Set("Length", MakeInteger(int64(len(encoded))))
return nil
}