1 /* encoder.cpp -- various PostScript and PDF encoding filter implementations
2 * by pts@fazekas.hu at Sun Mar 3 14:16:00 CET 2002
3 * --- Mon Mar 4 00:00:20 CET 2002
4 */
5
6 /* Imp: make built-in FlateEncode DYNALLOC */
7 /* Imp: add lzw_codec */
8 /* Imp: add gzip */
9 /* Imp: add zlib */
10
11 #ifdef __GNUC__
12 #ifndef __clang__
13 #pragma implementation
14 #endif
15 #endif
16
17
18 #include "encoder.hpp"
19 #include "error.hpp"
20 #include "gensio.hpp"
21 #include <stdlib.h> /* getenv() */
22 #include <string.h>
23
24 /* --- */
25
26 /** Does output EOD (end-of-data) marker `>' */
27 class ASCIIHexEncode: public PSEncoder {
28 public:
29 /** @param maxcpl_: maximum # hex digits per line, should be even */
30 ASCIIHexEncode(GenBuffer::Writable &out_, unsigned maxcpl_);
31 virtual void vi_write(char const*buf, slen_t len);
32 protected:
33 unsigned maxcpl;
34 /** Number of hex digits already printed. */
35 unsigned curcpl;
36 GenBuffer::Writable &out;
37 };
38
39 /** Does output EOD (end-of-data) marker `~>' */
40 class ASCII85Encode: public PSEncoder {
41 public:
42 /** @param maxcpl_: maximum # hex digits per line, should be even */
43 ASCII85Encode(GenBuffer::Writable &out_, unsigned maxcpl_);
44 virtual void vi_write(char const*buf, slen_t len);
45
46 protected:
47 void wencoded(char const *encoded);
48 void wout(unsigned PTS_INT32_T buf_);
49 unsigned maxcpl;
50 /** Number of digits available in this line */
51 GenBuffer::Writable &out;
52 unsigned ascii85breaklen;
53 unsigned ascii85left;
54 unsigned PTS_INT32_T ascii85buf;
55 char *obuf, *obufend, *op;
56 char dscst; /* For converting `%%' to `% %' to avoid DSC parser errors */
57 };
58
59 /** Doesn't output EOD (end-of-data) marker `>' */
60 class RunLengthEncode: public PSEncoder {
61 public:
62 /** @param maxcpl_: maximum # hex digits per line, should be even */
63 RunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize_);
64 virtual void vi_write(char const*buf, slen_t len);
65
66 protected:
67 slen_t recordsize;
68 GenBuffer::Writable &out;
69 // char *obuf, *obufend, *op;
70 slen_t record_left;
71 unsigned saved_c, saved_rep;
72 /** size == header+buffer+EOD */
73 char saved[130];
74 };
75
76 static int gen_write(char *block, unsigned len, void *zfile);
77
78 #if USE_BUILTIN_ZIP
79 #include "pts_defl.h" /* Imp: because pts_defl_interface :-( */
80 #if OBJDEP
81 # warning REQUIRES: pts_defl
82 #endif
83 class FlateEncode: public PSEncoder {
84 #if PTS_DEFL_RIPPED_ZLIB /* Dat: defined in pts_defl.h */
85 public:
86 /** @param level: 1..9: 9==highest compression */
87 FlateEncode(GenBuffer::Writable &out_, unsigned level_);
~FlateEncode()88 virtual ~FlateEncode() { zlib_deflateEnd(&zs); } /* Dat: ==Z_OK check (for unflushed buffers) omitted */
89 virtual void vi_write(char const*buf, slen_t len);
90 protected:
91 /** Formerly only one instance of FlateEncode was allowed.
92 * It exists <=> loced==true
93 */
94 // static bool locked;
95 /** Writable that this filter writes to */
96 GenBuffer::Writable &out;
97 char workspace[ZLIB_DEFLATE_WORKSPACESIZE_MIN]; /* big, about 270k */
98 char obuf[4096];
99 /*struct*/ z_stream zs;
100 #else /* old, ripped from Info-ZIP 2.2 */
101 public:
102 /** @param level: 1..9: 9==highest compression */
103 FlateEncode(GenBuffer::Writable &out_, unsigned level_);
104 virtual ~FlateEncode() { if (fs!=NULLP) fs->delete2(fs); }
105 virtual void vi_write(char const*buf, slen_t len);
106 static void *gen_malloc(unsigned n);
107 static void gen_free(void *p);
108 protected:
109 /** Formerly only one instance of FlateEncode was allowed.
110 * It exists <=> loced==true
111 */
112 // static bool locked;
113 /** Writable that this filter writes to */
114 GenBuffer::Writable &out;
115 #if SIZEOF_INT>2
116 typedef unsigned s_t;
117 #else
118 typedef unsigned short s_t;
119 #endif
120 /** Adler32 checksum */
121 s_t s1, s2;
122 bool had_header;
123 struct pts_defl_interface* fs;
124 #endif /* else PTS_DEFL_RIPPED_ZLIB */
125 };
126 #endif
127
128 /** Just store the data in Flate (ZLIB) format, no real compression. Adds
129 * about 3 bytes of overhead per 65535 bytes (compression ratio:
130 * 100.004578%)
131 */
132 class FlateStoreEncode: public PSEncoder {
133 public:
134 /** @param level: 1..9: 9==highest compression */
135 FlateStoreEncode(GenBuffer::Writable &out_);
~FlateStoreEncode()136 inline virtual ~FlateStoreEncode() {}
137 virtual void vi_write(char const*buf, slen_t len);
138 protected:
139 GenBuffer::Writable &out;
140 #if SIZEOF_INT>2
141 typedef unsigned s_t;
142 #else
143 typedef unsigned short s_t;
144 #endif
145 /** Adler32 checksum */
146 s_t s1, s2;
147 bool had_header;
148 /** Number of bytes already in buf */
149 unsigned abuflen;
150 /** Max: 65535 */
151 #if HAVE_STATIC_CONST
152 static const unsigned ABUFSIZE=65535;
153 #else
154 #define ABUFSIZE 65535
155 #endif
156 /** Should really not allocate a FlateStoreEncode on the stack. */
157 char abuf[ABUFSIZE+5];
158 };
159
160 #if USE_BUILTIN_FAXE
161
162 #include "pts_fax.h"
163 #if OBJDEP
164 # warning REQUIRES: pts_faxe
165 #endif
166 class CCITTFaxEncode: public PSEncoder {
167 public:
168 CCITTFaxEncode(GenBuffer::Writable &out_, slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1);
169 virtual void vi_write(char const*buf, slen_t len);
170 protected:
171 GenBuffer::Writable &out;
172 stream_CFE_state sCFEs;
173 unsigned char rbuf[4096];
174 unsigned char wbuf[4096];
175 stream_cursor_read r;
176 stream_cursor_write w;
177 unsigned char *hard, *rlimit;
178
179 static void*gen_xalloc(unsigned n);
180 static void gen_free(void *ptr);
181 static void gen_memset(void *s, int c, unsigned n);
182 static void gen_memcpy(void *dest, const void *src, unsigned n);
183 };
184 #endif
185
186 #if USE_BUILTIN_LZW
187 #include "pts_lzw.h" /* Imp: because pts_lzw_state :-( */
188 #if OBJDEP
189 # warning REQUIRES: pts_lzw
190 #endif
191 class LZWEncode: public PSEncoder {
192 public:
193 LZWEncode(GenBuffer::Writable &out_);
194 virtual void vi_write(char const*buf, slen_t len);
195 protected:
196 GenBuffer::Writable &out;
197 struct pts_lzw_state fs;
198 };
199 #endif
200
201 /**
202 * Reporting of GS errors is somewhat dump: the actual message isn't reported,
203 * only the fact that something went wrong.
204 * Imp: force a no-error trailer output by gs, and check that
205 */
206 class GSEncode: public PSEncoder {
207 public:
208 /** @param filter_psname is a full-featured PostScript *Encode filter
209 * specification string, for example: "<</Effort 5>>/FlateEncode" or
210 * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
211 * `currentfile ... filter'
212 */
213 GSEncode(GenBuffer::Writable &out_, char const*filter_psname);
~GSEncode()214 inline virtual ~GSEncode() {}
215 /* vvv Imp: correct these */
216 virtual void vi_write(char const*buf, slen_t len);
217 protected:
218 class P: public Filter::PipeE {
219 protected: virtual void vi_check();
220 public: P(GenBuffer::Writable &out_, char const*filter_psname);
221 };
222 /** We need this delegator because `delete ...' won't work with multiple
223 * inheritance. (?? )
224 */
225 P p;
226 };
227
228 class CjpegEncode: public PSEncoder {
229 public:
230 /** @param filter_psname is a full-featured PostScript *Encode filter
231 * specification string, for example: "<</Effort 5>>/FlateEncode" or
232 * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
233 * `currentfile ... filter'
234 */
235 CjpegEncode(GenBuffer::Writable &out_, char const*filter_psname, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality);
~CjpegEncode()236 inline virtual ~CjpegEncode() {}
237 virtual void vi_write(char const*buf, slen_t len);
238 protected:
239 class P: public Filter::PipeE { public:
240 // protected: virtual void vi_check();
241 P(GenBuffer::Writable &out_, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality);
242 protected: /* Not needed: protected -> public: pacify VC6.0 */
243 virtual void vi_copy(FILE *f);
244 bool rgbp;
245 };
246 /** We need this delegator because `delete ...' won't work with multiple
247 * inheritance. (?? )
248 */
249 P p;
250 };
251
252 #if !USE_BUILTIN_LZW
253 class Lzw_codecEncode: public PSEncoder {
254 public:
255 /** @param filter_psname is a full-featured PostScript *Encode filter
256 * specification string, for example: "<</Effort 5>>/FlateEncode" or
257 * "0/RunLengthEncode" or "72 pop/ASCIIHexEncode"; will be surrounded as
258 * `currentfile ... filter'
259 */
260 Lzw_codecEncode(GenBuffer::Writable &out_, char const*filter_psname);
~Lzw_codecEncode()261 inline virtual ~Lzw_codecEncode() {}
262 virtual void vi_write(char const*buf, slen_t len);
263 protected:
264 class P: public Filter::PipeE { public:
265 // protected: virtual void vi_check();
266 P(GenBuffer::Writable &out_);
267 protected:
268 // virtual void vi_copy(FILE *f);
269 };
270 /** We need this delegator because `delete ...' won't work with multiple
271 * inheritance. (?? )
272 */
273 P p;
274 };
275 #endif
276
277 class TIFFPredictor2: public Encoder {
278 public:
279 /** @param maxcpl_: maximum # hex digits per line, should be even */
280 TIFFPredictor2(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
281 virtual void vi_write(char const*buf, slen_t len);
282 protected:
283 unsigned PTS_INT32_T h;
284 unsigned char *obuf, *op, bpc, cpp;
285 slen_t rlen;
286 GenBuffer::Writable &out;
287 };
288
289 class PNGPredictorNone: public Encoder {
290 public:
291 /** @param maxcpl_: maximum # hex digits per line, should be even */
292 PNGPredictorNone(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
293 virtual void vi_write(char const*buf, slen_t len);
294 protected:
295 slen_t rlen, opleft;
296 GenBuffer::Writable &out;
297 };
298
299 class PNGPredictorSub: public Encoder {
300 public:
301 /** @param maxcpl_: maximum # hex digits per line, should be even */
302 PNGPredictorSub(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
303 virtual void vi_write(char const*buf, slen_t len);
304 protected:
305 unsigned PTS_INT32_T h;
306 unsigned char *obuf, *op;
307 slen_t rlen;
308 GenBuffer::Writable &out;
309 unsigned char bpccpp;
310 };
311
312 class PNGPredictorUp: public Encoder {
313 public:
314 /** @param maxcpl_: maximum # hex digits per line, should be even */
315 PNGPredictorUp(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
316 virtual void vi_write(char const*buf, slen_t len);
317 protected:
318 unsigned char *obuf, *op, *oq;
319 slen_t rlen;
320 GenBuffer::Writable &out;
321 };
322
323 class PNGPredictorAverage: public Encoder {
324 public:
325 /** @param maxcpl_: maximum # hex digits per line, should be even */
326 PNGPredictorAverage(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
327 virtual void vi_write(char const*buf, slen_t len);
328 protected:
329 unsigned PTS_INT32_T h/*, g*/;
330 unsigned char *obuf, *op, *oq;
331 slen_t rlen;
332 GenBuffer::Writable &out;
333 unsigned char bpccpp;
334 };
335
336 class PNGPredictorPaeth: public Encoder {
337 public:
338 /** @param maxcpl_: maximum # hex digits per line, should be even */
339 PNGPredictorPaeth(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
340 virtual void vi_write(char const*buf, slen_t len);
341 protected:
342 unsigned PTS_INT32_T h, g;
343 unsigned char *obuf, *op, *oq;
344 slen_t rlen;
345 GenBuffer::Writable &out;
346 unsigned char bpccpp;
347 };
348
349 /** This class implements inferior predictor autoselection heuristics.
350 * Please use PNGPredictorAuto instead.
351 * Imp: code reuse with PNGPredictorAuto
352 */
353 class PNGPredictorAutoBadSigned: public Encoder {
354 public:
355 /** @param maxcpl_: maximum # hex digits per line, should be even */
356 PNGPredictorAutoBadSigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
357 virtual void vi_write(char const*buf, slen_t len);
358 protected:
359 unsigned PTS_INT32_T h, g;
360 unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
361 slen_t rlen;
362 GenBuffer::Writable &out;
363 unsigned char bpccpp;
364 slen_t opleft;
365 };
366
367 /** This class implements inferior predictor autoselection heuristics.
368 * Please use PNGPredictorAuto instead.
369 * Imp: code reuse with PNGPredictorAuto
370 */
371 class PNGPredictorAutoBadUnsigned: public Encoder {
372 public:
373 /** @param maxcpl_: maximum # hex digits per line, should be even */
374 PNGPredictorAutoBadUnsigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
375 virtual void vi_write(char const*buf, slen_t len);
376 protected:
377 unsigned PTS_INT32_T h, g;
378 unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
379 slen_t rlen;
380 GenBuffer::Writable &out;
381 unsigned char bpccpp;
382 slen_t opleft;
383 };
384
385 /** This class implements to so-called ``minimum sum of absolute differences''
386 * predictior autoselection heuristics, the same as what pngwutil.c
387 * contains in function png_write_find_filter() in libpng 1.2.20. (See that
388 * function for a discussion of other heuristics. A summary of this heuristics:
389 * we find which method provides the smallest value when summing the absolute
390 * values of the distances from zero, using anything >= 128 as negative
391 * numbers.
392 */
393 class PNGPredictorAuto: public Encoder {
394 public:
395 /** @param maxcpl_: maximum # hex digits per line, should be even */
396 PNGPredictorAuto(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_);
397 virtual void vi_write(char const*buf, slen_t len);
398 protected:
399 unsigned PTS_INT32_T h, g;
400 unsigned char *obuf, *o_prior, *o_0, *o_1, *o_2, *o_3, *o_4, *oo[5];
401 slen_t rlen;
402 GenBuffer::Writable &out;
403 unsigned char bpccpp;
404 slen_t opleft;
405 };
406
407 /* --- */
408
FlateStoreEncode(GenBuffer::Writable & out_)409 FlateStoreEncode::FlateStoreEncode(GenBuffer::Writable &out_)
410 :out(out_)
411 ,s1(1)
412 ,s2(0)
413 ,had_header(false)
414 ,abuflen(0)
415 {}
416
417 #if 0
418 /** 0x7801: ZLIB header signaling fastest compression
419 * 0: 2 bits: DEFLATE block header signaling stored (uncompressed) block +
420 * 6 bits of padding.
421 */
422 char FlateStoreEncode::header[3]= { 0x78, 1, 0 };
423 #endif
424
vi_write(char const * buf,slen_t len)425 void FlateStoreEncode::vi_write(char const*buf, slen_t len) {
426 register s_t sold;
427 register char const*p=buf; char const*pend=p+len;
428 (void)sold;
429 if (len==0) { /* EOF: flush and send trailer */
430 /* Dat: Last block has to be written even if it's empty. */
431 if (!had_header) { out.vi_write("\x78\x01", 2); had_header=true; }
432 abuf[0]=(char)1; /* Last, stored block with padding */
433 abuf[1]=abuflen; abuf[2]=abuflen>>8;
434 abuf[3]=~(abuflen); abuf[4]=~(abuflen>>8);
435 out.vi_write(abuf, abuflen+5);
436 if (s1>=65521) s1-=65521;
437 if (s2>=65521) s2-=65521;
438 unsigned char trailer[4];
439 trailer[0]=s2>>8; trailer[1]=s2&255; trailer[2]=s1>>8; trailer[3]=s1&255;
440 out.vi_write((char const*)trailer,4);
441 out.vi_write(0,0); /* Signal EOF */
442 return;
443 }
444 /* From rfc1950.txt:
445 Adler-32 is composed of two sums accumulated per byte: s1 is
446 the sum of all bytes, s2 is the sum of all s1 values. Both sums
447 are done modulo 65521. s1 is initialized to 1, s2 to zero. The
448 Adler-32 checksum is stored as s2*65536 + s1 in most-
449 significant-byte first (network) order.
450 */
451 /* Update Adler-32 checksum */
452 while (p!=pend) {
453 #if SIZEOF_INT>2
454 if ((s1+=*(unsigned char const*)p)>=65521) s1-=65521;
455 if ((s2+=s1)>=65521) s2-=65521;
456 #elif SIZEOF_SHORT==2
457 sold=s1;
458 if ((s1+=*(unsigned char const*)p))<sold) s1+=15; /* 15==65536-21 */
459 sold=s2;
460 s2=(s2+s1)&0xffff;
461 if ((s2+=s1)<sold) s2+=15;
462 #else
463 /* vvv 0xffff is needed since unsigned short may be > 0..65535 */
464 sold=s1;
465 s1=(s1+*(unsigned char const*)p)&0xffff;
466 if (s1<sold) s1+=15; /* 15==65536-21 */
467 sold=s2;
468 s2=(s2+s1)&0xffff;
469 if (s2<sold) s2+=15;
470 #endif
471 p++;
472 }
473 // fprintf(stderr, "len=%u\n", len);
474 unsigned abufleft;
475 while ((abufleft=ABUFSIZE-abuflen)<len) {
476 // putchar('.');
477 // fprintf(stderr, "ABUFSIZE=%u abuflen=%u\n", ABUFSIZE, abuflen);
478 memcpy(abuf+abuflen+5, buf, abufleft);
479 abuf[0]=0; /* Stored block with padding */
480 abuf[1]=(char)ABUFSIZE; abuf[2]=(char)(ABUFSIZE>>8);
481 abuf[3]=(char)~(ABUFSIZE); abuf[4]=(char)~(ABUFSIZE>>8);
482 if (!had_header) { out.vi_write("\x78\x01", 2); had_header=true; }
483 /* fprintf(stderr,"%02x %02x", abuf[1], abuf[2]); */
484 out.vi_write(abuf, ABUFSIZE+5); /* emit next stored block with header */
485 abuflen=0;
486 len-=abufleft;
487 buf+=abufleft;
488 }
489 // putchar('X');
490 memcpy(abuf+abuflen+5, buf, len);
491 abuflen+=len;
492 /* Now abuf is possibly full. That is intentional, so we will be able to
493 * emit a full last block instead of an empty one.
494 */
495 }
496
497 /* --- */
498
ASCIIHexEncode(GenBuffer::Writable & out_,unsigned maxcpl_)499 ASCIIHexEncode::ASCIIHexEncode(GenBuffer::Writable &out_, unsigned maxcpl_)
500 :maxcpl(maxcpl_)
501 ,curcpl(0)
502 ,out(out_) {}
503
vi_write(char const * buf,slen_t len)504 void ASCIIHexEncode::vi_write(char const*buf, slen_t len) {
505 /* Imp: buffering (1K etc.) */
506 static char const hextable []="0123456789abcdef";
507 char obuf[3];
508 obuf[0]='\n';
509 if (len==0) { out.vi_write(">",1); out.vi_write(0,0); }
510 else while (len--!=0) {
511 obuf[1]=hextable[(*(unsigned char const*)buf)>>4];
512 obuf[2]=hextable[(*(unsigned char const*)buf)&15];
513 if (curcpl>=maxcpl) { curcpl=2; out.vi_write(obuf, 3); }
514 else { curcpl+=2; out.vi_write(obuf+1, 2); }
515 buf++;
516 }
517 }
518
519 /* --- */
520
ASCII85Encode(GenBuffer::Writable & out_,unsigned maxcpl_)521 ASCII85Encode::ASCII85Encode(GenBuffer::Writable &out_, unsigned maxcpl_)
522 :maxcpl(maxcpl_)
523 ,out(out_)
524 ,ascii85breaklen(maxcpl_)
525 ,ascii85left(4)
526 ,dscst(1) {
527 obufend=(op=obuf=new char[4096])+4096;
528 }
529
wencoded(char const * cp)530 void ASCII85Encode::wencoded(char const *cp) {
531 for (; *cp!='\0'; ) {
532 if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
533 // if (*cp<='!') { fprintf(stderr, "e=%d.\n", cp-encoded); }
534 assert(*cp>='!');
535 assert(*cp<='~');
536 if (dscst) {
537 if (dscst == 1) {
538 dscst = (*cp == '%') ? 2 : 0;
539 } else { /* if (dscst == 2) { */
540 if (*cp == '%') {
541 if (--ascii85breaklen == 0) {
542 *op++ = '\n';
543 ascii85breaklen = maxcpl;
544 } else {
545 /* Add space for `% %' instead of `%%' at BOL. */
546 *op++ = ' ';
547 }
548 if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
549 }
550 dscst = 0;
551 }
552 }
553 *op++=*cp++;
554 if (--ascii85breaklen == 0) {
555 if (op==obufend) out.vi_write(op=obuf, obufend-obuf);
556 *op++='\n';
557 ascii85breaklen = maxcpl;
558 dscst = 1;
559 }
560 } /* NEXT */
561 }
562
vi_write(char const * buf,slen_t len)563 void ASCII85Encode::vi_write(char const*buf, slen_t len) {
564 if (len==0) {
565 char encoded[6];
566 assert(ascii85left<=4);
567 if (ascii85left!=4) {
568 unsigned PTS_INT32_T buf_=ascii85buf<<8*ascii85left;
569 unsigned PTS_INT32_T q;
570 unsigned w1;
571
572 q = buf_ / ((unsigned PTS_INT32_T)85*85*85*85); /* actually only a byte */
573 assert(q<=85);
574 encoded[0] = q + '!';
575
576 buf_ -= q * ((unsigned PTS_INT32_T)85*85*85*85); q = buf_ / ((unsigned PTS_INT32_T)85*85*85);
577 encoded[1] = q + '!';
578
579 buf_ -= q * ((unsigned PTS_INT32_T)85*85*85); q = buf_ / (85*85);
580 encoded[2] = q + '!';
581
582 w1 = (unsigned) (buf_ - q*(unsigned PTS_INT32_T)(85*85));
583 assert(w1/85<85);
584 encoded[3] = (w1 / 85) + '!';
585 encoded[4] = (w1 % 85) + '!';
586 encoded[5-ascii85left] = '\0';
587 wencoded(encoded);
588 } /* IF */
589 if (op!=obuf) out.vi_write(obuf, op-obuf); /* flush buffer cache */
590 out.vi_write("~>",2); out.vi_write(0,0);
591 delete [] obuf;
592 obuf=(char*)NULLP;
593 } else {
594 assert(obuf!=NULLP);
595 register unsigned PTS_INT32_T abuf=ascii85buf;
596 register unsigned aleft=ascii85left;
597 assert(aleft>=1 && aleft<=4);
598 do {
599 while (len!=0 && aleft!=0) {
600 abuf=(abuf<<8)+*(unsigned char const*)buf++; len--; aleft--;
601 }
602 if (aleft!=0) break;
603 wout(abuf);
604 aleft=4;
605 } while (len!=0);
606 ascii85buf=abuf; ascii85left=aleft;
607 }
608 }
609
wout(unsigned PTS_INT32_T buf_)610 void ASCII85Encode::wout(unsigned PTS_INT32_T buf_) {
611 char encoded[6];
612 if (buf_ != (unsigned PTS_INT32_T)0) {
613 unsigned PTS_INT32_T q;
614 unsigned w1;
615
616 q = buf_ / ((unsigned PTS_INT32_T)85*85*85*85); /* actually only a byte */
617 encoded[0] = q + '!';
618
619 buf_ -= q * ((unsigned PTS_INT32_T)85*85*85*85); q = buf_ / ((unsigned PTS_INT32_T)85*85*85);
620 encoded[1] = q + '!';
621
622 buf_ -= q * ((unsigned PTS_INT32_T)85*85*85); q = buf_ / (85*85);
623 encoded[2] = q + '!';
624
625 w1 = (unsigned) (buf_ - q*(unsigned PTS_INT32_T)(85*85));
626 encoded[3] = (w1 / 85) + '!';
627 encoded[4] = (w1 % 85) + '!';
628 encoded[5] = '\0';
629 } else {
630 encoded[0] = 'z', encoded[1] = '\0';
631 }
632 wencoded(encoded);
633 }
634
635 /* --- */
636
RunLengthEncode(GenBuffer::Writable & out_,slen_t RecordSize_)637 RunLengthEncode::RunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize_)
638 :recordsize(RecordSize_==0?(slen_t)-1:RecordSize_)
639 ,out(out_) {
640 record_left=recordsize;
641 // obufend=(op=obuf=new char[4096])+4096; /* Imp: implement write buffering */
642 saved_c=saved_rep=0;
643 }
644
vi_write(char const * buf,slen_t len)645 void RunLengthEncode::vi_write(char const*buf, slen_t len) {
646 unsigned j, umax;
647 char b;
648 if (len==0) { /* handle EOF */
649 if (saved_rep!=0) {
650 assert(saved_rep>=2);
651 (saved+1)[-1]=257-saved_rep;
652 (saved+1)[1]=(char)128; /* EOD */
653 out.vi_write((saved+1)-1,3);
654 // fprintf(stderr,"rd=%u\n",saved_rep);
655 } else if (saved_c!=0) {
656 (saved+1)[-1]=saved_c-1;
657 (saved+1)[saved_c]=(char)128; /* EOD */
658 out.vi_write((saved+1)-1, saved_c+2);
659 // fprintf(stderr,"re=%u\n",saved_c);
660 } else {
661 (saved+1)[-1]=(char)128;
662 out.vi_write((saved+1)-1, 1);
663 }
664 out.vi_write(0,0); /* propagate EOF */
665 record_left=0; /* signal that no further data will be accepted */
666 return;
667 }
668 again:
669 assert(record_left>=1);
670 assert(len>=1);
671 /* Imp: locally cache vars saved* */
672 j=0;
673 if (saved_c==0) {
674 saved_rep=0; saved_c=1; b=(saved+1)[0]=*buf++; len--;
675 if (0==--record_left) goto put_norep;
676 if (0==len) return;
677 goto yes;
678 }
679 if (saved_c==1 && saved_rep==0) { yes:
680 if (*buf++==(saved+1)[0]) {
681 saved_rep=2; len--;
682 if (0==--record_left) goto put_rep;
683 } else {
684 (saved+1)[1]=buf[-1]; saved_c=2; len--;
685 if (0==--record_left) goto put_norep;
686 }
687 if (0==len) return;
688 }
689 assert(record_left>=1);
690 assert(len>=1);
691 assert((saved_rep==0 && saved_c>=2) || (saved_rep>=2 && saved_c==1));
692 if (saved_rep!=0) { /* Try to increase the repeating sequence */
693 assert(saved_rep>=2);
694 assert(saved_c==1);
695 assert(len>=1);
696 b=(saved+1)[0];
697 umax=len>128?128:len; if (umax>record_left) umax=record_left;
698 /* fprintf(stderr,"um1=%u\n", umax); */
699 if (umax>128-saved_rep) umax=128-saved_rep;
700 assert(umax>=1);
701 j=0; while (j!=umax && buf[j]==b) { j++; saved_rep++; }
702 if (j!=len || saved_rep==128) {
703 put_rep: /* Found a maximal repeat width */
704 (saved+1)[-1]=257-saved_rep;
705 out.vi_write((saved+1)-1,2);
706 /* fprintf(stderr,"ra=%u\n",saved_rep); */
707 if ((record_left-=j)==0) record_left=recordsize;
708 buf+=j;
709 saved_c=saved_rep=0;
710 if (0==(len-=j)) return;
711 goto again;
712 } /* Current repeat width can be further increased */
713 } else { /* Try to increase the non-repeating sequence */
714 assert(saved_c>=2);
715 if (buf[0]==(saved+1)[saved_c-1]) { /* this decision might be sub-optimal */
716 saved_c--;
717 /* Now: saved_c: non-repeat length, >=1 */
718 (saved+1)[-1]=saved_c-1;
719 out.vi_write((saved+1)-1, saved_c+1);
720 /* fprintf(stderr,"rb=%u\n",saved_c); */
721 // record_left++; /* because of saved_c--; but we would increase it later anyway */
722 // buf+=saved_c;
723 (saved+1)[0]=buf[0]; /* first matching char-pair data */
724 saved_c=1; saved_rep=2; /* make the new block a >=2 repeat */
725 record_left--; buf++;
726 if (0==--len) return;
727 goto again;
728 }
729 (saved+1)[saved_c++]=buf[0];
730 //record_left--;
731 //buf++;
732 //len--;
733 //if (saved_c==128) goto put_norep;
734 //if (0==len) return;
735 umax=len>128?128:len; if (umax>record_left) umax=record_left;
736 if (umax>128-saved_c) umax=128-saved_c;
737 /* fprintf(stderr,"um2=%u\n", umax); */
738 assert(umax>=1);
739 j=1; while (j!=umax && buf[j]!=buf[j-1]) (saved+1)[saved_c++]=buf[j++];
740 if (j!=len || saved_c==128) {
741 put_norep: /* Found a maximal non-repeat width */
742 (saved+1)[-1]=saved_c-1;
743 out.vi_write((saved+1)-1, saved_c+1);
744 /* fprintf(stderr,"rc=%u\n",saved_c); */
745 if ((record_left-=j)==0) record_left=recordsize;
746 buf+=j;
747 saved_c=saved_rep=0;
748 if (0==(len-=j)) return;
749 goto again;
750 } /* Current non-repeat width can be further increased */
751 }
752 assert(j==len);
753 record_left-=j;
754 assert(saved_rep<128);
755 assert(saved_c<128);
756 }
757
758 /* --- */
759
760 #if USE_BUILTIN_ZIP
761 // bool FlateEncode::locked=false;
762
763 #if PTS_DEFL_RIPPED_ZLIB
FlateEncode(GenBuffer::Writable & out_,unsigned level_)764 FlateEncode::FlateEncode(GenBuffer::Writable &out_, unsigned level_)
765 :out(out_) {
766 // assert(!locked); locked /* locking is not necessary anymore */
767 // pts_deflate_init(&fs); /* obsolete */
768 zs.total_in=0;
769 zs.total_out=0;
770 zs.workspace=workspace;
771 zs.msg=(char*)0;
772 zs.state=(struct zlib_internal_state*)0;
773 zs.data_type=Z_UNKNOWN; /* Imp: do we have to initialize it? */
774 assert(zlib_deflate_workspacesize()+(unsigned)0<sizeof(workspace) && "Flate workspace too small");
775 if (Z_OK!=zlib_deflateInit(&zs, level_))
776 Error::sev(Error::EERROR) << "Flate init error (out of memory?)" << (Error*)0;
777 }
778
vi_write(char const * buf,slen_t len)779 void FlateEncode::vi_write(char const*buf, slen_t len) {
780 slen_t got, zgot;
781 /* fprintf(stderr,"wcall\n"); */
782 zs.next_in=(unsigned char*)const_cast<char*>(buf); zs.avail_in=len;
783 if (len==0) { /* flush all output */
784 do { /* SUXX: C compiler should emit a warning: while (1) { ... } while(...); */
785 zs.next_out=(unsigned char*)obuf; zs.avail_out=sizeof(obuf);
786 /* fprintf(stderr,"wdone zai=%d zao=%d\n", zs.avail_in, zs.avail_out); */
787 if (Z_STREAM_END!=(zgot=zlib_deflate(&zs, Z_FINISH)) && Z_OK!=zgot)
788 Error::sev(Error::EERROR) << "Flate close error: " << zs.msg << (Error*)0;
789 got=sizeof(obuf)-zs.avail_out;
790 /* fprintf(stderr, "got=%u zgot=%d Z_OK=%d\n", got, zgot, Z_OK); */
791 if (got>0) out.vi_write(obuf, got);
792 } while (zgot==Z_OK);
793 /* Dat: zlib_deflateEnd() will be called in the destructur */
794 out.vi_write(0,0); /* Signal EOF */
795 /* Dat: zlib_deflate() adds RFC 1950 header and adler32 checksum automatically */
796 } else {
797 do {
798 /* fprintf(stderr,"writ\n"); */
799 zs.next_out=(unsigned char*)obuf; zs.avail_out=sizeof(obuf);
800 if (Z_OK!=zlib_deflate(&zs, 0))
801 Error::sev(Error::EERROR) << "Flate write error: " << zs.msg << (Error*)0;
802 if (0<(got=sizeof(obuf)-zs.avail_out)) out.vi_write(obuf, got);
803 } while (0!=zs.avail_in);
804 }
805 }
806 #else
FlateEncode(GenBuffer::Writable & out_,unsigned level_)807 FlateEncode::FlateEncode(GenBuffer::Writable &out_, unsigned level_)
808 :out(out_)
809 ,s1(1)
810 ,s2(0)
811 ,had_header(false) {
812 // assert(!locked); locked /* locking is not necessary anymore */
813 // pts_deflate_init(&fs); /* obsolete */
814 fs=pts_defl_new(
815 /*zpfwrite=*/ gen_write,
816 /*zpfmalloc=*/ gen_malloc,
817 /*zpffree=*/ gen_free,
818 /*pack_level=*/ level_,
819 /*zfile=*/ (void*)&out_
820 );
821 if (fs==NULL) Error::sev(Error::EERROR) << "Flate init error (out of memory?)" << (Error*)0;
822 }
gen_malloc(unsigned n)823 void *FlateEncode::gen_malloc(unsigned n) {
824 return operator new(n);
825 // return new char[n];
826 }
gen_free(void * p)827 void FlateEncode::gen_free(void *p) {
828 /*return*/ operator delete(p);
829 // delete [] (char*)p;
830 }
831
vi_write(char const * buf,slen_t len)832 void FlateEncode::vi_write(char const*buf, slen_t len) {
833 register s_t sold;
834 register char const*p=buf; char const*pend=p+len;
835 (void)sold;
836 if (!had_header) {
837 out.vi_write("\x78\xda",2); /* ZLIB (RFC 1950): max compression header */
838 had_header=true;
839 }
840 if (len==0) { /* EOF: send trailer */
841 fs->deflate2(0,0,fs); /* Let the compressor flush its buffers. */
842 if (fs->err!=0) Error::sev(Error::EERROR) << "Flate compression error" << (Error*)0;
843 fs->delete2(fs);
844 fs=(struct pts_defl_interface*)NULL;
845 if (s1>=65521) s1-=65521;
846 if (s2>=65521) s2-=65521;
847 unsigned char trailer[4];
848 trailer[0]=s2>>8; trailer[1]=s2&255; trailer[2]=s1>>8; trailer[3]=s1&255;
849 out.vi_write((char const*)trailer,4);
850 out.vi_write(0,0); /* Signal EOF */
851 return;
852 }
853 assert(fs!=NULL);
854
855 /* From rfc1950.txt:
856 Adler-32 is composed of two sums accumulated per byte: s1 is
857 the sum of all bytes, s2 is the sum of all s1 values. Both sums
858 are done modulo 65521. s1 is initialized to 1, s2 to zero. The
859 Adler-32 checksum is stored as s2*65536 + s1 in most-
860 significant-byte first (network) order.
861 */
862 /* Update Adler-32 checksum */
863 while (p!=pend) {
864 #if SIZEOF_INT>2
865 if ((s1+=*(unsigned char const*)p)>=65521) s1-=65521;
866 if ((s2+=s1)>=65521) s2-=65521;
867 #elif SIZEOF_SHORT==2
868 sold=s1;
869 if ((s1+=*(unsigned char const*)p))<sold) s1+=15; /* 15==65536-21 */
870 sold=s2;
871 s2=(s2+s1)&0xffff;
872 if ((s2+=s1)<sold) s2+=15;
873 #else
874 /* vvv 0xffff is needed since unsigned short may be > 0..65535 */
875 sold=s1;
876 s1=(s1+*(unsigned char const*)p)&0xffff;
877 if (s1<sold) s1+=15; /* 15==65536-21 */
878 sold=s2;
879 s2=(s2+s1)&0xffff;
880 if (s2<sold) s2+=15;
881 #endif
882 p++;
883 }
884 while (len>=0x8000) { fs->deflate2(const_cast<char*>(buf),0x8000, fs); len-=0x8000; buf+=0x8000; }
885 if (len!=0) fs->deflate2(const_cast<char*>(buf),len, fs);
886 }
887 #endif /* PTS_DEFL_RIPPED_ZLIB */
888 #endif /* USE_BUILTIN_ZIP */
889
gen_write(char * block,unsigned len,void * zfile)890 int /*FlateEncode::*/gen_write(char *block, unsigned len, void *zfile) {
891 static_cast<GenBuffer::Writable*>(zfile)->vi_write(block, len);
892 return 0;
893 }
894
895
896 /* --- */
897
898 #if USE_BUILTIN_FAXE
gen_xalloc(unsigned n)899 void* CCITTFaxEncode::gen_xalloc(unsigned n) {
900 return operator new(n);
901 // void *ret; if ((ret=malloc(n))==0) abort(); return ret;
902 }
gen_free(void * ptr)903 void CCITTFaxEncode::gen_free(void *ptr) {
904 /*return*/ operator delete(ptr);
905 // free(ptr);
906 }
gen_memset(void * s,int c,unsigned n)907 void CCITTFaxEncode::gen_memset(void *s, int c, unsigned n) {
908 /*return*/ memset(s,c,n);
909 }
gen_memcpy(void * dest,const void * src,unsigned n)910 void CCITTFaxEncode::gen_memcpy(void *dest, const void *src, unsigned n) {
911 /*return*/ memcpy(dest, src, n);
912 }
CCITTFaxEncode(GenBuffer::Writable & out_,slendiff_t K,slen_t Columns,bool EndOfLine,bool BlackIs1)913 CCITTFaxEncode::CCITTFaxEncode(GenBuffer::Writable &out_, slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1): out(out_) {
914 sCFEs.memset_=gen_memset;
915 sCFEs.xalloc_=gen_xalloc;
916 sCFEs.free_=gen_free;
917 sCFEs.memcpy_=gen_memcpy;
918 s_CFE_template.set_defaults((stream_state*)&sCFEs);
919 sCFEs.K=K;
920 sCFEs.Columns=Columns;
921 sCFEs.EndOfLine=EndOfLine;
922 sCFEs.BlackIs1=BlackIs1;
923 const int cf_max_height=(unsigned)-1/2-100; /* Dat: was slen_t */
924 if (sCFEs.K < -cf_max_height || sCFEs.K > cf_max_height /* Dat: .K is an int */
925 || sCFEs.Columns < 0 || sCFEs.Columns > cfe_max_width /* Dat: .Columns is an int */
926 || sCFEs.Rows < 0 || sCFEs.Rows > cf_max_height /* Dat: .Rows is an int */
927 || sCFEs.DamagedRowsBeforeError < 0
928 || sCFEs.DamagedRowsBeforeError > cf_max_height /* Dat: .DamagedRowsBeforeError is an int */
929 || sCFEs.DecodedByteAlign < 1 || sCFEs.DecodedByteAlign > 16
930 || (sCFEs.DecodedByteAlign & (sCFEs.DecodedByteAlign - 1)) != 0
931 ) Error::sev(Error::EERROR) << "pts_fax: invalid params" << (Error*)0;
932 if (0!=s_CFE_template.init((stream_state*)&sCFEs))
933 Error::sev(Error::EERROR) << "pts_fax: init failed" << (Error*)0;
934 #if __CHECKER__
935 memset(&r, 0, sizeof(r));
936 memset(&w, 0, sizeof(w));
937 #endif
938 r.ptr=rlimit=rbuf-1;
939 hard=rbuf+sizeof(rbuf)-1;
940 assert(hard-r.ptr>=(int)s_CFE_template.min_in_size);
941 }
942
vi_write(char const * buf,slen_t len)943 void CCITTFaxEncode::vi_write(char const*buf, slen_t len) {
944 int pog;
945 // unsigned char *save_wptr;
946 if (len==0) {
947 r.limit=rlimit;
948 do {
949 w.ptr=wbuf-1;
950 w.limit=wbuf+sizeof(wbuf)-1;
951 assert(w.limit-w.ptr>=(int)s_CFE_template.min_out_size);
952 pog=s_CFE_template.process((stream_state*)&sCFEs, &r, &w, /*last:*/ true);
953 // fprintf(stderr, "pog=%d write=%d last=%d\n", pog, w.ptr-(wbuf-1), true);
954 assert(pog!=PTSFAX_ERRC); /* /CCITTFaxEncode filter must accept any input */
955 assert(pog!=PTSFAX_EOFC); /* /CCITTFaxEncode filter doesn't have EOD markers */
956 if (w.ptr!=wbuf-1) out.vi_write((char const*)wbuf, w.ptr-(wbuf-1));
957 } while (pog==1);
958 s_CFE_template.release((stream_state*)&sCFEs);
959 out.vi_write(0,0); /* propagate EOF */
960 return;
961 }
962
963 while (len!=0) {
964 assert(r.ptr==rbuf-1);
965 assert(hard>rlimit);
966 unsigned clen=hard-rlimit;
967 if (clen>len) clen=len;
968 assert(clen>0);
969 // fprintf(stderr, "clen=%u\n", clen);
970 memcpy(rlimit+1, buf, clen);
971 rlimit+=clen;
972 buf+=clen;
973 len-=clen;
974 /* if (r.ptr==rlimit) break; */
975 r.limit=rlimit;
976 do {
977 w.ptr=wbuf-1;
978 w.limit=wbuf+sizeof(wbuf)-1;
979 assert(w.limit-w.ptr>=(int)s_CFE_template.min_out_size);
980 pog=s_CFE_template.process((stream_state*)&sCFEs, &r, &w, /*last:*/ false);
981 // fprintf(stderr, "len=%d pog=%d write=%d last=%d\n", len, pog, w.ptr-(wbuf-1), false);
982 assert(pog!=PTSFAX_ERRC); /* /CCITTFaxEncode filter must accept any input */
983 assert(pog!=PTSFAX_EOFC); /* /CCITTFaxEncode filter doesn't have EOD markers */
984 if (w.ptr!=wbuf-1) out.vi_write((char const*)wbuf, w.ptr-(wbuf-1));
985 } while (pog==1);
986 // assert(pog!=1); /* not true: output space is enough (sizeof(wbuf)>min_out_size) */
987 assert(pog==0); /* more input is needed */
988 if (r.ptr!=rbuf-1) {
989 // fprintf(stderr, "limit=%d\n", rlimit-r.ptr);
990 memmove(rbuf, r.ptr+1, rlimit-r.ptr);
991 rlimit=rbuf-1+(rlimit-r.ptr);
992 r.ptr=rbuf-1;
993 }
994 }
995 // fprintf(stderr, "done\n");
996 }
997 #endif /* USE_BUILTIN_FAXE */
998
999 /* --- */
1000
1001 #if USE_BUILTIN_LZW
LZWEncode(GenBuffer::Writable & out_)1002 LZWEncode::LZWEncode(GenBuffer::Writable &out_): out(out_) {
1003 fs.tif_writer=/*FlateEncode::*/gen_write;
1004 fs.tif_sout=(void*)&out_;
1005 if (0==pts_lzw_init(&fs)) Error::sev(Error::EERROR) << "LZW init error" << (Error*)0;
1006 }
1007
vi_write(char const * buf,slen_t len)1008 void LZWEncode::vi_write(char const*buf, slen_t len) {
1009 /* Imp: report real error _reason_ (if appropriate?? ) */
1010 if (len==0) {
1011 if (0==fs.tif_feeder(0,0,&fs)) goto we;
1012 out.vi_write(0,0); /* propagate EOF */
1013 return;
1014 }
1015 while (len>=0x8000) {
1016 if (0==fs.tif_feeder(const_cast<char*>(buf),0x8000,&fs)) we:
1017 Error::sev(Error::EERROR) << "LZW write error" << (Error*)0;
1018 len-=0x8000; buf+=0x8000;
1019 }
1020 if (len!=0 && 0==fs.tif_feeder(const_cast<char*>(buf),len,&fs)) goto we;
1021 }
1022 #endif /* USE_BUILTIN_LZW */
1023
1024 /* --- */
1025
1026 #if !USE_BUILTIN_LZW
Lzw_codecEncode(GenBuffer::Writable & out_,char const * filter_psname)1027 Lzw_codecEncode::Lzw_codecEncode(GenBuffer::Writable &out_, char const*filter_psname)
1028 :p(out_) {
1029 (void)filter_psname;
1030 }
vi_write(char const * buf,slen_t len)1031 void Lzw_codecEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
1032
1033 /* Imp: figure out path-to-gs: gs or gswin32c */
P(GenBuffer::Writable & out_)1034 Lzw_codecEncode::P::P(GenBuffer::Writable &out_)
1035 // :PipeEncoder(out_, ">/tmp/t cat - cjpeg quality %i", quality), rgbp(rgbp_) {
1036 // :Filter::PipeE(out_, "cjpeg -quality %i >%D", quality), rgbp(rgbp_) {
1037 :Filter::PipeE(out_, "lzw_codec encode >%D") {}
1038 #endif
1039
1040 /* --- */
1041
CjpegEncode(GenBuffer::Writable & out_,char const * filter_psname,slen_t Columns,slen_t Rows,bool rgbp_,unsigned char quality)1042 CjpegEncode::CjpegEncode(GenBuffer::Writable &out_, char const*filter_psname, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality)
1043 :p(out_, Columns, Rows, rgbp_, quality) {
1044 (void)filter_psname;
1045 }
vi_write(char const * buf,slen_t len)1046 void CjpegEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
1047
1048 /* Imp: figure out path-to-gs: gs or gswin32c */
P(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,bool rgbp_,unsigned char quality)1049 CjpegEncode::P::P(GenBuffer::Writable &out_, slen_t Columns, slen_t Rows, bool rgbp_, unsigned char quality)
1050 // :PipeEncoder(out_, ">/tmp/t cat - cjpeg quality %i", quality), rgbp(rgbp_) {
1051 :Filter::PipeE(out_, "cjpeg -quality %i >%D", quality), rgbp(rgbp_) {
1052 /* Dat: we're extremely lucky that cjpeg can read PGM or PPM files from stdin */
1053 // operator<<("P5 width height 255\n"); /* RAWBITS PGM */
1054 // operator<<("P6 width height 255\n"); /* RAWBITS PPM */
1055 *this << (rgbp_?"P6 ":"P5 ") << Columns << ' ' << Rows << " 255\n";
1056 }
vi_copy(FILE * f)1057 void CjpegEncode::P::vi_copy(FILE *f) {
1058 char r[10];
1059 static char jfif[9]="\377\340\000\020JFIF";
1060 static unsigned char adobe[16]= {
1061 0xff, /* marker */
1062 0xee, /* APP14 */
1063 0, /* length-hi */
1064 14, /* length-lo */
1065 'A', 'd', 'o', 'b', 'e', /* ID */
1066 1, /* version-hi */
1067 0, /* version-lo */
1068 0, 0, /* flags0 */
1069 0, 0, /* flags1 */
1070 0, /* ColorTransform */
1071 };
1072 if (MACRO_GETC(f)!=0xff || MACRO_GETC(f)!=0xd8 || fread(r, 1, 8, f)!=8) {
1073 bad: Error::sev(Error::EERROR) << "CjpegEncode: cjpeg created bad JPEG" << (Error*)0;
1074 }
1075 out.vi_putcc((char)0xff);
1076 out.vi_putcc((char)0xd8);
1077 r[9]=r[3]; r[3]='\020';
1078 if ((unsigned char)r[9]>=6 && 0==memcmp(r, jfif, 8)) { /* JFIF marker */
1079 r[3]=r[9]; unsigned skip=r[9]-6;
1080 out.vi_write(r, 8);
1081 while (skip--!=0) out.vi_putcc(MACRO_GETC(f));
1082 }
1083 if (ferror(f) || feof(f)) goto bad;
1084 /* Now we can emit the Adobe marker. */
1085 adobe[sizeof(adobe)-1]=rgbp==true; /* ColorTransform value 0 for Gray, 1 for RGB->YCbCr */
1086 out.vi_write((char*)adobe, sizeof(adobe));
1087 /* vvv Dat: pacify VC6.0: Filter::PipeE::vi_copy(f); doesn't work */
1088 PipeE::vi_copy(f);
1089 /* ^^^ copy rest of file verbatim */
1090 // ((Filter::PipeE)*this).vi_copy(f);
1091 }
1092
1093 /* --- */
1094
GSEncode(GenBuffer::Writable & out_,char const * filter_psname)1095 GSEncode::GSEncode(GenBuffer::Writable &out_, char const*filter_psname)
1096 :p(out_, filter_psname) {}
vi_write(char const * buf,slen_t len)1097 void GSEncode::vi_write(char const*buf, slen_t len) { p.vi_write(buf,len); }
1098
1099 /* Imp: figure out path-to-gs: gs or gswin32c */
P(GenBuffer::Writable & out_,char const * filter_psname)1100 GSEncode::P::P(GenBuffer::Writable &out_, char const*filter_psname)
1101 :Filter::PipeE(out_, "gs -s_OFN=%D -dNODISPLAY -q - >%E")
1102 {
1103 operator<<("{/o _OFN(w)file ");
1104 operator<<(filter_psname);
1105 operator<<(" filter def/s 4096 string def"
1106 "{currentfile s readstring exch o exch writestring not{exit}if}loop "
1107 "o closefile quit}bind exec\n");
1108 }
vi_check()1109 void GSEncode::P::vi_check() {
1110 /* If STDOUT of gs is not empty, then it is very probably an error message. */
1111 // tmpename.term0(); /* already is */
1112 assert(tmpename.end_()[0]=='\0');
1113 if (0!=Files::statSize(tmpename())) Error::sev(Error::EERROR) << "GSEncode: GS runtime error" << (Error*)0;
1114 /* Imp: display a meaningful error message */
1115 }
1116
1117 /* --- */
1118
newASCIIHexEncode(GenBuffer::Writable & out_,unsigned maxcpl_)1119 PSEncoder* PSEncoder::newASCIIHexEncode(GenBuffer::Writable &out_,unsigned maxcpl_) {
1120 // SimBuffer::B fp; (fp << maxcpl_ << " pop/ASCIIHexEncode").term0();
1121 // PSEncoder *ret=new GSEncode(out_, fp());
1122 PSEncoder *ret=new ASCIIHexEncode(out_,maxcpl_);
1123 // ret->shortname="AHx"; ret->longname="ASCIIHex";
1124 // ret->filter_psname << fp;
1125 return ret;
1126 }
newASCII85Encode(GenBuffer::Writable & out_,unsigned maxcpl_)1127 PSEncoder* PSEncoder::newASCII85Encode(GenBuffer::Writable &out_,unsigned maxcpl_) {
1128 // SimBuffer::B fp; (fp << maxcpl_ << " pop/ASCII85Encode").term0();
1129 PSEncoder *ret=new ASCII85Encode(out_,maxcpl_);
1130 // PSEncoder *ret=new GSEncode(out_, fp());
1131 // ret->shortname="A85"; ret->longname="ASCII85";
1132 // ret->filter_psname << fp;
1133 return ret;
1134 }
newCCITTFaxEncode(GenBuffer::Writable & out_,slendiff_t K,slen_t Columns,bool EndOfLine,bool BlackIs1)1135 PSEncoder* PSEncoder::newCCITTFaxEncode(GenBuffer::Writable &out_,slendiff_t K, slen_t Columns, bool EndOfLine, bool BlackIs1) {
1136 #if USE_BUILTIN_FAXE
1137 return new CCITTFaxEncode(out_, K, Columns, EndOfLine, BlackIs1);
1138 #else
1139 // (void)out_; (void)K; (void)Columns;
1140 // assert(0 && "unimplemented");
1141 SimBuffer::B fp("<< /K ");
1142 fp << K << "/Columns " << Columns;
1143 if (EndOfLine) fp << "/EndOfLine true"; /* PS default: false */
1144 if (BlackIs1) fp << "/BlackIs1 true";
1145 (fp << ">>/CCITTFaxEncode").term0();
1146 // fprintf(stderr, "fp=(%s)\n", fp());
1147 PSEncoder *ret=new GSEncode(out_, fp());
1148 // ret->shortname="CCF"; ret->longname="CCITTFax";
1149 // ret->filter_psname << fp; /* Dat: this could be made faster */
1150 return ret;
1151 #endif
1152 }
newLZWEncode(GenBuffer::Writable & out_)1153 PSEncoder* PSEncoder::newLZWEncode(GenBuffer::Writable &out_) {
1154 #if USE_BUILTIN_LZW
1155 SimBuffer::B fp("/LZWEncode");
1156 PSEncoder *ret=new LZWEncode(out_);
1157 // PSEncoder *ret=new GSEncode(out_, fp());
1158 // ret->shortname="LZW"; ret->longname="LZW";
1159 // ret->filter_psname << fp;
1160 return ret;
1161 #else
1162 (void)out_;
1163 #if 0
1164 Error::sev(Error::EERROR) << "LZW not supported in this compilation of sam2p" << (Error*)0;
1165 #endif
1166 Error::sev(Error::WARNING) << "LZW: please `configure --enable-lzw' for builtin /Compression/LZW support" << (Error*)0;
1167 #if 0
1168 /* This is useless, because gs 5.50--7.04 have dummy LZW compressor:
1169 * it emits a correct LZW stream, but does no real compression, and
1170 * the file size is often increased.
1171 */
1172 PSEncoder *ret=new GSEncode(out_, "/LZWEncode");
1173 // ret->shortname="LZW"; ret->longname="LZW";
1174 // ret->filter_psname << "/LZWEncode";
1175 return ret;
1176 #endif
1177 #if 1 /* ask lzw_codec from the author of sam2p */
1178 return new Lzw_codecEncode(out_, "/LZWEncode");
1179 #endif
1180 return 0;
1181 #endif
1182 }
newFlateEncode(GenBuffer::Writable & out_,signed Effort)1183 PSEncoder* PSEncoder::newFlateEncode(GenBuffer::Writable &out_, signed Effort) {
1184 // (void)out_; (void)K; (void)Columns;
1185 // assert(0 && "unimplemented");
1186 if (Effort==0) {
1187 PSEncoder *ret=new FlateStoreEncode(out_);
1188 // ret->shortname="Fla"; ret->longname="Flate";
1189 // ret->filter_psname << fp;
1190 return ret;
1191 }
1192 if (Effort<1 || Effort>9) Effort=5;
1193 #if USE_BUILTIN_ZIP
1194 PSEncoder *ret=new FlateEncode(out_, Effort);
1195 #else
1196 SimBuffer::B fp("<</Effort "); (fp << Effort << ">>/FlateEncode").term0();
1197 PSEncoder *ret=new GSEncode(out_, fp());
1198 #endif
1199 // ret->shortname="Fla"; ret->longname="Flate";
1200 // ret->filter_psname << fp;
1201 return ret;
1202 }
newRunLengthEncode(GenBuffer::Writable & out_,slen_t RecordSize)1203 PSEncoder* PSEncoder::newRunLengthEncode(GenBuffer::Writable &out_, slen_t RecordSize) {
1204 SimBuffer::B fp; (fp << RecordSize << "/RunLengthEncode").term0();
1205 PSEncoder *ret=new RunLengthEncode(out_, RecordSize);
1206 // PSEncoder *ret=new GSEncode(out_, fp());
1207 // ret->shortname="RL"; ret->longname="RunLength";
1208 // ret->filter_psname << fp;
1209 return ret;
1210 }
1211
newDCTIJGEncode(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,unsigned char Colors,unsigned char quality)1212 PSEncoder* PSEncoder::newDCTIJGEncode(GenBuffer::Writable &out_,
1213 slen_t Columns,
1214 slen_t Rows,
1215 unsigned char Colors, /*1..4*/
1216 unsigned char quality /*libJPEG quality: 0..100 */
1217 ) {
1218 /* Dat: this supports only the Gray and RGB color spaces of JPEG */
1219 param_assert(Colors==1 || Colors==3);
1220 param_assert(/* quality>=0 && */ quality <=100);
1221 SimBuffer::B fp("<<IJG ");
1222 (fp<< "/Columns " << Columns
1223 << "/Rows " << Rows
1224 << "/Colors " << (unsigned)Colors
1225 << ">>/DCTEncode").term0();
1226 /* Dat: the default of /ColorTransform (defined in DCTEncode in
1227 subsubsection 3.13.3 in PLRM.pdf) is just perfect. */
1228 PSEncoder *ret=new CjpegEncode(out_, fp(), Columns, Rows, Colors==3, quality);
1229 // ret->longname=ret->shortname="DCT"; ret->filter_psname << fp;
1230 return ret;
1231 }
1232
newDCTEncode(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,unsigned char Colors,unsigned char quality,unsigned char const * HSamples,unsigned char const * VSamples,unsigned char (* QuantTables)[64],double QFactor,unsigned numHuffTables,unsigned char ** HuffTables,unsigned char ColorTransform)1233 PSEncoder* PSEncoder::newDCTEncode(GenBuffer::Writable &out_,
1234 slen_t Columns,
1235 slen_t Rows,
1236 unsigned char Colors, /*1..4*/
1237 unsigned char quality, /*libJPEG quality: 0..100 */
1238 unsigned char const*HSamples, /*all 1..4, NULLP OK*/
1239 unsigned char const*VSamples, /*all 1..4, NULLP OK*/
1240 unsigned char (*QuantTables)[64], /*NULLP OK*/
1241 double QFactor, /*0..1000000*/
1242 unsigned numHuffTables,
1243 unsigned char **HuffTables, /*NULLP OK*/
1244 unsigned char ColorTransform /*0,1,2 3=default*/
1245 ) {
1246 (void)quality;
1247 (void)QuantTables;
1248 (void)QFactor;
1249 (void)numHuffTables;
1250 (void)HuffTables;
1251 SimBuffer::B tmp;
1252 /* Imp: respect quality */
1253 /* Imp: respect QFactor (double) */
1254 /* Imp: respect QuantTables */
1255 /* Imp: respect numHuffTables, HuffTables */
1256
1257 SimBuffer::B fp("<<");
1258 fp << "/Columns " << Columns
1259 << "/Rows " << Rows
1260 << "/Colors " << (unsigned)Colors;
1261 if (HSamples!=(unsigned char const*)NULLP) {
1262 tmp.clear(); tmp.vi_write((char const*)HSamples, (unsigned)Colors);
1263 fp << "/HSamples "; fp.appendDumpPS(tmp,true);
1264 }
1265 if (VSamples!=(unsigned char const*)NULLP) {
1266 tmp.clear(); tmp.vi_write((char const*)VSamples, (unsigned)Colors);
1267 fp << "/VSamples "; fp.appendDumpPS(tmp,true);
1268 }
1269 if (ColorTransform!=3) fp << "/ColorTransform " << (unsigned)ColorTransform;
1270 (fp << ">>/DCTEncode").term0();
1271
1272 // PSEncoder *ret=new DCTEncode(out_,? ? ?);
1273 PSEncoder *ret=new GSEncode(out_, fp());
1274 // ret->shortname="DCT"; ret->longname="DCT";
1275 // ret->filter_psname << fp;
1276 return ret;
1277 }
1278
newDCTEncode(GenBuffer::Writable & out_,slen_t Columns,slen_t Rows,unsigned char Colors,unsigned char ColorTransform,SimBuffer::Flat const & other_parameters)1279 PSEncoder* PSEncoder::newDCTEncode(GenBuffer::Writable &out_,
1280 slen_t Columns,
1281 slen_t Rows,
1282 unsigned char Colors, /*1..4*/
1283 unsigned char ColorTransform, /*0,1,2 3=default*/
1284 SimBuffer::Flat const& other_parameters
1285 ) {
1286 SimBuffer::B fp("<<");
1287 fp << "/Columns " << Columns
1288 << "/Rows " << Rows
1289 << "/Colors " << (unsigned)Colors;
1290 if (ColorTransform!=3) fp << "/ColorTransform " << (unsigned)ColorTransform;
1291 (fp << other_parameters << ">>/DCTEncode").term0();
1292 PSEncoder *ret=new GSEncode(out_, fp());
1293 // ret->shortname="DCT"; ret->longname="DCT";
1294 // ret->filter_psname << fp;
1295 return ret;
1296 }
1297
1298 /* --- */
1299
TIFFPredictor2(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1300 TIFFPredictor2::TIFFPredictor2(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1301 : h(0), bpc(bpc_), cpp(cpp_), out(out_) {
1302 param_assert(cpp_*bpc_<=32);
1303 rlen=(columns_*cpp_*bpc_+7)>>3; /* BUGFIX at Tue Mar 12 12:09:51 CET 2002 */
1304 op=obuf=new unsigned char[rlen];
1305 }
1306
vi_write(char const * buf,slen_t len)1307 void TIFFPredictor2::vi_write(char const*buf, slen_t len) {
1308 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1309 slen_t opleft=rlen-(op-obuf);
1310 register unsigned int i, d, o, bpccpp;
1311 if (len==0) {
1312 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1313 assert(obuf!=NULLP);
1314 delete [] obuf;
1315 obuf=(unsigned char*)NULLP;
1316 out.vi_write(0,0);
1317 return;
1318 }
1319 bpccpp=(cpp-1)*bpc;
1320 if (bpc==1) {
1321 while (p!=pend0) {
1322 i=*p++;
1323 d=(i>>7); o =((d-((h>>bpccpp)))&1)<<7; h=(h<<1)|d;
1324 d=(i>>6); o|=((d-((h>>bpccpp)))&1)<<6; h=(h<<1)|d;
1325 d=(i>>5); o|=((d-((h>>bpccpp)))&1)<<5; h=(h<<1)|d;
1326 d=(i>>4); o|=((d-((h>>bpccpp)))&1)<<4; h=(h<<1)|d;
1327 d=(i>>3); o|=((d-((h>>bpccpp)))&1)<<3; h=(h<<1)|d;
1328 d=(i>>2); o|=((d-((h>>bpccpp)))&1)<<2; h=(h<<1)|d;
1329 d=(i>>1); o|=((d-((h>>bpccpp)))&1)<<1; h=(h<<1)|d;
1330 d=(i ); o|=((d-((h>>bpccpp)))&1) ; h=(h<<1)|d;
1331 *op++=o;
1332 if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1333 }
1334 } else if (bpc==2) {
1335 while (p!=pend0) {
1336 i=*p++;
1337 d=(i>>6); o =((d-((h>>bpccpp)))&3)<<6; h=(h<<2)|d; // fprintf(stderr,"d=%#x\n", d);
1338 d=(i>>4); o|=((d-((h>>bpccpp)))&3)<<4; h=(h<<2)|d;
1339 d=(i>>2); o|=((d-((h>>bpccpp)))&3)<<2; h=(h<<2)|d;
1340 d=(i ); o|=((d-((h>>bpccpp)))&3) ; h=(h<<2)|d;
1341 *op++=o;
1342 if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1343 }
1344 } else if (bpc==4) {
1345 while (p!=pend0) {
1346 i=*p++;
1347 d=(i>>4); o =((d-((h>>bpccpp)))&15)<<4; h=(h<<4)|d;
1348 d=(i ); o|=((d-((h>>bpccpp)))&15) ; h=(h<<4)|d;
1349 *op++=o;
1350 if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1351 }
1352 } else if (bpc==8) {
1353 while (p!=pend0) {
1354 i=*p++; *op++=((i-((h>>bpccpp)))/*&255*/); h=(h<<8)|i;
1355 if (--opleft==0) { h=0; out.vi_write((char*)obuf,rlen); op=obuf; opleft=rlen; }
1356 }
1357 } else assert(0);
1358 }
1359
1360 /* --- */
1361
PNGPredictorNone(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1362 PNGPredictorNone::PNGPredictorNone(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1363 : opleft(0), out(out_) {
1364 rlen=(columns_*cpp_*bpc_+7)>>3;
1365 }
1366
vi_write(char const * buf,slen_t len)1367 void PNGPredictorNone::vi_write(char const*buf, slen_t len) {
1368 if (len==0) {
1369 assert(opleft==0); /* unflushed (half-ready) row disallowed */
1370 out.vi_write(0,0);
1371 return;
1372 }
1373 /* The following code just inserts a '\0' in front of each scanline */
1374 /* Imp: make it faster by collapsing vi_writes */
1375 if (opleft==0) { opleft=rlen; out.vi_write("\0",1); } /* Scanline (row) header: describes predictor used */
1376 while (len>opleft) {
1377 out.vi_write(buf,opleft);
1378 buf+=opleft; len-=opleft;
1379 opleft=rlen; out.vi_write("\0",1); /* Scanline (row) header: describes predictor used */
1380 }
1381 if (len!=0) out.vi_write(buf,len);
1382 opleft-=len;
1383 }
1384
1385 /* --- */
1386
PNGPredictorSub(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1387 PNGPredictorSub::PNGPredictorSub(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1388 : h(0), out(out_) {
1389 param_assert(cpp_*bpc_<=32);
1390 rlen=(columns_*cpp_*bpc_+7)>>3;
1391 op=obuf=1+new unsigned char[rlen+1];
1392 obuf[-1]='\1'; /* Scanline (row) header: describes predictor used */
1393 bpccpp=((cpp_*bpc_+7)&~7)-8;
1394 }
1395
vi_write(char const * buf,slen_t len)1396 void PNGPredictorSub::vi_write(char const*buf, slen_t len) {
1397 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1398 slen_t opleft=rlen-(op-obuf);
1399 register unsigned int i;
1400 if (len==0) {
1401 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1402 assert(obuf!=NULLP);
1403 delete [] (obuf-1);
1404 obuf=(unsigned char*)NULLP;
1405 out.vi_write(0,0);
1406 return;
1407 }
1408 while (p!=pend0) {
1409 i=*p++; *op++=((i-((h>>bpccpp)))/*&255*/); h=(h<<8)|i;
1410 if (--opleft==0) { h=0;
1411 out.vi_write((char*)obuf-1,rlen+1); op=obuf; opleft=rlen;
1412 }
1413 }
1414 }
1415
1416 /* --- */
1417
PNGPredictorUp(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1418 PNGPredictorUp::PNGPredictorUp(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1419 : out(out_) {
1420 rlen=(columns_*cpp_*bpc_+7)>>3;
1421 // fprintf(stderr, "rUp.rlen=%u cpp=%u bpc=%u\n", rlen, cpp_, bpc_);
1422 op=obuf=1+new unsigned char[2*rlen+1];
1423 oq=op+rlen; /* prev scanline */
1424 memset(oq, '\0', rlen);
1425 obuf[-1]='\2'; /* Scanline (row) header: describes predictor used */
1426 }
1427
vi_write(char const * buf,slen_t len)1428 void PNGPredictorUp::vi_write(char const*buf, slen_t len) {
1429 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1430 slen_t opleft=rlen-(op-obuf);
1431 if (len==0) {
1432 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1433 assert(obuf!=NULLP);
1434 delete [] (obuf-1);
1435 obuf=(unsigned char*)NULLP;
1436 out.vi_write(0,0);
1437 return;
1438 }
1439 while (p!=pend0) {
1440 *op++=((*p-*oq)/*&255*/); *oq++=*p++;
1441 if (--opleft==0) {
1442 out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
1443 op=obuf; oq=obuf+rlen;
1444 }
1445 }
1446 }
1447
1448 /* --- */
1449
PNGPredictorAverage(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1450 PNGPredictorAverage::PNGPredictorAverage(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1451 : h(0), /*g(0),*/ out(out_) {
1452 param_assert(cpp_*bpc_<=32);
1453 rlen=(columns_*cpp_*bpc_+7)>>3;
1454 op=obuf=1+new unsigned char[2*rlen+1];
1455 oq=op+rlen; /* prev scanline */
1456 memset(oq, '\0', rlen);
1457 obuf[-1]='\3'; /* Scanline (row) header: describes predictor used */
1458 bpccpp=((cpp_*bpc_+7)&~7)-8;
1459 }
1460
vi_write(char const * buf,slen_t len)1461 void PNGPredictorAverage::vi_write(char const*buf, slen_t len) {
1462 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1463 slen_t opleft=rlen-(op-obuf);
1464 register unsigned int i;
1465 if (len==0) {
1466 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1467 assert(obuf!=NULLP);
1468 delete [] (obuf-1);
1469 obuf=(unsigned char*)NULLP;
1470 out.vi_write(0,0);
1471 return;
1472 }
1473 while (p!=pend0) {
1474 /* vvv Data: *og+h can be 0..510 */
1475 i=*p; *op++=i-((((h>>bpccpp)&255)+*oq)>>1); h=(h<<8)|i; *oq++=*p++;
1476 // i=*p; *op++=(*p-((*oq+h)>>1)/*&255*/); h=i; *oq++=*p++;
1477 if (--opleft==0) {
1478 out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
1479 op=obuf; oq=obuf+rlen; h=0;
1480 }
1481 }
1482 }
1483
1484 /* --- */
1485
1486 /* Dat: egcs-2.91.60 is buggy */
1487 // static inline unsigned abs_(unsigned i) { return ((signed)i)<0 ? -i : i; }
abs_(unsigned i)1488 static inline unsigned abs_(unsigned i) { return ((signed)i)<0 ? (i*-1) : i; }
1489
paeth_predictor(unsigned a,unsigned b,unsigned c)1490 static inline unsigned paeth_predictor(unsigned a, unsigned b, unsigned c) {
1491 /* Code ripped from RFC 2083 (PNG specification), which also says:
1492 * The calculations within the PaethPredictor function must be
1493 * performed exactly, without overflow. Arithmetic modulo 256 is to
1494 * be used only for the final step of subtracting the function result
1495 * from the target byte value.
1496 */
1497 /* a = left, b = above, c = upper left */
1498 unsigned p = a + b - c; /* initial estimate */
1499 unsigned pa = abs_(p - a); /* distances to a, b, c */
1500 unsigned pb = abs_(p - b);
1501 unsigned pc = abs_(p - c);
1502 // assert(abs_(3*(-1))==3);
1503 // fprintf(stderr, "b=%u c=%u %d %d\n", b, c, p-b, ((signed)(p-b))<0 ? (b-p) : (p-b) );
1504 // fprintf(stderr, "pa=%u pb=%u pc=%u\n", pa, pb, pc);
1505 assert(pa<=255);
1506 assert(pb<=255);
1507 assert(pc<=255*2);
1508 /* return nearest of a,b,c, breaking ties in order a,b,c. */
1509 return (pa <= pb && pa <= pc) ? a
1510 : pb <= pc ? b
1511 : c;
1512 }
1513
PNGPredictorPaeth(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1514 PNGPredictorPaeth::PNGPredictorPaeth(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1515 : h(0), g(0), out(out_) {
1516 param_assert(cpp_*bpc_<=32);
1517 rlen=(columns_*cpp_*bpc_+7)>>3;
1518 op=obuf=1+new unsigned char[2*rlen+2];
1519 oq=obuf+rlen+1; /* prev scanline */
1520 memset(obuf+rlen, '\0', rlen+1);
1521 obuf[-1]='\4'; /* Scanline (row) header: describes predictor used */
1522 bpccpp=((cpp_*bpc_+7)&~7)-8;
1523 }
1524
vi_write(char const * buf,slen_t len)1525 void PNGPredictorPaeth::vi_write(char const*buf, slen_t len) {
1526 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1527 slen_t opleft=rlen-(op-obuf);
1528 register unsigned int i;
1529 if (len==0) {
1530 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1531 assert(obuf!=NULLP);
1532 delete [] (obuf-1);
1533 obuf=(unsigned char*)NULLP;
1534 out.vi_write(0,0);
1535 return;
1536 }
1537 while (p!=pend0) {
1538 // assert(0==obuf[rlen] && 4==obuf[-1]);
1539 i=*p; *op++=i-paeth_predictor((h>>bpccpp)&255, *oq, (g>>bpccpp)&255);
1540 h=(h<<8)|i; g=(g<<8)|*oq; *oq++=*p++;
1541 // i=*p; *op++=i-h; h=i; *oq++=*p++;
1542 if (--opleft==0) {
1543 out.vi_write((char*)obuf-1,rlen+1); opleft=rlen;
1544 op=obuf; oq=obuf+rlen+1; h=0; g=0;
1545 }
1546 }
1547 }
1548
1549 /* --- */
1550
1551 #if SIZEOF_INT >= 4
1552 typedef int weight_t;
1553 #else
1554 typedef long weight_t;
1555 #endif
1556
PNGPredictorAutoBadSigned(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1557 PNGPredictorAutoBadSigned::PNGPredictorAutoBadSigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1558 : h(0), g(0), out(out_) {
1559 param_assert(cpp_*bpc_<=32);
1560 opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
1561 obuf=new unsigned char[6*rlen+6];
1562 o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
1563 obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
1564 obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
1565 obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
1566 obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
1567 obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
1568 oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
1569 memset(obuf, '\0', rlen+1);
1570 bpccpp=((cpp_*bpc_+7)&~7)-8;
1571 }
1572
vi_write(char const * buf,slen_t len)1573 void PNGPredictorAutoBadSigned::vi_write(char const*buf, slen_t len) {
1574 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1575 register unsigned int i;
1576 register unsigned raw_x_bpp, prior_x, prior_x_bpp;
1577 if (len==0) {
1578 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1579 assert(obuf!=NULLP);
1580 delete [] obuf;
1581 obuf=(unsigned char*)NULLP;
1582 out.vi_write(0,0);
1583 return;
1584 }
1585 while (p!=pend0) {
1586 raw_x_bpp=(h>>bpccpp) &255;
1587 prior_x=*(o_prior-opleft);
1588 prior_x_bpp=(g>>bpccpp) &255;
1589 i=*p;
1590 *(o_0-opleft)=i;
1591 *(o_1-opleft)=i-raw_x_bpp;
1592 *(o_2-opleft)=i-prior_x;
1593 *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
1594 *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
1595 h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
1596 if (--opleft==0) {
1597 /* Select the predictor having the smallest signed sum of values. */
1598 weight_t min_weight, cur_weight;
1599 unsigned min_pred=0, cur_pred;
1600 register signed char *beg, *end;
1601 min_weight=0; beg=(end=(signed char*)o_0)-rlen; while (beg!=end) min_weight+=*beg++;
1602 if (min_weight<0) min_weight*=-1;
1603 for (cur_pred=1; cur_pred<=4; cur_pred++) {
1604 cur_weight=0; beg=(end=(signed char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=*beg++;
1605 if (cur_weight<0) cur_weight*=-1;
1606 if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
1607 }
1608 // fprintf(stderr, "cp=%u\n", min_pred);
1609
1610 out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
1611 opleft=rlen; h=0; g=0;
1612 }
1613 }
1614 }
1615
1616 /* --- */
1617
PNGPredictorAutoBadUnsigned(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1618 PNGPredictorAutoBadUnsigned::PNGPredictorAutoBadUnsigned(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1619 : h(0), g(0), out(out_) {
1620 param_assert(cpp_*bpc_<=32);
1621 opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
1622 obuf=new unsigned char[6*rlen+6];
1623 o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
1624 obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
1625 obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
1626 obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
1627 obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
1628 obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
1629 oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
1630 memset(obuf, '\0', rlen+1);
1631 bpccpp=((cpp_*bpc_+7)&~7)-8;
1632 }
1633
vi_write(char const * buf,slen_t len)1634 void PNGPredictorAutoBadUnsigned::vi_write(char const*buf, slen_t len) {
1635 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1636 register unsigned int i;
1637 register unsigned raw_x_bpp, prior_x, prior_x_bpp;
1638 // unsigned lines=0;
1639 if (len==0) {
1640 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1641 assert(obuf!=NULLP);
1642 delete [] obuf;
1643 obuf=(unsigned char*)NULLP;
1644 out.vi_write(0,0);
1645 return;
1646 }
1647 // fprintf(stderr, "rlen=%u len=%u opleft=%u\n", rlen, len, opleft);
1648 while (p!=pend0) {
1649 raw_x_bpp=(h>>bpccpp) &255;
1650 prior_x=*(o_prior-opleft);
1651 prior_x_bpp=(g>>bpccpp) &255;
1652 i=*p;
1653 *(o_0-opleft)=i;
1654 *(o_1-opleft)=i-raw_x_bpp;
1655 *(o_2-opleft)=i-prior_x;
1656 *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
1657 *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
1658 h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
1659 if (--opleft==0) {
1660 /* Select the predictor having the smallest unsigned sum of values. */
1661 weight_t min_weight, cur_weight;
1662 unsigned min_pred=0, cur_pred;
1663 register unsigned char *beg, *end;
1664 min_weight=0; beg=(end=(unsigned char*)o_0)-rlen; while (beg!=end) min_weight+=*beg++;
1665 for (cur_pred=1; cur_pred<=4; cur_pred++) {
1666 cur_weight=0; beg=(end=(unsigned char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=*beg++;
1667 if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
1668 }
1669 // fprintf(stderr, "cp=%u\n", min_pred);
1670
1671 out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
1672 opleft=rlen; h=0; g=0;
1673 // lines++;
1674 }
1675 }
1676 // fprintf(stderr, "oen=%u opleft=%u lines=%u\n", len, opleft, lines);
1677 }
1678
1679 /* --- */
1680
PNGPredictorAuto(GenBuffer::Writable & out_,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1681 PNGPredictorAuto::PNGPredictorAuto(GenBuffer::Writable &out_, unsigned char bpc_, slen_t columns_, unsigned char cpp_)
1682 : h(0), g(0), out(out_) {
1683 param_assert(cpp_*bpc_<=32);
1684 opleft=rlen=(columns_*cpp_*bpc_+7)>>3;
1685 obuf=new unsigned char[6*rlen+6];
1686 o_prior=obuf+rlen+1; /* Prior(x): ooprior[-opleft] */
1687 obuf[rlen*1+1]='\0'; o_0=obuf+2*rlen+2;
1688 obuf[rlen*2+2]='\1'; o_1=obuf+3*rlen+3;
1689 obuf[rlen*3+3]='\2'; o_2=obuf+4*rlen+4;
1690 obuf[rlen*4+4]='\3'; o_3=obuf+5*rlen+5;
1691 obuf[rlen*5+5]='\4'; o_4=obuf+6*rlen+6;
1692 oo[0]=o_0; oo[1]=o_1; oo[2]=o_2; oo[3]=o_3; oo[4]=o_4;
1693 memset(obuf, '\0', rlen+1);
1694 bpccpp=((cpp_*bpc_+7)&~7)-8;
1695 }
1696
vi_write(char const * buf,slen_t len)1697 void PNGPredictorAuto::vi_write(char const*buf, slen_t len) {
1698 unsigned char const *p=(unsigned char const*)buf, *pend0=p+len;
1699 register unsigned int i;
1700 register unsigned raw_x_bpp, prior_x, prior_x_bpp;
1701 // unsigned lines=0;
1702 if (len==0) {
1703 assert(opleft==rlen); /* unflushed (half-ready) row disallowed */
1704 assert(obuf!=NULLP);
1705 delete [] obuf;
1706 obuf=(unsigned char*)NULLP;
1707 out.vi_write(0,0);
1708 return;
1709 }
1710 // fprintf(stderr, "rlen=%u len=%u opleft=%u\n", rlen, len, opleft);
1711 while (p!=pend0) {
1712 raw_x_bpp=(h>>bpccpp) &255;
1713 prior_x=*(o_prior-opleft);
1714 prior_x_bpp=(g>>bpccpp) &255;
1715 i=*p;
1716 *(o_0-opleft)=i;
1717 *(o_1-opleft)=i-raw_x_bpp;
1718 *(o_2-opleft)=i-prior_x;
1719 *(o_3-opleft)=i-((raw_x_bpp+prior_x)>>1);
1720 *(o_4-opleft)=i-paeth_predictor(raw_x_bpp, prior_x, prior_x_bpp);
1721 h=(h<<8)|i; g=(g<<8)|*(o_prior-opleft); *(o_prior-opleft)=*p++;
1722 if (--opleft==0) {
1723 /* Select the predictor having the smallest unsigned sum of values. */
1724 weight_t min_weight, cur_weight;
1725 unsigned min_pred=0, cur_pred;
1726 register signed char *beg, *end;
1727 /* abs_(...) here converts '\xFF' to 1. Good. */
1728 min_weight=0; beg=(end=(signed char*)o_0)-rlen; while (beg!=end) min_weight+=abs_(*beg++);
1729 for (cur_pred=1; cur_pred<=4; cur_pred++) {
1730 cur_weight=0; beg=(end=(signed char*)oo[cur_pred])-rlen; while (beg!=end) cur_weight+=abs_(*beg++);
1731 if (cur_weight<min_weight) { min_weight=cur_weight; min_pred=cur_pred; }
1732 }
1733 // fprintf(stderr, "cp=%u\n", min_pred);
1734
1735 out.vi_write((char*)(oo[min_pred]-rlen-1),rlen+1);
1736 opleft=rlen; h=0; g=0;
1737 // lines++;
1738 }
1739 }
1740 // fprintf(stderr, "oen=%u opleft=%u lines=%u\n", len, opleft, lines);
1741 }
1742
1743 /* --- */
1744
newPredictor(GenBuffer::Writable & out_,unsigned char type,unsigned char bpc_,slen_t columns_,unsigned char cpp_)1745 Encoder* PSEncoder::newPredictor(GenBuffer::Writable &out_, unsigned char type, unsigned char bpc_, slen_t columns_, unsigned char cpp_) {
1746 switch ((unsigned)type) {
1747 /* Imp: make these faster with `register int' etc. tricks */
1748 /* See also better_predictor in rule.cpp for the list of predictor numbers */
1749 case 1: return new Filter::VerbatimE(out_);
1750 case 2: return new TIFFPredictor2(out_, bpc_, columns_, cpp_);
1751 case 10: return new PNGPredictorNone(out_, bpc_, columns_, cpp_);
1752 case 11: return new PNGPredictorSub(out_, bpc_, columns_, cpp_);
1753 case 12: return new PNGPredictorUp(out_, bpc_, columns_, cpp_);
1754 case 13: return new PNGPredictorAverage(out_, bpc_, columns_, cpp_);
1755 case 14: return new PNGPredictorPaeth(out_, bpc_, columns_, cpp_);
1756 case 15: return new PNGPredictorAuto(out_, bpc_, columns_, cpp_);
1757 case 45: return new PNGPredictorAutoBadUnsigned(out_, bpc_, columns_, cpp_); /* pts' extension */
1758 case 55: return new PNGPredictorAutoBadSigned(out_, bpc_, columns_, cpp_); /* pts' extension */
1759 }
1760 // fprintf(stderr, "pred=%d\n", type);
1761 param_assert(0 && "invalid predictor requested");
1762 return (Encoder*)0; /*notreached*/
1763 }
1764
1765 /* __END__ */
1766