github.com/pdfcpu/pdfcpu@v0.11.1/pkg/filter/runLengthDecode.go (about)

     1  /*
     2  Copyright 2018 The pdfcpu Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  	http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package filter
    18  
    19  import (
    20  	"bytes"
    21  	"io"
    22  )
    23  
    24  type runLengthDecode struct {
    25  	baseFilter
    26  }
    27  
    28  func (f runLengthDecode) decode(w io.ByteWriter, src []byte, maxLen int64) {
    29  	var written int64
    30  
    31  	for i := 0; i < len(src); {
    32  		b := src[i]
    33  		if b == 0x80 {
    34  			// eod
    35  			break
    36  		}
    37  		i++
    38  		if b < 0x80 {
    39  			c := int(b) + 1
    40  			for j := 0; j < c; j++ {
    41  				if maxLen >= 0 && maxLen == written {
    42  					break
    43  				}
    44  
    45  				w.WriteByte(src[i])
    46  				written++
    47  				i++
    48  			}
    49  			continue
    50  		}
    51  		c := 257 - int(b)
    52  		for j := 0; j < c; j++ {
    53  			if maxLen >= 0 && maxLen == written {
    54  				break
    55  			}
    56  
    57  			w.WriteByte(src[i])
    58  			written++
    59  		}
    60  		i++
    61  	}
    62  }
    63  
    64  func (f runLengthDecode) encode(w io.ByteWriter, src []byte) {
    65  
    66  	const maxLen = 0x80
    67  	const eod = 0x80
    68  
    69  	i := 0
    70  	b := src[i]
    71  	start := i
    72  
    73  	for {
    74  
    75  		// Detect constant run eg. 0x1414141414141414
    76  		for i < len(src) && src[i] == b && (i-start < maxLen) {
    77  			i++
    78  		}
    79  		c := i - start
    80  		if c > 1 {
    81  			// Write constant run with length=c
    82  			w.WriteByte(byte(257 - c))
    83  			w.WriteByte(b)
    84  			if i == len(src) {
    85  				w.WriteByte(eod)
    86  				return
    87  			}
    88  			b = src[i]
    89  			start = i
    90  			continue
    91  		}
    92  
    93  		// Detect variable run eg. 0x20FFD023335BCC12
    94  		for i < len(src) && src[i] != b && (i-start < maxLen) {
    95  			b = src[i]
    96  			i++
    97  		}
    98  		if i == len(src) || i-start == maxLen {
    99  			c = i - start
   100  			w.WriteByte(byte(c - 1))
   101  			for j := 0; j < c; j++ {
   102  				w.WriteByte(src[start+j])
   103  			}
   104  			if i == len(src) {
   105  				w.WriteByte(eod)
   106  				return
   107  			}
   108  		} else {
   109  			c = i - 1 - start
   110  			// Write variable run with length=c
   111  			w.WriteByte(byte(c - 1))
   112  			for j := 0; j < c; j++ {
   113  				w.WriteByte(src[start+j])
   114  			}
   115  			i--
   116  		}
   117  		b = src[i]
   118  		start = i
   119  	}
   120  
   121  }
   122  
   123  // Encode implements encoding for a RunLengthDecode filter.
   124  func (f runLengthDecode) Encode(r io.Reader) (io.Reader, error) {
   125  
   126  	b1, err := getReaderBytes(r)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	var b2 bytes.Buffer
   132  	f.encode(&b2, b1)
   133  
   134  	return &b2, nil
   135  }
   136  
   137  // Decode implements decoding for an RunLengthDecode filter.
   138  func (f runLengthDecode) Decode(r io.Reader) (io.Reader, error) {
   139  	return f.DecodeLength(r, -1)
   140  }
   141  
   142  func (f runLengthDecode) DecodeLength(r io.Reader, maxLen int64) (io.Reader, error) {
   143  
   144  	b1, err := getReaderBytes(r)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	var b2 bytes.Buffer
   150  	f.decode(&b2, b1, maxLen)
   151  
   152  	return &b2, nil
   153  }