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  }