summaryrefslogtreecommitdiff
path: root/graphics/sam2p/encoder.cpp
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/sam2p/encoder.cpp
Initial commit
Diffstat (limited to 'graphics/sam2p/encoder.cpp')
-rw-r--r--graphics/sam2p/encoder.cpp1765
1 files changed, 1765 insertions, 0 deletions
diff --git a/graphics/sam2p/encoder.cpp b/graphics/sam2p/encoder.cpp
new file mode 100644
index 0000000000..4bb8c714ad
--- /dev/null
+++ b/graphics/sam2p/encoder.cpp
@@ -0,0 +1,1765 @@
+/* encoder.cpp -- various PostScript and PDF encoding filter implementations
+ * by pts@fazekas.hu at Sun Mar 3 14:16:00 CET 2002
+ * --- Mon Mar 4 00:00:20 CET 2002
+ */
+
+/* Imp: make built-in FlateEncode DYNALLOC */
+/* Imp: add lzw_codec */
+/* Imp: add gzip */
+/* Imp: add zlib */
+
+#ifdef __GNUC__
+#ifndef __clang__
+#pragma implementation
+#endif
+#endif
+
+
+#include "encoder.hpp"
+#include "error.hpp"
+#include "gensio.hpp"
+#include <stdlib.h> /* getenv() */
+#include <string.h>
+
+/* --- */
+
+/** Does output EOD (end-of-data) marker `>' */
+class ASCIIHexEncode: public PSEncoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ ASCIIHexEncode(GenBuffer::Writable &out_, unsigned maxcpl_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned maxcpl;
+ /** Number of hex digits already printed. */
+ unsigned curcpl;
+ GenBuffer::Writable &out;
+};
+
+/** Does output EOD (end-of-data) marker `~>' */
+class ASCII85Encode: public PSEncoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ ASCII85Encode(GenBuffer::Writable &out_, unsigned maxcpl_);
+ virtual void vi_write(char const*buf, slen_t len);
+
+ protected:
+ void wencoded(char const *encoded);
+ void wout(unsigned PTS_INT32_T buf_);
+ unsigned maxcpl;
+ /** Number of digits available in this line */
+ GenBuffer::Writable &out;
+ unsigned ascii85breaklen;
+ unsigned ascii85left;
+ unsigned PTS_INT32_T ascii85buf;
+ char *obuf, *obufend, *op;
+ char dscst; /* For converting `%%' to `% %' to avoid DSC parser errors */
+};
+
+/** Doesn't output EOD (end-of-data) marker `>' */
+class RunLengthEncode: public PSEncoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ RunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize_);
+ virtual void vi_write(char const*buf, slen_t len);
+
+ protected:
+ slen_t recordsize;
+ GenBuffer::Writable &out;
+ // char *obuf, *obufend, *op;
+ slen_t record_left;
+ unsigned saved_c, saved_rep;
+ /** size == header+buffer+EOD */
+ char saved[130];
+};
+
+static int gen_write(char *block, unsigned len, void *zfile);
+
+#if USE_BUILTIN_ZIP
+#include "pts_defl.h" /* Imp: because pts_defl_interface :-( */
+#if OBJDEP
+# warning REQUIRES: pts_defl
+#endif
+class FlateEncode: public PSEncoder {
+#if PTS_DEFL_RIPPED_ZLIB /* Dat: defined in pts_defl.h */
+ public:
+ /** @param level: 1..9: 9==highest compression */
+ FlateEncode(GenBuffer::Writable &out_, unsigned level_);
+ virtual ~FlateEncode() { zlib_deflateEnd(&zs); } /* Dat: ==Z_OK check (for unflushed buffers) omitted */
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ /** Formerly only one instance of FlateEncode was allowed.
+ * It exists <=> loced==true
+ */
+ // static bool locked;
+ /** Writable that this filter writes to */
+ GenBuffer::Writable &out;
+ char workspace[ZLIB_DEFLATE_WORKSPACESIZE_MIN]; /* big, about 270k */
+ char obuf[4096];
+ /*struct*/ z_stream zs;
+#else /* old, ripped from Info-ZIP 2.2 */
+ public:
+ /** @param level: 1..9: 9==highest compression */
+ FlateEncode(GenBuffer::Writable &out_, unsigned level_);
+ virtual ~FlateEncode() { if (fs!=NULLP) fs->delete2(fs); }
+ virtual void vi_write(char const*buf, slen_t len);
+ static void *gen_malloc(unsigned n);
+ static void gen_free(void *p);
+ protected:
+ /** Formerly only one instance of FlateEncode was allowed.
+ * It exists <=> loced==true
+ */
+ // static bool locked;
+ /** Writable that this filter writes to */
+ GenBuffer::Writable &out;
+ #if SIZEOF_INT>2
+ typedef unsigned s_t;
+ #else
+ typedef unsigned short s_t;
+ #endif
+ /** Adler32 checksum */
+ s_t s1, s2;
+ bool had_header;
+ struct pts_defl_interface* fs;
+#endif /* else PTS_DEFL_RIPPED_ZLIB */
+};
+#endif
+
+/** Just store the data in Flate (ZLIB) format, no real compression. Adds
+ * about 3 bytes of overhead per 65535 bytes (compression ratio:
+ * 100.004578%)
+ */
+class FlateStoreEncode: public PSEncoder {
+ public:
+ /** @param level: 1..9: 9==highest compression */
+ FlateStoreEncode(GenBuffer::Writable &out_);
+ inline virtual ~FlateStoreEncode() {}
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ GenBuffer::Writable &out;
+ #if SIZEOF_INT>2
+ typedef unsigned s_t;
+ #else
+ typedef unsigned short s_t;
+ #endif
+ /** Adler32 checksum */
+ s_t s1, s2;
+ bool had_header;
+ /** Number of bytes already in buf */
+ unsigned abuflen;
+ /** Max: 65535 */
+ #if HAVE_STATIC_CONST
+ static const unsigned ABUFSIZE=65535;
+ #else
+ #define ABUFSIZE 65535
+ #endif
+ /** Should really not allocate a FlateStoreEncode on the stack. */
+ char abuf[ABUFSIZE+5];
+};
+
+#if USE_BUILTIN_FAXE
+
+#include "pts_fax.h"
+#if OBJDEP
+# warning REQUIRES: pts_faxe
+#endif
+class CCITTFaxEncode: public PSEncoder {
+ public:
+ CCITTFaxEncode(GenBuffer::Writable &out_, slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ GenBuffer::Writable &out;
+ stream_CFE_state sCFEs;
+ unsigned char rbuf[4096];
+ unsigned char wbuf[4096];
+ stream_cursor_read r;
+ stream_cursor_write w;
+ unsigned char *hard, *rlimit;
+
+ static void*gen_xalloc(unsigned n);
+ static void gen_free(void *ptr);
+ static void gen_memset(void *s, int c, unsigned n);
+ static void gen_memcpy(void *dest, const void *src, unsigned n);
+};
+#endif
+
+#if USE_BUILTIN_LZW
+#include "pts_lzw.h" /* Imp: because pts_lzw_state :-( */
+#if OBJDEP
+# warning REQUIRES: pts_lzw
+#endif
+class LZWEncode: public PSEncoder {
+ public:
+ LZWEncode(GenBuffer::Writable &out_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ GenBuffer::Writable &out;
+ struct pts_lzw_state fs;
+};
+#endif
+
+/**
+ * Reporting of GS errors is somewhat dump: the actual message isn't reported,
+ * only the fact that something went wrong.
+ * Imp: force a no-error trailer output by gs, and check that
+ */
+class GSEncode: public PSEncoder {
+ public:
+ /** @param filter_psname is a full-featured PostScript *Encode filter
+ * specification string, for example: "<</Effort 5>>/FlateEncode" or
+ * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
+ * `currentfile ... filter'
+ */
+ GSEncode(GenBuffer::Writable &out_, char const*filter_psname);
+ inline virtual ~GSEncode() {}
+ /* vvv Imp: correct these */
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ class P: public Filter::PipeE {
+ protected: virtual void vi_check();
+ public: P(GenBuffer::Writable &out_, char const*filter_psname);
+ };
+ /** We need this delegator because `delete ...' won't work with multiple
+ * inheritance. (?? )
+ */
+ P p;
+};
+
+class CjpegEncode: public PSEncoder {
+ public:
+ /** @param filter_psname is a full-featured PostScript *Encode filter
+ * specification string, for example: "<</Effort 5>>/FlateEncode" or
+ * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
+ * `currentfile ... filter'
+ */
+ CjpegEncode(GenBuffer::Writable &out_, char const*filter_psname, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality);
+ inline virtual ~CjpegEncode() {}
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ class P: public Filter::PipeE { public:
+ // protected: virtual void vi_check();
+ P(GenBuffer::Writable &out_, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality);
+ protected: /* Not needed: protected -> public: pacify VC6.0 */
+ virtual void vi_copy(FILE *f);
+ bool rgbp;
+ };
+ /** We need this delegator because `delete ...' won't work with multiple
+ * inheritance. (?? )
+ */
+ P p;
+};
+
+#if !USE_BUILTIN_LZW
+class Lzw_codecEncode: public PSEncoder {
+ public:
+ /** @param filter_psname is a full-featured PostScript *Encode filter
+ * specification string, for example: "<</Effort 5>>/FlateEncode" or
+ * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
+ * `currentfile ... filter'
+ */
+ Lzw_codecEncode(GenBuffer::Writable &out_, char const*filter_psname);
+ inline virtual ~Lzw_codecEncode() {}
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ class P: public Filter::PipeE { public:
+ // protected: virtual void vi_check();
+ P(GenBuffer::Writable &out_);
+ protected:
+ // virtual void vi_copy(FILE *f);
+ };
+ /** We need this delegator because `delete ...' won't work with multiple
+ * inheritance. (?? )
+ */
+ P p;
+};
+#endif
+
+class TIFFPredictor2: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ TIFFPredictor2(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h;
+ unsigned char *obuf, *op, bpc, cpp;
+ slen_t rlen;
+ GenBuffer::Writable &out;
+};
+
+class PNGPredictorNone: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorNone(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ slen_t rlen, opleft;
+ GenBuffer::Writable &out;
+};
+
+class PNGPredictorSub: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorSub(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h;
+ unsigned char *obuf, *op;
+ slen_t rlen;
+ GenBuffer::Writable &out;
+ unsigned char bpccpp;
+};
+
+class PNGPredictorUp: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorUp(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned char *obuf, *op, *oq;
+ slen_t rlen;
+ GenBuffer::Writable &out;
+};
+
+class PNGPredictorAverage: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorAverage(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h/*, g*/;
+ unsigned char *obuf, *op, *oq;
+ slen_t rlen;
+ GenBuffer::Writable &out;
+ unsigned char bpccpp;
+};
+
+class PNGPredictorPaeth: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorPaeth(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h, g;
+ unsigned char *obuf, *op, *oq;
+ slen_t rlen;
+ GenBuffer::Writable &out;
+ unsigned char bpccpp;
+};
+
+/** This class implements inferior predictor autoselection heuristics.
+ * Please use PNGPredictorAuto instead.
+ * Imp: code reuse with PNGPredictorAuto
+ */
+class PNGPredictorAutoBadSigned: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorAutoBadSigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h, g;
+ unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
+ slen_t rlen;
+ GenBuffer::Writable &out;
+ unsigned char bpccpp;
+ slen_t opleft;
+};
+
+/** This class implements inferior predictor autoselection heuristics.
+ * Please use PNGPredictorAuto instead.
+ * Imp: code reuse with PNGPredictorAuto
+ */
+class PNGPredictorAutoBadUnsigned: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorAutoBadUnsigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h, g;
+ unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
+ slen_t rlen;
+ GenBuffer::Writable &out;
+ unsigned char bpccpp;
+ slen_t opleft;
+};
+
+/** This class implements to so-called ``minimum sum of absolute differences''
+ * predictior autoselection heuristics, the same as what pngwutil.c
+ * contains in function png_write_find_filter() in libpng 1.2.20. (See that
+ * function for a discussion of other heuristics. A summary of this heuristics:
+ * we find which method provides the smallest value when summing the absolute
+ * values of the distances from zero, using anything >= 128 as negative
+ * numbers.
+ */
+class PNGPredictorAuto: public Encoder {
+ public:
+ /** @param maxcpl_: maximum # hex digits per line, should be even */
+ PNGPredictorAuto(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
+ virtual void vi_write(char const*buf, slen_t len);
+ protected:
+ unsigned PTS_INT32_T h, g;
+ unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
+ slen_t rlen;
+ GenBuffer::Writable &out;
+ unsigned char bpccpp;
+ slen_t opleft;
+};
+
+/* --- */
+
+FlateStoreEncode::FlateStoreEncode(GenBuffer::Writable &out_)
+ :out(out_)
+ ,s1(1)
+ ,s2(0)
+ ,had_header(false)
+ ,abuflen(0)
+ {}
+
+#if 0
+/** 0x7801: ZLIB header signaling fastest compression
+ * 0: 2 bits: DEFLATE block header signaling stored (uncompressed) block +
+ * 6 bits of padding.
+ */
+char FlateStoreEncode::header[3]= { 0x78, 1, 0 };
+#endif
+
+void FlateStoreEncode::vi_write(char const*buf, slen_t len) {
+ register s_t sold;
+ register char const*p=buf; char const*pend=p+len;
+ (void)sold;
+ if (len==0) { /* EOF: flush and send trailer */
+ /* Dat: Last block has to be written even if it's empty. */
+ if (!had_header) { out.vi_write("\x78\x01", 2); had_header=true; }
+ abuf[0]=(char)1; /* Last, stored block with padding */
+ abuf[1]=abuflen; abuf[2]=abuflen>>8;
+ abuf[3]=~(abuflen); abuf[4]=~(abuflen>>8);
+ out.vi_write(abuf, abuflen+5);
+ if (s1>=65521) s1-=65521;
+ if (s2>=65521) s2-=65521;
+ unsigned char trailer[4];
+ trailer[0]=s2>>8; trailer[1]=s2&255; trailer[2]=s1>>8; trailer[3]=s1&255;
+ out.vi_write((char const*)trailer,4);
+ out.vi_write(0,0); /* Signal EOF */
+ return;
+ }
+ /* From rfc1950.txt:
+ Adler-32 is composed of two sums accumulated per byte: s1 is
+ the sum of all bytes, s2 is the sum of all s1 values. Both sums
+ are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+ Adler-32 checksum is stored as s2*65536 + s1 in most-
+ significant-byte first (network) order.
+ */
+ /* Update Adler-32 checksum */
+ while (p!=pend) {
+ #if SIZEOF_INT>2
+ if ((s1+=*(unsigned char const*)p)>=65521) s1-=65521;
+ if ((s2+=s1)>=65521) s2-=65521;
+ #elif SIZEOF_SHORT==2
+ sold=s1;
+ if ((s1+=*(unsigned char const*)p))<sold) s1+=15; /* 15==65536-21 */
+ sold=s2;
+ s2=(s2+s1)&0xffff;
+ if ((s2+=s1)<sold) s2+=15;
+ #else
+ /* vvv 0xffff is needed since unsigned short may be > 0..65535 */
+ sold=s1;
+ s1=(s1+*(unsigned char const*)p)&0xffff;
+ if (s1<sold) s1+=15; /* 15==65536-21 */
+ sold=s2;
+ s2=(s2+s1)&0xffff;
+ if (s2<sold) s2+=15;
+ #endif
+ p++;
+ }
+ // fprintf(stderr, "len=%u\n", len);
+ unsigned abufleft;
+ while ((abufleft=ABUFSIZE-abuflen)<len) {
+ // putchar('.');
+ // fprintf(stderr, "ABUFSIZE=%u abuflen=%u\n", ABUFSIZE, abuflen);
+ memcpy(abuf+abuflen+5, buf, abufleft);
+ abuf[0]=0; /* Stored block with padding */
+ abuf[1]=(char)ABUFSIZE; abuf[2]=(char)(ABUFSIZE>>8);
+ abuf[3]=(char)~(ABUFSIZE); abuf[4]=(char)~(ABUFSIZE>>8);
+ if (!had_header) { out.vi_write("\x78\x01", 2); had_header=true; }
+ /* fprintf(stderr,"%02x %02x", abuf[1], abuf[2]); */
+ out.vi_write(abuf, ABUFSIZE+5); /* emit next stored block with header */
+ abuflen=0;
+ len-=abufleft;
+ buf+=abufleft;
+ }
+ // putchar('X');
+ memcpy(abuf+abuflen+5, buf, len);
+ abuflen+=len;
+ /* Now abuf is possibly full. That is intentional, so we will be able to
+ * emit a full last block instead of an empty one.
+ */
+}
+
+/* --- */
+
+ASCIIHexEncode::ASCIIHexEncode(GenBuffer::Writable &out_, unsigned maxcpl_)
+ :maxcpl(maxcpl_)
+ ,curcpl(0)
+ ,out(out_) {}
+
+void ASCIIHexEncode::vi_write(char const*buf, slen_t len) {
+ /* Imp: buffering (1K etc.) */
+ static char const hextable []="0123456789abcdef";
+ char obuf[3];
+ obuf[0]='\n';
+ if (len==0) { out.vi_write(">",1); out.vi_write(0,0); }
+ else while (len--!=0) {
+ obuf[1]=hextable[(*(unsigned char const*)buf)>>4];
+ obuf[2]=hextable[(*(unsigned char const*)buf)&15];
+ if (curcpl>=maxcpl) { curcpl=2; out.vi_write(obuf, 3); }
+ else { curcpl+=2; out.vi_write(obuf+1, 2); }
+ buf++;
+ }
+}
+
+/* --- */
+
+ASCII85Encode::ASCII85Encode(GenBuffer::Writable &out_, unsigned maxcpl_)
+ :maxcpl(maxcpl_)
+ ,out(out_)
+ ,ascii85breaklen(maxcpl_)
+ ,ascii85left(4)
+ ,dscst(1) {
+ obufend=(op=obuf=new char[4096])+4096;
+}
+
+void ASCII85Encode::wencoded(char const *cp) {
+ for (; *cp!='\0'; ) {
+ if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
+ // if (*cp<='!') { fprintf(stderr, "e=%d.\n", cp-encoded); }
+ assert(*cp>='!');
+ assert(*cp<='~');
+ if (dscst) {
+ if (dscst == 1) {
+ dscst = (*cp == '%') ? 2 : 0;
+ } else { /* if (dscst == 2) { */
+ if (*cp == '%') {
+ if (--ascii85breaklen == 0) {
+ *op++ = '\n';
+ ascii85breaklen = maxcpl;
+ } else {
+ /* Add space for `% %' instead of `%%' at BOL. */
+ *op++ = ' ';
+ }
+ if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
+ }
+ dscst = 0;
+ }
+ }
+ *op++=*cp++;
+ if (--ascii85breaklen == 0) {
+ if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
+ *op++='\n';
+ ascii85breaklen = maxcpl;
+ dscst = 1;
+ }
+ } /* NEXT */
+}
+
+void ASCII85Encode::vi_write(char const*buf, slen_t len) {
+ if (len==0) {
+ char encoded[6];
+ assert(ascii85left<=4);
+ if (ascii85left!=4) {
+ unsigned PTS_INT32_T buf_=ascii85buf<<8*ascii85left;
+ unsigned PTS_INT32_T q;
+ unsigned w1;
+
+ q = buf_ / ((unsigned PTS_INT32_T)85*85*85*85); /* actually only a byte */
+ assert(q<=85);
+ encoded[0] = q + '!';
+
+ buf_ -= q * ((unsigned PTS_INT32_T)85*85*85*85); q = buf_ / ((unsigned PTS_INT32_T)85*85*85);
+ encoded[1] = q + '!';
+
+ buf_ -= q * ((unsigned PTS_INT32_T)85*85*85); q = buf_ / (85*85);
+ encoded[2] = q + '!';
+
+ w1 = (unsigned) (buf_ - q*(unsigned PTS_INT32_T)(85*85));
+ assert(w1/85<85);
+ encoded[3] = (w1 / 85) + '!';
+ encoded[4] = (w1 % 85) + '!';
+ encoded[5-ascii85left] = '\0';
+ wencoded(encoded);
+ } /* IF */
+ if (op!=obuf) out.vi_write(obuf, op-obuf); /* flush buffer cache */
+ out.vi_write("~>",2); out.vi_write(0,0);
+ delete [] obuf;
+ obuf=(char*)NULLP;
+ } else {
+ assert(obuf!=NULLP);
+ register unsigned PTS_INT32_T abuf=ascii85buf;
+ register unsigned aleft=ascii85left;
+ assert(aleft>=1 && aleft<=4);
+ do {
+ while (len!=0 && aleft!=0) {
+ abuf=(abuf<<8)+*(unsigned char const*)buf++; len--; aleft--;
+ }
+ if (aleft!=0) break;
+ wout(abuf);
+ aleft=4;
+ } while (len!=0);
+ ascii85buf=abuf; ascii85left=aleft;
+ }
+}
+
+void ASCII85Encode::wout(unsigned PTS_INT32_T buf_) {
+ char encoded[6];
+ if (buf_ != (unsigned PTS_INT32_T)0) {
+ unsigned PTS_INT32_T q;
+ unsigned w1;
+
+ q = buf_ / ((unsigned PTS_INT32_T)85*85*85*85); /* actually only a byte */
+ encoded[0] = q + '!';
+
+ buf_ -= q * ((unsigned PTS_INT32_T)85*85*85*85); q = buf_ / ((unsigned PTS_INT32_T)85*85*85);
+ encoded[1] = q + '!';
+
+ buf_ -= q * ((unsigned PTS_INT32_T)85*85*85); q = buf_ / (85*85);
+ encoded[2] = q + '!';
+
+ w1 = (unsigned) (buf_ - q*(unsigned PTS_INT32_T)(85*85));
+ encoded[3] = (w1 / 85) + '!';
+ encoded[4] = (w1 % 85) + '!';
+ encoded[5] = '\0';
+ } else {
+ encoded[0] = 'z', encoded[1] = '\0';
+ }
+ wencoded(encoded);
+}
+
+/* --- */
+
+RunLengthEncode::RunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize_)
+ :recordsize(RecordSize_==0?(slen_t)-1:RecordSize_)
+ ,out(out_) {
+ record_left=recordsize;
+ // obufend=(op=obuf=new char[4096])+4096; /* Imp: implement write buffering */
+ saved_c=saved_rep=0;
+}
+
+void RunLengthEncode::vi_write(char const*buf, slen_t len) {
+ unsigned j, umax;
+ char b;
+ if (len==0) { /* handle EOF */
+ if (saved_rep!=0) {
+ assert(saved_rep>=2);
+ (saved+1)[-1]=257-saved_rep;
+ (saved+1)[1]=(char)128; /* EOD */
+ out.vi_write((saved+1)-1,3);
+ // fprintf(stderr,"rd=%u\n",saved_rep);
+ } else if (saved_c!=0) {
+ (saved+1)[-1]=saved_c-1;
+ (saved+1)[saved_c]=(char)128; /* EOD */
+ out.vi_write((saved+1)-1, saved_c+2);
+ // fprintf(stderr,"re=%u\n",saved_c);
+ } else {
+ (saved+1)[-1]=(char)128;
+ out.vi_write((saved+1)-1, 1);
+ }
+ out.vi_write(0,0); /* propagate EOF */
+ record_left=0; /* signal that no further data will be accepted */
+ return;
+ }
+ again:
+ assert(record_left>=1);
+ assert(len>=1);
+ /* Imp: locally cache vars saved* */
+ j=0;
+ if (saved_c==0) {
+ saved_rep=0; saved_c=1; b=(saved+1)[0]=*buf++; len--;
+ if (0==--record_left) goto put_norep;
+ if (0==len) return;
+ goto yes;
+ }
+ if (saved_c==1 && saved_rep==0) { yes:
+ if (*buf++==(saved+1)[0]) {
+ saved_rep=2; len--;
+ if (0==--record_left) goto put_rep;
+ } else {
+ (saved+1)[1]=buf[-1]; saved_c=2; len--;
+ if (0==--record_left) goto put_norep;
+ }
+ if (0==len) return;
+ }
+ assert(record_left>=1);
+ assert(len>=1);
+ assert((saved_rep==0 && saved_c>=2) || (saved_rep>=2 && saved_c==1));
+ if (saved_rep!=0) { /* Try to increase the repeating sequence */
+ assert(saved_rep>=2);
+ assert(saved_c==1);
+ assert(len>=1);
+ b=(saved+1)[0];
+ umax=len>128?128:len; if (umax>record_left) umax=record_left;
+ /* fprintf(stderr,"um1=%u\n", umax); */
+ if (umax>128-saved_rep) umax=128-saved_rep;
+ assert(umax>=1);
+ j=0; while (j!=umax && buf[j]==b) { j++; saved_rep++; }
+ if (j!=len || saved_rep==128) {
+ put_rep: /* Found a maximal repeat width */
+ (saved+1)[-1]=257-saved_rep;
+ out.vi_write((saved+1)-1,2);
+ /* fprintf(stderr,"ra=%u\n",saved_rep); */
+ if ((record_left-=j)==0) record_left=recordsize;
+ buf+=j;
+ saved_c=saved_rep=0;
+ if (0==(len-=j)) return;
+ goto again;
+ } /* Current repeat width can be further increased */
+ } else { /* Try to increase the non-repeating sequence */
+ assert(saved_c>=2);
+ if (buf[0]==(saved+1)[saved_c-1]) { /* this decision might be sub-optimal */
+ saved_c--;
+ /* Now: saved_c: non-repeat length, >=1 */
+ (saved+1)[-1]=saved_c-1;
+ out.vi_write((saved+1)-1, saved_c+1);
+ /* fprintf(stderr,"rb=%u\n",saved_c); */
+ // record_left++; /* because of saved_c--; but we would increase it later anyway */
+ // buf+=saved_c;
+ (saved+1)[0]=buf[0]; /* first matching char-pair data */
+ saved_c=1; saved_rep=2; /* make the new block a >=2 repeat */
+ record_left--; buf++;
+ if (0==--len) return;
+ goto again;
+ }
+ (saved+1)[saved_c++]=buf[0];
+ //record_left--;
+ //buf++;
+ //len--;
+ //if (saved_c==128) goto put_norep;
+ //if (0==len) return;
+ umax=len>128?128:len; if (umax>record_left) umax=record_left;
+ if (umax>128-saved_c) umax=128-saved_c;
+ /* fprintf(stderr,"um2=%u\n", umax); */
+ assert(umax>=1);
+ j=1; while (j!=umax && buf[j]!=buf[j-1]) (saved+1)[saved_c++]=buf[j++];
+ if (j!=len || saved_c==128) {
+ put_norep: /* Found a maximal non-repeat width */
+ (saved+1)[-1]=saved_c-1;
+ out.vi_write((saved+1)-1, saved_c+1);
+ /* fprintf(stderr,"rc=%u\n",saved_c); */
+ if ((record_left-=j)==0) record_left=recordsize;
+ buf+=j;
+ saved_c=saved_rep=0;
+ if (0==(len-=j)) return;
+ goto again;
+ } /* Current non-repeat width can be further increased */
+ }
+ assert(j==len);
+ record_left-=j;
+ assert(saved_rep<128);
+ assert(saved_c<128);
+}
+
+/* --- */
+
+#if USE_BUILTIN_ZIP
+// bool FlateEncode::locked=false;
+
+#if PTS_DEFL_RIPPED_ZLIB
+FlateEncode::FlateEncode(GenBuffer::Writable &out_, unsigned level_)
+ :out(out_) {
+ // assert(!locked); locked /* locking is not necessary anymore */
+ // pts_deflate_init(&fs); /* obsolete */
+ zs.total_in=0;
+ zs.total_out=0;
+ zs.workspace=workspace;
+ zs.msg=(char*)0;
+ zs.state=(struct zlib_internal_state*)0;
+ zs.data_type=Z_UNKNOWN; /* Imp: do we have to initialize it? */
+ assert(zlib_deflate_workspacesize()+(unsigned)0<sizeof(workspace) && "Flate workspace too small");
+ if (Z_OK!=zlib_deflateInit(&zs, level_))
+ Error::sev(Error::EERROR) << "Flate init error (out of memory?)" << (Error*)0;
+}
+
+void FlateEncode::vi_write(char const*buf, slen_t len) {
+ slen_t got, zgot;
+ /* fprintf(stderr,"wcall\n"); */
+ zs.next_in=(unsigned char*)const_cast<char*>(buf); zs.avail_in=len;
+ if (len==0) { /* flush all output */
+ do { /* SUXX: C compiler should emit a warning: while (1) { ... } while(...); */
+ zs.next_out=(unsigned char*)obuf; zs.avail_out=sizeof(obuf);
+ /* fprintf(stderr,"wdone zai=%d zao=%d\n", zs.avail_in, zs.avail_out); */
+ if (Z_STREAM_END!=(zgot=zlib_deflate(&zs, Z_FINISH)) && Z_OK!=zgot)
+ Error::sev(Error::EERROR) << "Flate close error: " << zs.msg << (Error*)0;
+ got=sizeof(obuf)-zs.avail_out;
+ /* fprintf(stderr, "got=%u zgot=%d Z_OK=%d\n", got, zgot, Z_OK); */
+ if (got>0) out.vi_write(obuf, got);
+ } while (zgot==Z_OK);
+ /* Dat: zlib_deflateEnd() will be called in the destructur */
+ out.vi_write(0,0); /* Signal EOF */
+ /* Dat: zlib_deflate() adds RFC 1950 header and adler32 checksum automatically */
+ } else {
+ do {
+ /* fprintf(stderr,"writ\n"); */
+ zs.next_out=(unsigned char*)obuf; zs.avail_out=sizeof(obuf);
+ if (Z_OK!=zlib_deflate(&zs, 0))
+ Error::sev(Error::EERROR) << "Flate write error: " << zs.msg << (Error*)0;
+ if (0<(got=sizeof(obuf)-zs.avail_out)) out.vi_write(obuf, got);
+ } while (0!=zs.avail_in);
+ }
+}
+#else
+FlateEncode::FlateEncode(GenBuffer::Writable &out_, unsigned level_)
+ :out(out_)
+ ,s1(1)
+ ,s2(0)
+ ,had_header(false) {
+ // assert(!locked); locked /* locking is not necessary anymore */
+ // pts_deflate_init(&fs); /* obsolete */
+ fs=pts_defl_new(
+ /*zpfwrite=*/ gen_write,
+ /*zpfmalloc=*/ gen_malloc,
+ /*zpffree=*/ gen_free,
+ /*pack_level=*/ level_,
+ /*zfile=*/ (void*)&out_
+ );
+ if (fs==NULL) Error::sev(Error::EERROR) << "Flate init error (out of memory?)" << (Error*)0;
+}
+void *FlateEncode::gen_malloc(unsigned n) {
+ return operator new(n);
+ // return new char[n];
+}
+void FlateEncode::gen_free(void *p) {
+ /*return*/ operator delete(p);
+ // delete [] (char*)p;
+}
+
+void FlateEncode::vi_write(char const*buf, slen_t len) {
+ register s_t sold;
+ register char const*p=buf; char const*pend=p+len;
+ (void)sold;
+ if (!had_header) {
+ out.vi_write("\x78\xda",2); /* ZLIB (RFC 1950): max compression header */
+ had_header=true;
+ }
+ if (len==0) { /* EOF: send trailer */
+ fs->deflate2(0,0,fs); /* Let the compressor flush its buffers. */
+ if (fs->err!=0) Error::sev(Error::EERROR) << "Flate compression error" << (Error*)0;
+ fs->delete2(fs);
+ fs=(struct pts_defl_interface*)NULL;
+ if (s1>=65521) s1-=65521;
+ if (s2>=65521) s2-=65521;
+ unsigned char trailer[4];
+ trailer[0]=s2>>8; trailer[1]=s2&255; trailer[2]=s1>>8; trailer[3]=s1&255;
+ out.vi_write((char const*)trailer,4);
+ out.vi_write(0,0); /* Signal EOF */
+ return;
+ }
+ assert(fs!=NULL);
+
+ /* From rfc1950.txt:
+ Adler-32 is composed of two sums accumulated per byte: s1 is
+ the sum of all bytes, s2 is the sum of all s1 values. Both sums
+ are done modulo 65521. s1 is initialized to 1, s2 to zero. The
+ Adler-32 checksum is stored as s2*65536 + s1 in most-
+ significant-byte first (network) order.
+ */
+ /* Update Adler-32 checksum */
+ while (p!=pend) {
+ #if SIZEOF_INT>2
+ if ((s1+=*(unsigned char const*)p)>=65521) s1-=65521;
+ if ((s2+=s1)>=65521) s2-=65521;
+ #elif SIZEOF_SHORT==2
+ sold=s1;
+ if ((s1+=*(unsigned char const*)p))<sold) s1+=15; /* 15==65536-21 */
+ sold=s2;
+ s2=(s2+s1)&0xffff;
+ if ((s2+=s1)<sold) s2+=15;
+ #else
+ /* vvv 0xffff is needed since unsigned short may be > 0..65535 */
+ sold=s1;
+ s1=(s1+*(unsigned char const*)p)&0xffff;
+ if (s1<sold) s1+=15; /* 15==65536-21 */
+ sold=s2;
+ s2=(s2+s1)&0xffff;
+ if (s2<sold) s2+=15;
+ #endif
+ p++;
+ }
+ while (len>=0x8000) { fs->deflate2(const_cast<char*>(buf),0x8000, fs); len-=0x8000; buf+=0x8000; }
+ if (len!=0) fs->deflate2(const_cast<char*>(buf),len, fs);
+}
+#endif /* PTS_DEFL_RIPPED_ZLIB */
+#endif /* USE_BUILTIN_ZIP */
+
+int /*FlateEncode::*/gen_write(char *block, unsigned len, void *zfile) {
+ static_cast<GenBuffer::Writable*>(zfile)->vi_write(block, len);
+ return 0;
+}
+
+
+/* --- */
+
+#if USE_BUILTIN_FAXE
+void* CCITTFaxEncode::gen_xalloc(unsigned n) {
+ return operator new(n);
+ // void *ret; if ((ret=malloc(n))==0) abort(); return ret;
+}
+void CCITTFaxEncode::gen_free(void *ptr) {
+ /*return*/ operator delete(ptr);
+ // free(ptr);
+}
+void CCITTFaxEncode::gen_memset(void *s, int c, unsigned n) {
+ /*return*/ memset(s,c,n);
+}
+void CCITTFaxEncode::gen_memcpy(void *dest, const void *src, unsigned n) {
+ /*return*/ memcpy(dest, src, n);
+}
+CCITTFaxEncode::CCITTFaxEncode(GenBuffer::Writable &out_, slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1): out(out_) {
+ sCFEs.memset_=gen_memset;
+ sCFEs.xalloc_=gen_xalloc;
+ sCFEs.free_=gen_free;
+ sCFEs.memcpy_=gen_memcpy;
+ s_CFE_template.set_defaults((stream_state*)&sCFEs);
+ sCFEs.K=K;
+ sCFEs.Columns=Columns;
+ sCFEs.EndOfLine=EndOfLine;
+ sCFEs.BlackIs1=BlackIs1;
+ const int cf_max_height=(unsigned)-1/2-100; /* Dat: was slen_t */
+ if (sCFEs.K < -cf_max_height || sCFEs.K > cf_max_height /* Dat: .K is an int */
+ || sCFEs.Columns < 0 || sCFEs.Columns > cfe_max_width /* Dat: .Columns is an int */
+ || sCFEs.Rows < 0 || sCFEs.Rows > cf_max_height /* Dat: .Rows is an int */
+ || sCFEs.DamagedRowsBeforeError < 0
+ || sCFEs.DamagedRowsBeforeError > cf_max_height /* Dat: .DamagedRowsBeforeError is an int */
+ || sCFEs.DecodedByteAlign < 1 || sCFEs.DecodedByteAlign > 16
+ || (sCFEs.DecodedByteAlign & (sCFEs.DecodedByteAlign - 1)) != 0
+ ) Error::sev(Error::EERROR) << "pts_fax: invalid params" << (Error*)0;
+ if (0!=s_CFE_template.init((stream_state*)&sCFEs))
+ Error::sev(Error::EERROR) << "pts_fax: init failed" << (Error*)0;
+ #if __CHECKER__
+ memset(&r, 0, sizeof(r));
+ memset(&w, 0, sizeof(w));
+ #endif
+ r.ptr=rlimit=rbuf-1;
+ hard=rbuf+sizeof(rbuf)-1;
+ assert(hard-r.ptr>=(int)s_CFE_template.min_in_size);
+}
+
+void CCITTFaxEncode::vi_write(char const*buf, slen_t len) {
+ int pog;
+ // unsigned char *save_wptr;
+ if (len==0) {
+ r.limit=rlimit;
+ do {
+ w.ptr=wbuf-1;
+ w.limit=wbuf+sizeof(wbuf)-1;
+ assert(w.limit-w.ptr>=(int)s_CFE_template.min_out_size);
+ pog=s_CFE_template.process((stream_state*)&sCFEs, &r, &w, /*last:*/ true);
+ // fprintf(stderr, "pog=%d write=%d last=%d\n", pog, w.ptr-(wbuf-1), true);
+ assert(pog!=PTSFAX_ERRC); /* /CCITTFaxEncode filter must accept any input */
+ assert(pog!=PTSFAX_EOFC); /* /CCITTFaxEncode filter doesn't have EOD markers */
+ if (w.ptr!=wbuf-1) out.vi_write((char const*)wbuf, w.ptr-(wbuf-1));
+ } while (pog==1);
+ s_CFE_template.release((stream_state*)&sCFEs);
+ out.vi_write(0,0); /* propagate EOF */
+ return;
+ }
+
+ while (len!=0) {
+ assert(r.ptr==rbuf-1);
+ assert(hard>rlimit);
+ unsigned clen=hard-rlimit;
+ if (clen>len) clen=len;
+ assert(clen>0);
+ // fprintf(stderr, "clen=%u\n", clen);
+ memcpy(rlimit+1, buf, clen);
+ rlimit+=clen;
+ buf+=clen;
+ len-=clen;
+ /* if (r.ptr==rlimit) break; */
+ r.limit=rlimit;
+ do {
+ w.ptr=wbuf-1;
+ w.limit=wbuf+sizeof(wbuf)-1;
+ assert(w.limit-w.ptr>=(int)s_CFE_template.min_out_size);
+ pog=s_CFE_template.process((stream_state*)&sCFEs, &r, &w, /*last:*/ false);
+ // fprintf(stderr, "len=%d pog=%d write=%d last=%d\n", len, pog, w.ptr-(wbuf-1), false);
+ assert(pog!=PTSFAX_ERRC); /* /CCITTFaxEncode filter must accept any input */
+ assert(pog!=PTSFAX_EOFC); /* /CCITTFaxEncode filter doesn't have EOD markers */
+ if (w.ptr!=wbuf-1) out.vi_write((char const*)wbuf, w.ptr-(wbuf-1));
+ } while (pog==1);
+ // assert(pog!=1); /* not true: output space is enough (sizeof(wbuf)>min_out_size) */
+ assert(pog==0); /* more input is needed */
+ if (r.ptr!=rbuf-1) {
+ // fprintf(stderr, "limit=%d\n", rlimit-r.ptr);
+ memmove(rbuf, r.ptr+1, rlimit-r.ptr);
+ rlimit=rbuf-1+(rlimit-r.ptr);
+ r.ptr=rbuf-1;
+ }
+ }
+ // fprintf(stderr, "done\n");
+}
+#endif /* USE_BUILTIN_FAXE */
+
+/* --- */
+
+#if USE_BUILTIN_LZW
+LZWEncode::LZWEncode(GenBuffer::Writable &out_): out(out_) {
+ fs.tif_writer=/*FlateEncode::*/gen_write;
+ fs.tif_sout=(void*)&out_;
+ if (0==pts_lzw_init(&fs)) Error::sev(Error::EERROR) << "LZW init error" << (Error*)0;
+}
+
+void LZWEncode::vi_write(char const*buf, slen_t len) {
+ /* Imp: report real error _reason_ (if appropriate?? ) */
+ if (len==0) {
+ if (0==fs.tif_feeder(0,0,&fs)) goto we;
+ out.vi_write(0,0); /* propagate EOF */
+ return;
+ }
+ while (len>=0x8000) {
+ if (0==fs.tif_feeder(const_cast<char*>(buf),0x8000,&fs)) we:
+ Error::sev(Error::EERROR) << "LZW write error" << (Error*)0;
+ len-=0x8000; buf+=0x8000;
+ }
+ if (len!=0 && 0==fs.tif_feeder(const_cast<char*>(buf),len,&fs)) goto we;
+}
+#endif /* USE_BUILTIN_LZW */
+
+/* --- */
+
+#if !USE_BUILTIN_LZW
+Lzw_codecEncode::Lzw_codecEncode(GenBuffer::Writable &out_, char const*filter_psname)
+ :p(out_) {
+ (void)filter_psname;
+}
+void Lzw_codecEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
+
+/* Imp: figure out path-to-gs: gs or gswin32c */
+Lzw_codecEncode::P::P(GenBuffer::Writable &out_)
+ // :PipeEncoder(out_, ">/tmp/t cat - cjpeg quality %i", quality), rgbp(rgbp_) {
+ // :Filter::PipeE(out_, "cjpeg -quality %i >%D", quality), rgbp(rgbp_) {
+ :Filter::PipeE(out_, "lzw_codec encode >%D") {}
+#endif
+
+/* --- */
+
+CjpegEncode::CjpegEncode(GenBuffer::Writable &out_, char const*filter_psname, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality)
+ :p(out_, Columns, Rows, rgbp_, quality) {
+ (void)filter_psname;
+}
+void CjpegEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
+
+/* Imp: figure out path-to-gs: gs or gswin32c */
+CjpegEncode::P::P(GenBuffer::Writable &out_, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality)
+ // :PipeEncoder(out_, ">/tmp/t cat - cjpeg quality %i", quality), rgbp(rgbp_) {
+ :Filter::PipeE(out_, "cjpeg -quality %i >%D", quality), rgbp(rgbp_) {
+ /* Dat: we're extremely lucky that cjpeg can read PGM or PPM files from stdin */
+ // operator<<("P5 width height 255\n"); /* RAWBITS PGM */
+ // operator<<("P6 width height 255\n"); /* RAWBITS PPM */
+ *this << (rgbp_?"P6 ":"P5 ") << Columns << ' ' << Rows << " 255\n";
+}
+void CjpegEncode::P::vi_copy(FILE *f) {
+ char r[10];
+ static char jfif[9]="\377\340\000\020JFIF";
+ static unsigned char adobe[16]= {
+ 0xff, /* marker */
+ 0xee, /* APP14 */
+ 0, /* length-hi */
+ 14, /* length-lo */
+ 'A', 'd', 'o', 'b', 'e', /* ID */
+ 1, /* version-hi */
+ 0, /* version-lo */
+ 0, 0, /* flags0 */
+ 0, 0, /* flags1 */
+ 0, /* ColorTransform */
+ };
+ if (MACRO_GETC(f)!=0xff || MACRO_GETC(f)!=0xd8 || fread(r, 1, 8, f)!=8) {
+ bad: Error::sev(Error::EERROR) << "CjpegEncode: cjpeg created bad JPEG" << (Error*)0;
+ }
+ out.vi_putcc((char)0xff);
+ out.vi_putcc((char)0xd8);
+ r[9]=r[3]; r[3]='\020';
+ if ((unsigned char)r[9]>=6 && 0==memcmp(r, jfif, 8)) { /* JFIF marker */
+ r[3]=r[9]; unsigned skip=r[9]-6;
+ out.vi_write(r, 8);
+ while (skip--!=0) out.vi_putcc(MACRO_GETC(f));
+ }
+ if (ferror(f) || feof(f)) goto bad;
+ /* Now we can emit the Adobe marker. */
+ adobe[sizeof(adobe)-1]=rgbp==true; /* ColorTransform value 0 for Gray, 1 for RGB->YCbCr */
+ out.vi_write((char*)adobe, sizeof(adobe));
+ /* vvv Dat: pacify VC6.0: Filter::PipeE::vi_copy(f); doesn't work */
+ PipeE::vi_copy(f);
+ /* ^^^ copy rest of file verbatim */
+ // ((Filter::PipeE)*this).vi_copy(f);
+}
+
+/* --- */
+
+GSEncode::GSEncode(GenBuffer::Writable &out_, char const*filter_psname)
+ :p(out_, filter_psname) {}
+void GSEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
+
+/* Imp: figure out path-to-gs: gs or gswin32c */
+GSEncode::P::P(GenBuffer::Writable &out_, char const*filter_psname)
+ :Filter::PipeE(out_, "gs -s_OFN=%D -dNODISPLAY -q - >%E")
+ {
+ operator<<("{/o _OFN(w)file ");
+ operator<<(filter_psname);
+ operator<<(" filter def/s 4096 string def"
+ "{currentfile s readstring exch o exch writestring not{exit}if}loop "
+ "o closefile quit}bind exec\n");
+}
+void GSEncode::P::vi_check() {
+ /* If STDOUT of gs is not empty, then it is very probably an error message. */
+ // tmpename.term0(); /* already is */
+ assert(tmpename.end_()[0]=='\0');
+ if (0!=Files::statSize(tmpename())) Error::sev(Error::EERROR) << "GSEncode: GS runtime error" << (Error*)0;
+ /* Imp: display a meaningful error message */
+}
+
+/* --- */
+
+PSEncoder* PSEncoder::newASCIIHexEncode(GenBuffer::Writable &out_,unsigned maxcpl_) {
+ // SimBuffer::B fp; (fp << maxcpl_ << " pop/ASCIIHexEncode").term0();
+ // PSEncoder *ret=new GSEncode(out_, fp());
+ PSEncoder *ret=new ASCIIHexEncode(out_,maxcpl_);
+ // ret->shortname="AHx"; ret->longname="ASCIIHex";
+ // ret->filter_psname << fp;
+ return ret;
+}
+PSEncoder* PSEncoder::newASCII85Encode(GenBuffer::Writable &out_,unsigned maxcpl_) {
+ // SimBuffer::B fp; (fp << maxcpl_ << " pop/ASCII85Encode").term0();
+ PSEncoder *ret=new ASCII85Encode(out_,maxcpl_);
+ // PSEncoder *ret=new GSEncode(out_, fp());
+ // ret->shortname="A85"; ret->longname="ASCII85";
+ // ret->filter_psname << fp;
+ return ret;
+}
+PSEncoder* PSEncoder::newCCITTFaxEncode(GenBuffer::Writable &out_,slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1) {
+ #if USE_BUILTIN_FAXE
+ return new CCITTFaxEncode(out_, K, Columns, EndOfLine, BlackIs1);
+ #else
+ // (void)out_; (void)K; (void)Columns;
+ // assert(0 && "unimplemented");
+ SimBuffer::B fp("<< /K ");
+ fp << K << "/Columns " << Columns;
+ if (EndOfLine) fp << "/EndOfLine true"; /* PS default: false */
+ if (BlackIs1) fp << "/BlackIs1 true";
+ (fp << ">>/CCITTFaxEncode").term0();
+ // fprintf(stderr, "fp=(%s)\n", fp());
+ PSEncoder *ret=new GSEncode(out_, fp());
+ // ret->shortname="CCF"; ret->longname="CCITTFax";
+ // ret->filter_psname << fp; /* Dat: this could be made faster */
+ return ret;
+ #endif
+}
+PSEncoder* PSEncoder::newLZWEncode(GenBuffer::Writable &out_) {
+#if USE_BUILTIN_LZW
+ SimBuffer::B fp("/LZWEncode");
+ PSEncoder *ret=new LZWEncode(out_);
+ // PSEncoder *ret=new GSEncode(out_, fp());
+ // ret->shortname="LZW"; ret->longname="LZW";
+ // ret->filter_psname << fp;
+ return ret;
+#else
+ (void)out_;
+ #if 0
+ Error::sev(Error::EERROR) << "LZW not supported in this compilation of sam2p" << (Error*)0;
+ #endif
+ Error::sev(Error::WARNING) << "LZW: please `configure --enable-lzw' for builtin /Compression/LZW support" << (Error*)0;
+ #if 0
+ /* This is useless, because gs 5.50--7.04 have dummy LZW compressor:
+ * it emits a correct LZW stream, but does no real compression, and
+ * the file size is often increased.
+ */
+ PSEncoder *ret=new GSEncode(out_, "/LZWEncode");
+ // ret->shortname="LZW"; ret->longname="LZW";
+ // ret->filter_psname << "/LZWEncode";
+ return ret;
+ #endif
+ #if 1 /* ask lzw_codec from the author of sam2p */
+ return new Lzw_codecEncode(out_, "/LZWEncode");
+ #endif
+ return 0;
+#endif
+}
+PSEncoder* PSEncoder::newFlateEncode(GenBuffer::Writable &out_, signed Effort) {
+ // (void)out_; (void)K; (void)Columns;
+ // assert(0 && "unimplemented");
+ if (Effort==0) {
+ PSEncoder *ret=new FlateStoreEncode(out_);
+ // ret->shortname="Fla"; ret->longname="Flate";
+ // ret->filter_psname << fp;
+ return ret;
+ }
+ if (Effort<1 || Effort>9) Effort=5;
+ #if USE_BUILTIN_ZIP
+ PSEncoder *ret=new FlateEncode(out_, Effort);
+ #else
+ SimBuffer::B fp("<</Effort "); (fp << Effort << ">>/FlateEncode").term0();
+ PSEncoder *ret=new GSEncode(out_, fp());
+ #endif
+ // ret->shortname="Fla"; ret->longname="Flate";
+ // ret->filter_psname << fp;
+ return ret;
+}
+PSEncoder* PSEncoder::newRunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize) {
+ SimBuffer::B fp; (fp << RecordSize << "/RunLengthEncode").term0();
+ PSEncoder *ret=new RunLengthEncode(out_, RecordSize);
+ // PSEncoder *ret=new GSEncode(out_, fp());
+ // ret->shortname="RL"; ret->longname="RunLength";
+ // ret->filter_psname << fp;
+ return ret;
+}
+
+PSEncoder* PSEncoder::newDCTIJGEncode(GenBuffer::Writable &out_,
+ slen_t Columns,
+ slen_t Rows,
+ unsigned char Colors, /*1..4*/
+ unsigned char quality /*libJPEG quality: 0..100 */
+) {
+ /* Dat: this supports only the Gray and RGB color spaces of JPEG */
+ param_assert(Colors==1 || Colors==3);
+ param_assert(/* quality>=0 && */ quality <=100);
+ SimBuffer::B fp("<<IJG ");
+ (fp<< "/Columns " << Columns
+ << "/Rows " << Rows
+ << "/Colors " << (unsigned)Colors
+ << ">>/DCTEncode").term0();
+ /* Dat: the default of /ColorTransform (defined in DCTEncode in
+ subsubsection 3.13.3 in PLRM.pdf) is just perfect. */
+ PSEncoder *ret=new CjpegEncode(out_, fp(), Columns, Rows, Colors==3, quality);
+ // ret->longname=ret->shortname="DCT"; ret->filter_psname << fp;
+ return ret;
+}
+
+PSEncoder* PSEncoder::newDCTEncode(GenBuffer::Writable &out_,
+ slen_t Columns,
+ slen_t Rows,
+ unsigned char Colors, /*1..4*/
+ unsigned char quality, /*libJPEG quality: 0..100 */
+ unsigned char const*HSamples, /*all 1..4, NULLP OK*/
+ unsigned char const*VSamples, /*all 1..4, NULLP OK*/
+ unsigned char (*QuantTables)[64], /*NULLP OK*/
+ double QFactor, /*0..1000000*/
+ unsigned numHuffTables,
+ unsigned char **HuffTables, /*NULLP OK*/
+ unsigned char ColorTransform /*0,1,2 3=default*/
+) {
+ (void)quality;
+ (void)QuantTables;
+ (void)QFactor;
+ (void)numHuffTables;
+ (void)HuffTables;
+ SimBuffer::B tmp;
+ /* Imp: respect quality */
+ /* Imp: respect QFactor (double) */
+ /* Imp: respect QuantTables */
+ /* Imp: respect numHuffTables, HuffTables */
+
+ SimBuffer::B fp("<<");
+ fp << "/Columns " << Columns
+ << "/Rows " << Rows
+ << "/Colors " << (unsigned)Colors;
+ if (HSamples!=(unsigned char const*)NULLP) {
+ tmp.clear(); tmp.vi_write((char const*)HSamples, (unsigned)Colors);
+ fp << "/HSamples "; fp.appendDumpPS(tmp,true);
+ }
+ if (VSamples!=(unsigned char const*)NULLP) {
+ tmp.clear(); tmp.vi_write((char const*)VSamples, (unsigned)Colors);
+ fp << "/VSamples "; fp.appendDumpPS(tmp,true);
+ }
+ if (ColorTransform!=3) fp << "/ColorTransform " << (unsigned)ColorTransform;
+ (fp << ">>/DCTEncode").term0();
+
+ // PSEncoder *ret=new DCTEncode(out_,? ? ?);
+ PSEncoder *ret=new GSEncode(out_, fp());
+ // ret->shortname="DCT"; ret->longname="DCT";
+ // ret->filter_psname << fp;
+ return ret;
+}
+
+PSEncoder* PSEncoder::newDCTEncode(GenBuffer::Writable &out_,
+ slen_t Columns,
+ slen_t Rows,
+ unsigned char Colors, /*1..4*/
+ unsigned char ColorTransform, /*0,1,2 3=default*/
+ SimBuffer::Flat const& other_parameters
+) {
+ SimBuffer::B fp("<<");
+ fp << "/Columns " << Columns
+ << "/Rows " << Rows
+ << "/Colors " << (unsigned)Colors;
+ if (ColorTransform!=3) fp << "/ColorTransform " << (unsigned)ColorTransform;
+ (fp << other_parameters << ">>/DCTEncode").term0();
+ PSEncoder *ret=new GSEncode(out_, fp());
+ // ret->shortname="DCT"; ret->longname="DCT";
+ // ret->filter_psname << fp;
+ return ret;
+}
+
+/* --- */
+
+TIFFPredictor2::TIFFPredictor2(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), bpc(bpc_), cpp(cpp_), out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ rlen=(columns_*cpp_*bpc_+7)>>3; /* BUGFIX at Tue Mar 12 12:09:51 CET 2002 */
+ op=obuf=new unsigned char[rlen];
+}
+
+void TIFFPredictor2::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ slen_t opleft=rlen-(op-obuf);
+ register unsigned int i, d, o, bpccpp;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] obuf;
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ bpccpp=(cpp-1)*bpc;
+ if (bpc==1) {
+ while (p!=pend0) {
+ i=*p++;
+ d=(i>>7); o =((d-((h>>bpccpp)))&1)<<7; h=(h<<1)|d;
+ d=(i>>6); o|=((d-((h>>bpccpp)))&1)<<6; h=(h<<1)|d;
+ d=(i>>5); o|=((d-((h>>bpccpp)))&1)<<5; h=(h<<1)|d;
+ d=(i>>4); o|=((d-((h>>bpccpp)))&1)<<4; h=(h<<1)|d;
+ d=(i>>3); o|=((d-((h>>bpccpp)))&1)<<3; h=(h<<1)|d;
+ d=(i>>2); o|=((d-((h>>bpccpp)))&1)<<2; h=(h<<1)|d;
+ d=(i>>1); o|=((d-((h>>bpccpp)))&1)<<1; h=(h<<1)|d;
+ d=(i ); o|=((d-((h>>bpccpp)))&1) ; h=(h<<1)|d;
+ *op++=o;
+ if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
+ }
+ } else if (bpc==2) {
+ while (p!=pend0) {
+ i=*p++;
+ d=(i>>6); o =((d-((h>>bpccpp)))&3)<<6; h=(h<<2)|d; // fprintf(stderr,"d=%#x\n", d);
+ d=(i>>4); o|=((d-((h>>bpccpp)))&3)<<4; h=(h<<2)|d;
+ d=(i>>2); o|=((d-((h>>bpccpp)))&3)<<2; h=(h<<2)|d;
+ d=(i ); o|=((d-((h>>bpccpp)))&3) ; h=(h<<2)|d;
+ *op++=o;
+ if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
+ }
+ } else if (bpc==4) {
+ while (p!=pend0) {
+ i=*p++;
+ d=(i>>4); o =((d-((h>>bpccpp)))&15)<<4; h=(h<<4)|d;
+ d=(i ); o|=((d-((h>>bpccpp)))&15) ; h=(h<<4)|d;
+ *op++=o;
+ if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
+ }
+ } else if (bpc==8) {
+ while (p!=pend0) {
+ i=*p++; *op++=((i-((h>>bpccpp)))/*&255*/); h=(h<<8)|i;
+ if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
+ }
+ } else assert(0);
+}
+
+/* --- */
+
+PNGPredictorNone::PNGPredictorNone(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : opleft(0), out(out_) {
+ rlen=(columns_*cpp_*bpc_+7)>>3;
+}
+
+void PNGPredictorNone::vi_write(char const*buf, slen_t len) {
+ if (len==0) {
+ assert(opleft==0); /* unflushed (half-ready) row disallowed */
+ out.vi_write(0,0);
+ return;
+ }
+ /* The following code just inserts a '\0' in front of each scanline */
+ /* Imp: make it faster by collapsing vi_writes */
+ if (opleft==0) { opleft=rlen; out.vi_write("\0",1); } /* Scanline (row) header: describes predictor used */
+ while (len>opleft) {
+ out.vi_write(buf,opleft);
+ buf+=opleft; len-=opleft;
+ opleft=rlen; out.vi_write("\0",1); /* Scanline (row) header: describes predictor used */
+ }
+ if (len!=0) out.vi_write(buf,len);
+ opleft-=len;
+}
+
+/* --- */
+
+PNGPredictorSub::PNGPredictorSub(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ rlen=(columns_*cpp_*bpc_+7)>>3;
+ op=obuf=1+new unsigned char[rlen+1];
+ obuf[-1]='\1'; /* Scanline (row) header: describes predictor used */
+ bpccpp=((cpp_*bpc_+7)&~7)-8;
+}
+
+void PNGPredictorSub::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ slen_t opleft=rlen-(op-obuf);
+ register unsigned int i;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] (obuf-1);
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ while (p!=pend0) {
+ i=*p++; *op++=((i-((h>>bpccpp)))/*&255*/); h=(h<<8)|i;
+ if (--opleft==0) { h=0;
+ out.vi_write((char*)obuf-1,rlen+1); op=obuf; opleft=rlen;
+ }
+ }
+}
+
+/* --- */
+
+PNGPredictorUp::PNGPredictorUp(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : out(out_) {
+ rlen=(columns_*cpp_*bpc_+7)>>3;
+ // fprintf(stderr, "rUp.rlen=%u cpp=%u bpc=%u\n", rlen, cpp_, bpc_);
+ op=obuf=1+new unsigned char[2*rlen+1];
+ oq=op+rlen; /* prev scanline */
+ memset(oq, '\0', rlen);
+ obuf[-1]='\2'; /* Scanline (row) header: describes predictor used */
+}
+
+void PNGPredictorUp::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ slen_t opleft=rlen-(op-obuf);
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] (obuf-1);
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ while (p!=pend0) {
+ *op++=((*p-*oq)/*&255*/); *oq++=*p++;
+ if (--opleft==0) {
+ out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
+ op=obuf; oq=obuf+rlen;
+ }
+ }
+}
+
+/* --- */
+
+PNGPredictorAverage::PNGPredictorAverage(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), /*g(0),*/ out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ rlen=(columns_*cpp_*bpc_+7)>>3;
+ op=obuf=1+new unsigned char[2*rlen+1];
+ oq=op+rlen; /* prev scanline */
+ memset(oq, '\0', rlen);
+ obuf[-1]='\3'; /* Scanline (row) header: describes predictor used */
+ bpccpp=((cpp_*bpc_+7)&~7)-8;
+}
+
+void PNGPredictorAverage::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ slen_t opleft=rlen-(op-obuf);
+ register unsigned int i;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] (obuf-1);
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ while (p!=pend0) {
+ /* vvv Data: *og+h can be 0..510 */
+ i=*p; *op++=i-((((h>>bpccpp)&255)+*oq)>>1); h=(h<<8)|i; *oq++=*p++;
+ // i=*p; *op++=(*p-((*oq+h)>>1)/*&255*/); h=i; *oq++=*p++;
+ if (--opleft==0) {
+ out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
+ op=obuf; oq=obuf+rlen; h=0;
+ }
+ }
+}
+
+/* --- */
+
+/* Dat: egcs-2.91.60 is buggy */
+// static inline unsigned abs_(unsigned i) { return ((signed)i)<0 ? -i : i; }
+static inline unsigned abs_(unsigned i) { return ((signed)i)<0 ? (i*-1) : i; }
+
+static inline unsigned paeth_predictor(unsigned a, unsigned b, unsigned c) {
+ /* Code ripped from RFC 2083 (PNG specification), which also says:
+ * The calculations within the PaethPredictor function must be
+ * performed exactly, without overflow. Arithmetic modulo 256 is to
+ * be used only for the final step of subtracting the function result
+ * from the target byte value.
+ */
+ /* a = left, b = above, c = upper left */
+ unsigned p = a + b - c; /* initial estimate */
+ unsigned pa = abs_(p - a); /* distances to a, b, c */
+ unsigned pb = abs_(p - b);
+ unsigned pc = abs_(p - c);
+ // assert(abs_(3*(-1))==3);
+ // fprintf(stderr, "b=%u c=%u %d %d\n", b, c, p-b, ((signed)(p-b))<0 ? (b-p) : (p-b) );
+ // fprintf(stderr, "pa=%u pb=%u pc=%u\n", pa, pb, pc);
+ assert(pa<=255);
+ assert(pb<=255);
+ assert(pc<=255*2);
+ /* return nearest of a,b,c, breaking ties in order a,b,c. */
+ return (pa <= pb && pa <= pc) ? a
+ : pb <= pc ? b
+ : c;
+}
+
+PNGPredictorPaeth::PNGPredictorPaeth(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), g(0), out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ rlen=(columns_*cpp_*bpc_+7)>>3;
+ op=obuf=1+new unsigned char[2*rlen+2];
+ oq=obuf+rlen+1; /* prev scanline */
+ memset(obuf+rlen, '\0', rlen+1);
+ obuf[-1]='\4'; /* Scanline (row) header: describes predictor used */
+ bpccpp=((cpp_*bpc_+7)&~7)-8;
+}
+
+void PNGPredictorPaeth::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ slen_t opleft=rlen-(op-obuf);
+ register unsigned int i;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] (obuf-1);
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ while (p!=pend0) {
+ // assert(0==obuf[rlen] && 4==obuf[-1]);
+ i=*p; *op++=i-paeth_predictor((h>>bpccpp)&255, *oq, (g>>bpccpp)&255);
+ h=(h<<8)|i; g=(g<<8)|*oq; *oq++=*p++;
+ // i=*p; *op++=i-h; h=i; *oq++=*p++;
+ if (--opleft==0) {
+ out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
+ op=obuf; oq=obuf+rlen+1; h=0; g=0;
+ }
+ }
+}
+
+/* --- */
+
+#if SIZEOF_INT >= 4
+typedef int weight_t;
+#else
+typedef long weight_t;
+#endif
+
+PNGPredictorAutoBadSigned::PNGPredictorAutoBadSigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), g(0), out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
+ obuf=new unsigned char[6*rlen+6];
+ o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
+ obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
+ obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
+ obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
+ obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
+ obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
+ oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
+ memset(obuf, '\0', rlen+1);
+ bpccpp=((cpp_*bpc_+7)&~7)-8;
+}
+
+void PNGPredictorAutoBadSigned::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ register unsigned int i;
+ register unsigned raw_x_bpp, prior_x, prior_x_bpp;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] obuf;
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ while (p!=pend0) {
+ raw_x_bpp=(h>>bpccpp) &255;
+ prior_x=*(o_prior-opleft);
+ prior_x_bpp=(g>>bpccpp) &255;
+ i=*p;
+ *(o_0-opleft)=i;
+ *(o_1-opleft)=i-raw_x_bpp;
+ *(o_2-opleft)=i-prior_x;
+ *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
+ *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
+ h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
+ if (--opleft==0) {
+ /* Select the predictor having the smallest signed sum of values. */
+ weight_t min_weight, cur_weight;
+ unsigned min_pred=0, cur_pred;
+ register signed char *beg, *end;
+ min_weight=0; beg=(end=(signed char*)o_0)-rlen; while (beg!=end) min_weight+=*beg++;
+ if (min_weight<0) min_weight*=-1;
+ for (cur_pred=1; cur_pred<=4; cur_pred++) {
+ cur_weight=0; beg=(end=(signed char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=*beg++;
+ if (cur_weight<0) cur_weight*=-1;
+ if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
+ }
+ // fprintf(stderr, "cp=%u\n", min_pred);
+
+ out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
+ opleft=rlen; h=0; g=0;
+ }
+ }
+}
+
+/* --- */
+
+PNGPredictorAutoBadUnsigned::PNGPredictorAutoBadUnsigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), g(0), out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
+ obuf=new unsigned char[6*rlen+6];
+ o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
+ obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
+ obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
+ obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
+ obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
+ obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
+ oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
+ memset(obuf, '\0', rlen+1);
+ bpccpp=((cpp_*bpc_+7)&~7)-8;
+}
+
+void PNGPredictorAutoBadUnsigned::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ register unsigned int i;
+ register unsigned raw_x_bpp, prior_x, prior_x_bpp;
+ // unsigned lines=0;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] obuf;
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ // fprintf(stderr, "rlen=%u len=%u opleft=%u\n", rlen, len, opleft);
+ while (p!=pend0) {
+ raw_x_bpp=(h>>bpccpp) &255;
+ prior_x=*(o_prior-opleft);
+ prior_x_bpp=(g>>bpccpp) &255;
+ i=*p;
+ *(o_0-opleft)=i;
+ *(o_1-opleft)=i-raw_x_bpp;
+ *(o_2-opleft)=i-prior_x;
+ *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
+ *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
+ h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
+ if (--opleft==0) {
+ /* Select the predictor having the smallest unsigned sum of values. */
+ weight_t min_weight, cur_weight;
+ unsigned min_pred=0, cur_pred;
+ register unsigned char *beg, *end;
+ min_weight=0; beg=(end=(unsigned char*)o_0)-rlen; while (beg!=end) min_weight+=*beg++;
+ for (cur_pred=1; cur_pred<=4; cur_pred++) {
+ cur_weight=0; beg=(end=(unsigned char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=*beg++;
+ if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
+ }
+ // fprintf(stderr, "cp=%u\n", min_pred);
+
+ out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
+ opleft=rlen; h=0; g=0;
+ // lines++;
+ }
+ }
+ // fprintf(stderr, "oen=%u opleft=%u lines=%u\n", len, opleft, lines);
+}
+
+/* --- */
+
+PNGPredictorAuto::PNGPredictorAuto(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
+ : h(0), g(0), out(out_) {
+ param_assert(cpp_*bpc_<=32);
+ opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
+ obuf=new unsigned char[6*rlen+6];
+ o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
+ obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
+ obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
+ obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
+ obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
+ obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
+ oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
+ memset(obuf, '\0', rlen+1);
+ bpccpp=((cpp_*bpc_+7)&~7)-8;
+}
+
+void PNGPredictorAuto::vi_write(char const*buf, slen_t len) {
+ unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
+ register unsigned int i;
+ register unsigned raw_x_bpp, prior_x, prior_x_bpp;
+ // unsigned lines=0;
+ if (len==0) {
+ assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
+ assert(obuf!=NULLP);
+ delete [] obuf;
+ obuf=(unsigned char*)NULLP;
+ out.vi_write(0,0);
+ return;
+ }
+ // fprintf(stderr, "rlen=%u len=%u opleft=%u\n", rlen, len, opleft);
+ while (p!=pend0) {
+ raw_x_bpp=(h>>bpccpp) &255;
+ prior_x=*(o_prior-opleft);
+ prior_x_bpp=(g>>bpccpp) &255;
+ i=*p;
+ *(o_0-opleft)=i;
+ *(o_1-opleft)=i-raw_x_bpp;
+ *(o_2-opleft)=i-prior_x;
+ *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
+ *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
+ h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
+ if (--opleft==0) {
+ /* Select the predictor having the smallest unsigned sum of values. */
+ weight_t min_weight, cur_weight;
+ unsigned min_pred=0, cur_pred;
+ register signed char *beg, *end;
+ /* abs_(...) here converts '\xFF' to 1. Good. */
+ min_weight=0; beg=(end=(signed char*)o_0)-rlen; while (beg!=end) min_weight+=abs_(*beg++);
+ for (cur_pred=1; cur_pred<=4; cur_pred++) {
+ cur_weight=0; beg=(end=(signed char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=abs_(*beg++);
+ if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
+ }
+ // fprintf(stderr, "cp=%u\n", min_pred);
+
+ out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
+ opleft=rlen; h=0; g=0;
+ // lines++;
+ }
+ }
+ // fprintf(stderr, "oen=%u opleft=%u lines=%u\n", len, opleft, lines);
+}
+
+/* --- */
+
+Encoder* PSEncoder::newPredictor(GenBuffer::Writable &out_, unsigned char type, unsigned char bpc_, slen_t columns_, unsigned char cpp_) {
+ switch ((unsigned)type) {
+ /* Imp: make these faster with `register int' etc. tricks */
+ /* See also better_predictor in rule.cpp for the list of predictor numbers */
+ case 1: return new Filter::VerbatimE(out_);
+ case 2: return new TIFFPredictor2(out_, bpc_, columns_, cpp_);
+ case 10: return new PNGPredictorNone(out_, bpc_, columns_, cpp_);
+ case 11: return new PNGPredictorSub(out_, bpc_, columns_, cpp_);
+ case 12: return new PNGPredictorUp(out_, bpc_, columns_, cpp_);
+ case 13: return new PNGPredictorAverage(out_, bpc_, columns_, cpp_);
+ case 14: return new PNGPredictorPaeth(out_, bpc_, columns_, cpp_);
+ case 15: return new PNGPredictorAuto(out_, bpc_, columns_, cpp_);
+ case 45: return new PNGPredictorAutoBadUnsigned(out_, bpc_, columns_, cpp_); /* pts' extension */
+ case 55: return new PNGPredictorAutoBadSigned(out_, bpc_, columns_, cpp_); /* pts' extension */
+ }
+ // fprintf(stderr, "pred=%d\n", type);
+ param_assert(0 && "invalid predictor requested");
+ return (Encoder*)0; /*notreached*/
+}
+
+/* __END__ */