summaryrefslogtreecommitdiff
path: root/Build/source/libs/pplib/pplib-src/src/util/utilfpred.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/pplib/pplib-src/src/util/utilfpred.c')
-rw-r--r--Build/source/libs/pplib/pplib-src/src/util/utilfpred.c778
1 files changed, 778 insertions, 0 deletions
diff --git a/Build/source/libs/pplib/pplib-src/src/util/utilfpred.c b/Build/source/libs/pplib/pplib-src/src/util/utilfpred.c
new file mode 100644
index 00000000000..9203c5e0742
--- /dev/null
+++ b/Build/source/libs/pplib/pplib-src/src/util/utilfpred.c
@@ -0,0 +1,778 @@
+/* predictor filters; common for flate and lzw */
+
+#include "utilmem.h"
+#include "utillog.h"
+#include "utilfpred.h"
+
+/*
+Here we implement predictor filters used with flate and lzw compressions in PDF streams. The main idea of data prediction
+is to compute and output the differences between data records instead of those records. Adjacent pixels in images are usually
+similar, so differences between pixel values tends to be zero. And both Flate and LZW performs better when the input
+is rather smooth. Although a preliminary use of predictors is related to bitmap data, The actual need for predictor filter
+came from the fact that xref streams may also be predicted (usually with PNG up-predictor).
+
+PDF specification allows to use several predictor algorithms, specified by /Predictor key in /DecodeParms dictionary:
+
+ 1 - no predictor (default)
+ 2 - TIFF horizontal predictor
+ 10 - PNG none predictor
+ 11 - PNG sub predictor
+ 12 - PNG up predictor
+ 13 - PNG average predictor
+ 14 - PNG paeth predictor
+
+All PNG predictors works on bytes, regardless the image color-depth. While encoding, every input data byte is decreased
+by the appropriate byte of the previous pixel. Even if the pixel does not fit a full byte, PNG predictors use an artificial
+pixel size rounded up to a full byte. PNG predictors utilizes previous (left) pixel, pixel above and previous to above
+pixel. In case of PNG, the type of the predictor is written on a dedicated byte at the beginning of every scanline. It
+means all predictor functions must maintain and information about left, above and left-above pixels.
+
+Despite the same differencing idea, TIFF predictors are different. The prediction process bases on pixel components,
+which are not necessarily bytes (component of a pixel is added/substracted from a relevant component of a previous
+pixel). In TIFF predictor 2, only the previous (the left) pixel is taken into account, there is no need to keep
+an information about other surrounding pixels. Also there is no expicit algorithm marker in data; the same prediction
+method is applied to all input rows.
+
+Not surprisingly, predictor encoders and decoders are pretty similar. Encoders take some input value and the previous
+input value (or 0 at the beginning of the scanline) and output a difference between them. Decoders takes an input value,
+previously decoded value (or zero) and outputs their sum. When encoding, the result is cast to the proper unsigned integer,
+when decoding, modulo 256 (or appropriate) is used, which makes encoding and decoding looseless.
+
+Some extra bits trickery is involved in TIFF predictor function, when components don't fit bytes boundary. In that case,
+an input is treated as a bits stream. Every input byte is "buffered" in a larger integer, as its lower bits (from right).
+Every output value is taken from its higher (left) bits. In a special case of bits-per-component equal 1, we buffer all
+pixel bits and use XOR to compute bits difference between pixels. I've excerpted that trick from poppler, but I'm not
+really sure if it works any better, especially when the number of components per pixel is 1. In that case we do a hard
+bit-by-bit work anyway.
+
+In PNG prediction, we record every pixel byte (in decoded form) in state->rowsave. At the end of a scanline
+we copy state->rowsave to state->rowup, so that in the next scanline we can access up-pixel byte.
+Left pixel byte is accessed as state->rowsave (the byte recently stored or virtual left edge byte \0).
+Up-left pixel byte is accessed via state->rowup, but with state->pixelsize offset (same as left byte, possibly \0
+at the left edge of the row). Both state->rowup and state->rowsave has a safe span of pixelsize bytes on the left,
+that are permanently \0.
+*/
+
+#define predictor_component_t uint16_t
+#define predictor_pixel1b_t uint32_t
+
+#define MAX_COMPONENTS 8
+
+struct predictor_state {
+ int default_predictor; /* default predictor indicator */
+ int current_predictor; /* current predictor, possibly taken from algorithm marker in PNG data */
+ int rowsamples; /* number of pixels in a scanline (/DecodeParms << /Columns ... >>) */
+ int compbits; /* number of bits per component (/DecodeParms << /BitsPerComponent ... >>) */
+ int components; /* number of components (/DecodeParms << /Colors ... >>) */
+ uint8_t *buffer; /* temporary private buffer area */
+ uint8_t *rowin; /* an input row buffer position */
+ int rowsize; /* size of a current scanline in bytes (rounded up) */
+ int rowend; /* an input buffer end position */
+ int rowindex; /* an output buffer position */
+ union {
+ struct { /* used by PNG predictor codecs */
+ uint8_t *rowup, *rowsave; /* previous scanline buffers */
+ int predictorbyte; /* flag indicating that algorithm byte is read/written */
+ int pixelsize; /* number of bytes per pixel (rounded up) */
+ };
+ struct { /* used by TIFF predictor codecs */
+ predictor_component_t compbuffer[MAX_COMPONENTS];
+ union {
+ predictor_component_t *prevcomp; /* an array of left pixel components, typically eq ->compbuffer */
+ predictor_pixel1b_t *prevpixel; /* left pixel value stored on a single integer (for 1bit color-depth) */
+ };
+ int compin, compout; /* bit stream buffers */
+ int bitsin, bitsout; /* bit stream counters */
+ int sampleindex; /* pixel counter */
+ int compindex; /* component counter */
+ int pixbufsize; /* size of pixel buffer in bytes */
+ };
+ };
+ int flush;
+ int status;
+};
+
+typedef union { predictor_state *predictorstate; void *voidstate; } predictor_state_pointer; // to avoid 'dereferencing type-puned ...' warnings
+
+enum {
+ STATUS_LAST = 0,
+ STATUS_CONTINUE = 1 // any value different then IOFEOF, IOFERR, ... which are < 0
+};
+
+/*
+Predictor type identifiers (pdf spec 76). lpdf doesn't hire the codec if predictor is 1. Predictor 15 indicates
+that the type of PNG prediction algorithm may change in subsequent lines. We always check algorithm marker anyway.
+*/
+
+enum predictor_code {
+ NONE_PREDICTOR = 1,
+ TIFF_PREDICTOR = 2,
+ PNG_NONE_PREDICTOR = 10,
+ PNG_SUB_PREDICTOR = 11,
+ PNG_UP_PREDICTOR = 12,
+ PNG_AVERAGE_PREDICTOR = 13,
+ PNG_PAETH_PREDICTOR = 14,
+ PNG_OPTIMUM_PREDICTOR = 15
+};
+
+predictor_state * predictor_decoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits)
+{
+ int rowsize, pixelsize;
+#define storage_pos(b, p, size) ((b = p), (p += size))
+ uint8_t *buffer, *p;
+ size_t buffersize;
+
+ pixelsize = (components * compbits + 7) >> 3; // to bytes, rounded up
+ rowsize = (rowsamples * components * compbits + 7) >> 3;
+
+ state->default_predictor = state->current_predictor = predictor;
+ state->rowsamples = rowsamples;
+ state->components = components;
+ state->compbits = compbits;
+
+ if (predictor == TIFF_PREDICTOR)
+ { /* tiff predictor */
+ size_t compbuf, pixbuf;
+ compbuf = components * sizeof(predictor_component_t);
+ pixbuf = 1 * sizeof(predictor_pixel1b_t);
+ state->pixbufsize = (int)(compbuf > pixbuf ? compbuf : pixbuf);
+ buffersize = rowsize * sizeof(uint8_t);
+ buffer = (uint8_t *)util_calloc(buffersize, 1);
+ if ((size_t)state->pixbufsize > sizeof(state->compbuffer)) // components > MAX_COMPONENTS
+ state->prevcomp = (predictor_component_t *)util_calloc(state->pixbufsize, 1);
+ else
+ state->prevcomp = state->compbuffer;
+ // &state->prevcomp == &state->prevpixel
+ state->sampleindex = state->compindex = 0;
+ state->bitsin = state->bitsout = 0;
+ state->compin = state->compout = 0;
+ }
+ else
+ { /* png predictors */
+ buffersize = (3 * rowsize + 2 * pixelsize + 1) * sizeof(uint8_t);
+ p = buffer = (uint8_t *)util_calloc(buffersize, 1);
+ storage_pos(state->rowin, p, 1 + rowsize); // one extra byte for prediction algorithm tag
+ p += pixelsize; // pixelsize extra bytes for virtual left pixel at the edge, eg. rowup[-1] (permanently \0)
+ storage_pos(state->rowup, p, rowsize); // actual row byte
+ p += pixelsize; // ditto
+ storage_pos(state->rowsave, p, rowsize);
+ state->pixelsize = pixelsize;
+ state->predictorbyte = 0;
+ }
+ state->buffer = buffer;
+ state->rowsize = rowsize;
+ state->rowindex = 0;
+ state->rowend = 0;
+ state->status = STATUS_CONTINUE;
+ return state;
+}
+
+predictor_state * predictor_encoder_init (predictor_state *state, int predictor, int rowsamples, int components, int compbits)
+{
+ return predictor_decoder_init(state, predictor, rowsamples, components, compbits);
+}
+
+void predictor_decoder_close (predictor_state *state)
+{
+ util_free(state->buffer);
+ if (state->default_predictor == TIFF_PREDICTOR && state->prevcomp != NULL && state->prevcomp != state->compbuffer)
+ util_free(state->prevcomp);
+}
+
+void predictor_encoder_close (predictor_state *state)
+{
+ predictor_decoder_close(state);
+}
+
+/*
+All predoctor codecs first read the entire data row into a buffer. This is not crucial for the process,
+but allows to separate read/write states. In particular, there is one place in which codec functions
+may return on EOD.
+*/
+
+#define start_row(state) (state->rowindex = 0, state->rowin = state->buffer)
+
+static int read_scanline (predictor_state *state, iof *I, int size)
+{
+ int rowtail, left;
+ while ((rowtail = size - state->rowend) > 0)
+ {
+ left = (int)iof_left(I);
+ if (left >= rowtail)
+ {
+ memcpy(state->buffer + state->rowend, I->pos, (size_t)rowtail);
+ state->rowend += rowtail;
+ I->pos += rowtail;
+ start_row(state);
+ break;
+ }
+ else
+ {
+ if ((rowtail = left) > 0)
+ {
+ memcpy(state->buffer + state->rowend, I->pos, (size_t)rowtail);
+ state->rowend += rowtail;
+ I->pos += rowtail;
+ }
+ if (iof_input(I) == 0)
+ {
+ if (state->rowend == 0) // no scanline to process, no more input
+ return state->flush ? IOFEOF : IOFEMPTY;
+ /* If we are here, there is an incomplete scanline in buffer:
+ - if there is a chance for more (state->flush == 0), than wait for more
+ - otherwise encode/decode the last incomplete line?
+ pdf spec p. 76 says that "A row occupies a whole number of bytes",
+ so this situation should be considered abnormal (not found so far).
+ */
+ if (!state->flush)
+ return IOFEMPTY;
+ loggerf("incomplete scanline in predictor filter");
+ //return IOFERR;
+ state->status = STATUS_LAST;
+ state->rowsize -= size - state->rowend;
+ start_row(state);
+ break;
+ }
+ }
+ }
+ return STATUS_CONTINUE;
+}
+
+#define read_row(state, I, size, status) if ((status = read_scanline(state, I, size)) != STATUS_CONTINUE) return status
+
+#define ensure_output_bytes(O, n) if (!iof_ensure(O, n)) return IOFFULL
+
+#define tobyte(c) ((uint8_t)(c))
+#define tocomp(c) ((uint16_t)(c))
+
+#define row_byte(state) (state->rowin[state->rowindex])
+
+/* png predictor macros; on bytes */
+
+#define up_pixel_byte(state) (state->rowup[state->rowindex])
+#define upleft_pixel_byte(state) (state->rowup[state->rowindex - state->pixelsize])
+#define left_pixel_byte(state) (state->rowsave[state->rowindex - state->pixelsize])
+#define save_pixel_byte(state, c) (state->rowsave[state->rowindex] = (uint8_t)(c))
+
+/* tiff predictor macros; on components */
+
+#define left_pixel_component(state) (state->prevcomp[state->compindex]) // tiff predictor with 2, 4, 8, 16 components
+#define left_pixel_value(state) (state->prevpixel[0]) // tiff predictor with 1bit components
+
+/* assignment in conditional
+#define save_pixel_component(state, c) ((void)\
+ ((state->prevcomp[state->compindex] = (predictor_component_t)(c)), \
+ ++state->compindex, (state->compindex < state->components || (state->compindex = 0))))
+*/
+#define save_pixel_component(state, c) \
+ do { state->prevcomp[state->compindex] = (predictor_component_t)(c); if (++state->compindex >= state->components) state->compindex = 0; } while (0)
+
+#define save_pixel_value(state, c) (state->prevpixel[0] = (predictor_pixel1b_t)(c))
+
+/* Once the codec function is done with the scanline, we set imaginary left pixel data to zero, and reset row counters to
+zero in order to allow buffering another input scanline. */
+
+#define reset_row(state) state->rowend = 0
+
+#define reset_png_row(state) (memcpy(state->rowup, state->rowsave, state->rowsize), state->predictorbyte = 0, reset_row(state))
+
+#define reset_tiff_row(state) \
+ memset(state->prevcomp, 0, state->pixbufsize), \
+ state->bitsin = state->bitsout = 0, \
+ state->compin = state->compout = 0, \
+ reset_row(state), \
+ state->sampleindex = state->compindex = 0
+
+/* PNG paeth predictor function; http://www.libpng.org/pub/png/book/chapter09.html
+Compute the base value p := left + up - upleft, then choose that byte the closest
+(of the smallest absolute difference) to the base value. Left byte has a precedence. */
+
+
+static int paeth (predictor_state *state)
+{
+ int p, p1, p2, p3;
+ p = left_pixel_byte(state) + up_pixel_byte(state) - upleft_pixel_byte(state);
+ p1 = p >= left_pixel_byte(state) ? (p - left_pixel_byte(state)) : (left_pixel_byte(state) - p);
+ p2 = p >= up_pixel_byte(state) ? (p - up_pixel_byte(state)) : (up_pixel_byte(state) - p);
+ p3 = p >= upleft_pixel_byte(state) ? (p - upleft_pixel_byte(state)) : (upleft_pixel_byte(state) - p);
+ return (p1 <= p2 && p1 <= p3) ? left_pixel_byte(state) : (p2 <= p3 ? up_pixel_byte(state) : upleft_pixel_byte(state));
+}
+
+/* predictor decoder */
+
+iof_status predictor_decode_state (iof *I, iof *O, predictor_state *state)
+{
+ int status, c, d, outbytes;
+ while (state->status == STATUS_CONTINUE)
+ {
+ if (state->default_predictor >= 10) // PNG predictor?
+ {
+ read_row(state, I, state->rowsize + 1, status);
+ if (state->predictorbyte == 0)
+ { // we could actually check state->rowin <> state->buffer, but we need this flag for encoder anyway
+ state->current_predictor = row_byte(state) + 10;
+ state->predictorbyte = 1;
+ ++state->rowin;
+ }
+ }
+ else
+ {
+ read_row(state, I, state->rowsize, status);
+ }
+ switch (state->current_predictor)
+ {
+ case NONE_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ iof_set(O, c);
+ }
+ reset_row(state);
+ break;
+ case TIFF_PREDICTOR:
+ switch (state->compbits)
+ {
+ case 1:
+ outbytes = (state->components + 7) >> 3;
+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex)
+ {
+ ensure_output_bytes(O, outbytes);
+ while (state->bitsin < state->components)
+ {
+ state->compin = (state->compin << 8) | row_byte(state);
+ state->bitsin += 8;
+ ++state->rowindex;
+ }
+ state->bitsin -= state->components;
+ d = state->compin >> state->bitsin;
+ state->compin &= (1 << state->bitsin) - 1;
+ c = d ^ left_pixel_value(state);
+ save_pixel_value(state, c);
+ state->compout = (state->compout << state->components) | c;
+ state->bitsout += state->components;
+ while (state->bitsout >= 8)
+ {
+ state->bitsout -= 8;
+ iof_set(O, state->compout >> state->bitsout);
+ state->compout &= (1 << state->bitsout) - 1;
+ }
+ }
+ if (state->bitsout > 0)
+ {
+ ensure_output_bytes(O, 1);
+ iof_set(O, state->compin << (8 - state->bitsout));
+ }
+ break;
+ case 2: case 4:
+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex)
+ {
+ for ( ; state->compindex < state->components; ) // state->compindex is ++ed by save_pixel_component()
+ {
+ ensure_output_bytes(O, 1);
+ if (state->bitsin < state->compbits)
+ {
+ state->compin = (state->compin << 8) | row_byte(state);
+ state->bitsin += 8;
+ ++state->rowindex;
+ }
+ state->bitsin -= state->compbits;
+ d = state->compin >> state->bitsin;
+ state->compin &= (1 << state->bitsin) - 1;
+ c = (d + left_pixel_component(state)) & 0xff;
+ save_pixel_component(state, c);
+ state->compout = (state->compout << state->compbits) | c;
+ state->bitsout += state->compbits;
+ if (state->bitsout >= 8)
+ {
+ state->bitsout -= 8;
+ iof_set(O, state->compout >> state->bitsout);
+ state->compout &= (1 << state->bitsout) - 1;
+ }
+ }
+ }
+ if (state->bitsout > 0)
+ {
+ ensure_output_bytes(O, 1);
+ iof_set(O, state->compin << (8 - state->bitsout));
+ }
+ break;
+ case 8:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = (row_byte(state) + left_pixel_component(state)) & 0xff;
+ save_pixel_component(state, c);
+ iof_set(O, c);
+ }
+ break;
+ case 16:
+ for ( ; state->rowindex < state->rowsize - 1; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 2);
+ d = row_byte(state) << 8;
+ ++state->rowindex;
+ d |= row_byte(state);
+ c = (d + left_pixel_component(state)) & 0xffff;
+ save_pixel_component(state, c);
+ iof_set2(O, c >> 8, c & 0xff);
+ }
+ break;
+ default:
+ return IOFERR;
+ }
+ reset_tiff_row(state);
+ break;
+ case PNG_NONE_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ save_pixel_byte(state, c); // next row may need it
+ iof_set(O, c);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_SUB_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = (row_byte(state) + left_pixel_byte(state)) & 0xff;
+ save_pixel_byte(state, c);
+ iof_set(O, c);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_UP_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = (row_byte(state) + up_pixel_byte(state)) & 0xff;
+ save_pixel_byte(state, c);
+ iof_set(O, c);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_AVERAGE_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = (row_byte(state) + ((up_pixel_byte(state) + left_pixel_byte(state)) / 2)) & 0xff;
+ save_pixel_byte(state, c);
+ iof_set(O, c);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_PAETH_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = (row_byte(state) + paeth(state)) & 0xff;
+ save_pixel_byte(state, c);
+ iof_set(O, c);
+ }
+ reset_png_row(state);
+ break;
+ //case PNG_OPTIMUM_PREDICTOR: // valid as default_redictor, but not as algorithm identifier byte
+ default:
+ return IOFERR;
+ }
+ }
+ return state->status == STATUS_LAST ? IOFERR : IOFEOF;
+}
+
+/* predictor encoder */
+
+iof_status predictor_encode_state (iof *I, iof *O, predictor_state *state)
+{
+ int status, c, d, outbytes;
+ while (state->status == STATUS_CONTINUE)
+ {
+ read_row(state, I, state->rowsize, status);
+ if (state->current_predictor >= 10 && state->predictorbyte == 0)
+ {
+ ensure_output_bytes(O, 1);
+ iof_set(O, state->current_predictor - 10);
+ state->predictorbyte = 1;
+ }
+ switch (state->current_predictor)
+ {
+ case NONE_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ iof_set(O, c);
+ }
+ reset_row(state);
+ break;
+ case TIFF_PREDICTOR:
+ switch (state->compbits)
+ {
+ case 1:
+ outbytes = (state->components + 7) >> 3;
+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex)
+ {
+ ensure_output_bytes(O, outbytes);
+ while (state->bitsin < state->components)
+ {
+ state->compin = (state->compin << 8) | row_byte(state);
+ state->bitsin += 8;
+ ++state->rowindex;
+ }
+ state->bitsin -= state->components;
+ c = state->compin >> state->bitsin;
+ state->compin &= (1 << state->bitsin) - 1;
+ d = c ^ left_pixel_value(state);
+ save_pixel_value(state, c);
+ state->compout = (state->compout << state->components) | d;
+ state->bitsout += state->components;
+ while (state->bitsout >= 8)
+ {
+ state->bitsout -= 8;
+ iof_set(O, state->compout >> state->bitsout);
+ state->compout &= (1 << state->bitsout) - 1;
+ }
+ }
+ if (state->bitsout > 0)
+ {
+ ensure_output_bytes(O, 1);
+ iof_set(O, state->compin << (8 - state->bitsout));
+ }
+ break;
+ case 2: case 4:
+ for ( ; state->sampleindex < state->rowsamples; ++state->sampleindex)
+ {
+ for ( ; state->compindex < state->components; )
+ {
+ ensure_output_bytes(O, 1);
+ if (state->bitsin < state->compbits)
+ {
+ state->compin = (state->compin << 8) | row_byte(state);
+ state->bitsin += 8;
+ ++state->rowindex;
+ }
+ state->bitsin -= state->compbits;
+ c = state->compin >> state->bitsin;
+ state->compin &= (1 << state->bitsin) - 1;
+ d = tocomp(c - left_pixel_component(state));
+ save_pixel_component(state, c);
+ state->compout = (state->compout << state->compbits) | d;
+ state->bitsout += state->compbits;
+ if (state->bitsout >= 8)
+ {
+ state->bitsout -= 8;
+ iof_set(O, state->compout >> state->bitsout);
+ state->compout &= (1 << state->bitsout) - 1;
+ }
+ }
+ }
+ if (state->bitsout > 0)
+ {
+ ensure_output_bytes(O, 1);
+ iof_set(O, state->compin << (8 - state->bitsout));
+ }
+ break;
+ case 8:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ d = tobyte(c - left_pixel_component(state));
+ save_pixel_component(state, c);
+ iof_set(O, d);
+ }
+ break;
+ case 16:
+ for ( ; state->rowindex < state->rowsize - 1; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 2);
+ c = row_byte(state) << 8;
+ ++state->rowindex;
+ c |= row_byte(state);
+ d = tocomp(c - left_pixel_component(state));
+ save_pixel_component(state, c);
+ iof_set2(O, d >> 8, d & 0xff);
+ }
+ break;
+ default:
+ return IOFERR;
+ }
+ reset_tiff_row(state);
+ break;
+ case PNG_NONE_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ save_pixel_byte(state, c); // next row may need it
+ iof_set(O, c);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_SUB_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ d = tobyte(c - left_pixel_byte(state));
+ save_pixel_byte(state, c);
+ iof_set(O, d);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_OPTIMUM_PREDICTOR: // not worthy to perform optimization
+ case PNG_UP_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ d = tobyte(c - up_pixel_byte(state));
+ save_pixel_byte(state, c);
+ iof_set(O, d);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_AVERAGE_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ d = tobyte(c - ((up_pixel_byte(state) + left_pixel_byte(state)) >> 1));
+ save_pixel_byte(state, c);
+ iof_set(O, d);
+ }
+ reset_png_row(state);
+ break;
+ case PNG_PAETH_PREDICTOR:
+ for ( ; state->rowindex < state->rowsize; ++state->rowindex)
+ {
+ ensure_output_bytes(O, 1);
+ c = row_byte(state);
+ d = tobyte(c - paeth(state));
+ save_pixel_byte(state, c);
+ iof_set(O, d);
+ }
+ reset_png_row(state);
+ break;
+ default:
+ return IOFERR;
+ }
+ }
+ return state->status == STATUS_LAST ? IOFERR : IOFEOF;
+}
+
+iof_status predictor_decode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits)
+{
+ predictor_state state;
+ int ret;
+ predictor_decoder_init(&state, predictor, rowsamples, components, compbits);
+ state.flush = 1;
+ ret = predictor_decode_state(I, O, &state);
+ predictor_decoder_close(&state);
+ return ret;
+}
+
+iof_status predictor_encode (iof *I, iof *O, int predictor, int rowsamples, int components, int compbits)
+{
+ predictor_state state;
+ int ret;
+ predictor_encoder_init(&state, predictor, rowsamples, components, compbits);
+ state.flush = 1;
+ ret = predictor_encode_state(I, O, &state);
+ predictor_encoder_close(&state);
+ return ret;
+}
+
+/* filters */
+
+// predictor decoder function
+
+static size_t predictor_decoder (iof *F, iof_mode mode)
+{
+ predictor_state *state;
+ iof_status status;
+ size_t tail;
+
+ state = iof_filter_state(predictor_state *, F);
+ switch(mode)
+ {
+ case IOFLOAD:
+ case IOFREAD:
+ if (F->flags & IOF_STOPPED)
+ return 0;
+ tail = iof_tail(F);
+ F->pos = F->buf + tail;
+ F->end = F->buf + F->space;
+ do {
+ status = predictor_decode_state(F->next, F, state);
+ } while (mode == IOFLOAD && status == IOFFULL && iof_resize_buffer(F));
+ return iof_decoder_retval(F, "predictor", status);
+ case IOFCLOSE:
+ predictor_decoder_close(state);
+ iof_free(F);
+ return 0;
+ default:
+ break;
+ }
+ return 0;
+}
+
+// predictor encoder function
+
+static size_t predictor_encoder (iof *F, iof_mode mode)
+{
+ predictor_state *state;
+ iof_status status;
+
+ state = iof_filter_state(predictor_state *, F);
+ switch (mode)
+ {
+ case IOFFLUSH:
+ state->flush = 1;
+ FALLTHRU // fall through
+ case IOFWRITE:
+ F->end = F->pos;
+ F->pos = F->buf;
+ status = predictor_encode_state(F, F->next, state);
+ return iof_encoder_retval(F, "predictor", status);
+ case IOFCLOSE:
+ if (!state->flush)
+ predictor_encoder(F, IOFFLUSH);
+ predictor_encoder_close(state);
+ iof_free(F);
+ return 0;
+ default:
+ break;
+ }
+ return 0;
+}
+
+iof * iof_filter_predictor_decoder (iof *N, int predictor, int rowsamples, int components, int compbits)
+{
+ iof *I;
+ predictor_state_pointer P;
+ I = iof_filter_reader(predictor_decoder, sizeof(predictor_state), &P.voidstate);
+ iof_setup_next(I, N);
+ if (predictor_decoder_init(P.predictorstate, predictor, rowsamples, components, compbits) == NULL)
+ {
+ iof_discard(I);
+ return NULL;
+ }
+ P.predictorstate->flush = 1;
+ return I;
+}
+
+iof * iof_filter_predictor_encoder (iof *N, int predictor, int rowsamples, int components, int compbits)
+{
+ iof *O;
+ predictor_state_pointer P;
+ O = iof_filter_writer(predictor_encoder, sizeof(predictor_state), &P.voidstate);
+ iof_setup_next(O, N);
+ if (predictor_encoder_init(P.predictorstate, predictor, rowsamples, components, compbits) == NULL)
+ {
+ iof_discard(O);
+ return NULL;
+ }
+ return O;
+}