# Stream encoding

Pdf streams can be encoded using one or more filters specified by pdf specification. The encoding/decoding algorithm is called a filter. There are two types of filters

- ASCII filters - enable decoding of arbitrary 8-bit binary data that has been encoded as ASCII text

- (de)compression filters - enable decoding of data that has been compressed

There is a set of filters which every pdf viewer must implement. It is up to the viewer how it handles an unknown filter.

## Xpdf filters

Xpdf viewer implements all decoding filters from pdf specification v1.5. However it does not implement any encoding filters (it does not need them).

Simple xpdf stream hierarchy

Simple xpdf stream hierarchy

Xpdf stream design is good but can be improved. The design resulted into many objects that are tightly coupled together (see picture). They can be decoupled using which also makes objects more reusable.

Finally, the unclear implementation makes it difficult to use and very difficult to extend and it lacks almost any fault tolerance. We use xpdf filters (because it is hardwired into xpdf parsing) only to decode data but we design our own encoding filters.

## Encoding filter design

The idea behind filtering streams is quite simple and common so we use boost filtering iostreams which give us a very nice filtering input/output concept. Filtering stream consists of filters and devices. A device can be either a sink(input) a or a source(output). We need just buffer encoding so we use only sources (devices you can read from). We can connect arbitrary number of filters to source. When we read from a filtering input stream, the read call is delegated through the chain of filters to first device which returns raw character(s). Then every filter, in reverse order, encodes the character(s) and passes it to the next filter. Finally an encoded character(s) falls from the filtering input stream.

Which filters to use is specified in stream dictionary.

Boost stream concept in pdfedit

Stream concept in pdfedit

This design is flexible, easily extensible as we only have to implement the new filter and connect it to the source when the filter name matches the filter name specified in the stream dictionary.