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