// -*- c++ -*- /// // Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING /// #ifndef ENCODE_H #define ENCODE_H #include #include #include // Standard PostScript encoding filters namespace PS { static const int max_line_width = 75; class EncodeFilter { public: EncodeFilter(bool _write_eod = true) : write_eod(_write_eod) {} virtual ~EncodeFilter() {} // The postscripts commands necessary to decode this filter: virtual std::string decode_command() const = 0; // Initalize: virtual void begin(std::ostream *out_) {out = out_;} // Write a chunk of data. If flush == true then it is assumed that // these are the last data. virtual void write(const unsigned char *data, unsigned long count, bool flush = false) = 0; // Finalize: virtual void end() {write(0, 0, true);} protected: bool write_eod; std::ostream *out; }; class EncodeFilterCascade; // This is actually NullEncodeFilter // It writes the input directly to the output, without change. class SimpleEncodeFilter: public EncodeFilter{ friend class EncodeFilterCascade; // so it can run filter(...) public: SimpleEncodeFilter(bool _write_eod = true) : EncodeFilter(_write_eod) {} std::string decode_command() const {return "/NullEncode filter";} // There is no NullDecode filter - it would be identical to NullEncode void begin(std::ostream *out_) {EncodeFilter::begin(out_); init();} void write(const unsigned char *data, unsigned long count, bool flush = false) {out->write(reinterpret_cast(data), count);} protected: int line_width; // filter data, data_out should be deleted when used. // If flush is set to true, the filter may assume these are the last data. virtual void filter(const unsigned char *data_in, unsigned long count_in, unsigned char *&data_out, unsigned long &count_out, bool flush = false) { count_out = count_in; data_out = new unsigned char[count_out]; memcpy(data_out, data_in, count_in); } // initialize, if begin is not to be called virtual void init() {line_width = 0;} }; typedef std::vector FilterSequence; // more than one (simple) filter after one another class EncodeFilterCascade: public EncodeFilter { public: EncodeFilterCascade(FilterSequence &filter_sequence): sequence(filter_sequence) {} std::string decode_command() const; void begin(std::ostream *out_); void write(const unsigned char *data, unsigned long count, bool flush = false); private: FilterSequence &sequence; }; // Simple binary-to-ASCII filter class ASCIIHexEncodeFilter: public SimpleEncodeFilter { public: ASCIIHexEncodeFilter(bool _write_eod = true) : SimpleEncodeFilter(_write_eod) {} std::string decode_command() const {return "/ASCIIHexDecode filter";} void begin(std::ostream *out_); void write(const unsigned char *data, unsigned long count, bool flush = false); protected: // binary output is rather pointless in an ASCII filter, but here goes ... // Beware! Untested code! void filter(const unsigned char *data_in, unsigned long count_in, unsigned char *&data_out, unsigned long &count_out, bool flush = false); }; // the ASCII85 encoding is much more efficient than ASCIIHex class ASCII85EncodeFilter: public SimpleEncodeFilter { public: ASCII85EncodeFilter(bool _write_eod = true) : SimpleEncodeFilter(_write_eod) {} std::string decode_command() const {return "/ASCII85Decode filter";} void write(const unsigned char *data, unsigned long count, bool flush=false); protected: //Note: this function does not work: void filter(const unsigned char *data_in, unsigned long count_in, unsigned char *&data_out, unsigned long &count_out, bool flush = false); void init(); private: // Encode and write the four bytes in chunk. // Returns number of characters written. // The z special case says that five zeros are encoded as 'z'. // The output_count argument is for the eod padding special case int write_chunk(const unsigned char *chunk, bool apply_z_special_case = true, int output_num = 5); // Buffer to hold remainder of data amount not divisible by 4: unsigned char buffer[4]; // Number of bytes in buffer: int fill; }; // RunLengthEncode can compress grayscale images with few gray levels // very efficiently. It doesn't work for color images, since it only // compares individual bytes, whereas color values are three bytes long. // However, it never expands data very much, so it is safe to use on any // image. class RunLengthEncodeFilter: public SimpleEncodeFilter { public: RunLengthEncodeFilter(bool _write_eod = true) : SimpleEncodeFilter(_write_eod) {} std::string decode_command() const {return "/RunLengthDecode filter";} void write(const unsigned char *data, unsigned long count, bool flush = false); protected: void filter(const unsigned char *data_in, unsigned long count_in, unsigned char *&data_out, unsigned long &count_out, bool flush = false); void init(); private: unsigned char buffer[128]; // RunLengthEncode can handle a maximum of 128 identical bytes in a row. // Number of bytes in buffer: int fill; typedef std::vector Bytes; Bytes bytes; // a place to write an unknown amount of data void flush_buffer(); // encode buffer and put it in bytes }; } #endif