Logo Search packages:      
Sourcecode: passepartout version File versions  Download package

encode.h

// -*- c++ -*-
///
// Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#ifndef ENCODE_H 
#define ENCODE_H

#include <iostream>
#include <string>
#include <vector>

// 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<const char*>(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<SimpleEncodeFilter*> 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<unsigned char> Bytes;
    Bytes bytes; // a place to write an unknown amount of data
    
    void flush_buffer(); // encode buffer and put it in bytes 
  };

}

#endif

Generated by  Doxygen 1.6.0   Back to index