diff options
-rw-r--r-- | include/mupdf/fitz/filter.h | 1 | ||||
-rw-r--r-- | source/fitz/filter-thunder.c | 153 | ||||
-rw-r--r-- | source/fitz/load-tiff.c | 13 |
3 files changed, 167 insertions, 0 deletions
diff --git a/include/mupdf/fitz/filter.h b/include/mupdf/fitz/filter.h index 5192540e..58dc3e21 100644 --- a/include/mupdf/fitz/filter.h +++ b/include/mupdf/fitz/filter.h @@ -34,5 +34,6 @@ void fz_drop_jbig2_globals_imp(fz_context *ctx, fz_storable *globals); fz_stream *fz_open_sgilog16(fz_context *ctx, fz_stream *chain, int w); fz_stream *fz_open_sgilog24(fz_context *ctx, fz_stream *chain, int w); fz_stream *fz_open_sgilog32(fz_context *ctx, fz_stream *chain, int w); +fz_stream *fz_open_thunder(fz_context *ctx, fz_stream *chain, int w); #endif diff --git a/source/fitz/filter-thunder.c b/source/fitz/filter-thunder.c new file mode 100644 index 00000000..65cb115b --- /dev/null +++ b/source/fitz/filter-thunder.c @@ -0,0 +1,153 @@ +#include "mupdf/fitz/system.h" +#include "mupdf/fitz/context.h" +#include "mupdf/fitz/stream.h" + +/* 4bit greyscale Thunderscan decoding */ + +typedef struct fz_thunder_s fz_thunder; + +struct fz_thunder_s +{ + fz_stream *chain; + int lastpixel; + int run; + int pixel; + + int len; + unsigned char *buffer; +}; + +static int +next_thunder(fz_context *ctx, fz_stream *stm, size_t max) +{ + fz_thunder *state = stm->state; + unsigned char *p = state->buffer; + unsigned char *ep; + int c, v, i, pixels, index; + + if (max > state->len); + max = state->len; + + ep = p + max; + + c = 0; + while (p < ep && c >= 0) + { + pixels = 0; + v = 0; + + while (pixels < 2) + { + if (state->run > 0) + { + v <<= 4; + v |= state->pixel & 0xf; + state->pixel >>= 4; + state->run--; + pixels++; + + if (state->run > 2) + state->pixel |= ((state->pixel >> 4) & 0xf) << 8; + } + else + { + c = fz_read_byte(ctx, state->chain); + if (c < 0) + break; + + switch ((c >> 6) & 0x3) + { + case 0x0: /* run of pixels identical to last pixel */ + state->run = c; + state->pixel = (state->lastpixel << 8) | (state->lastpixel << 4) | (state->lastpixel << 0); + break; + + case 0x1: /* three pixels with 2bit deltas to last pixel */ + for (i = 0; i < 3; i++) + { + static const int deltas[] = { 0, 1, 0, -1 }; + index = (c >> (4 - i * 2)) & 0x3; + if (index == 2) + continue; + + state->lastpixel = (state->lastpixel + deltas[index]) & 0xf; + state->pixel <<= 4; + state->pixel |= state->lastpixel; + state->run++; + } + break; + + case 0x2: /* two pixels with 3bit deltas to last pixel */ + for (i = 0; i < 2; i++) + { + static const int deltas[] = { 0, 1, 2, 3, 0, -3, -2, -1 }; + index = (c >> (3 - i * 3)) & 0x7; + if (index == 4) + continue; + + state->lastpixel = (state->lastpixel + deltas[index]) & 0xf; + state->pixel <<= 4; + state->pixel |= state->lastpixel; + state->run++; + } + break; + + case 0x3: /* a single raw 4bit pixel */ + state->run = 1; + state->pixel = c & 0xf; + state->lastpixel = state->pixel & 0xf; + break; + } + } + } + + if (pixels) + *p++ = v; + } + + stm->rp = state->buffer; + stm->wp = p; + stm->pos += p - state->buffer; + + if (stm->rp != p) + return *stm->rp++; + return EOF; +} + +static void +close_thunder(fz_context *ctx, void *state_) +{ + fz_thunder *state = (fz_thunder *)state_; + fz_stream *chain = state->chain; + + fz_free(ctx, state->buffer); + fz_free(ctx, state); + fz_drop_stream(ctx, chain); +} + +fz_stream * +fz_open_thunder(fz_context *ctx, fz_stream *chain, int w) +{ + fz_thunder *state = NULL; + + fz_var(state); + + fz_try(ctx) + { + state = fz_malloc_struct(ctx, fz_thunder); + state->chain = chain; + state->run = 0; + state->pixel = 0; + state->lastpixel = 0; + state->len = w / 2; + state->buffer = fz_malloc(ctx, state->len); + } + fz_catch(ctx) + { + fz_free(ctx, state); + fz_drop_stream(ctx, chain); + fz_rethrow(ctx); + } + + return fz_new_stream(ctx, state, next_thunder, close_thunder); +} diff --git a/source/fitz/load-tiff.c b/source/fitz/load-tiff.c index b57497a2..87e350f0 100644 --- a/source/fitz/load-tiff.c +++ b/source/fitz/load-tiff.c @@ -171,6 +171,14 @@ fz_decode_tiff_sgilog24(fz_context *ctx, struct tiff *tiff, fz_stream *chain, un } static void +fz_decode_tiff_thunder(fz_context *ctx, struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen, int w) +{ + fz_stream *stm = fz_open_thunder(ctx, chain, w); + fz_read(ctx, stm, wp, wlen); + fz_drop_stream(ctx, stm); +} + +static void fz_decode_tiff_sgilog32(fz_context *ctx, struct tiff *tiff, fz_stream *chain, unsigned char *wp, int wlen, int w) { fz_stream *stm = fz_open_sgilog32(ctx, chain, w); @@ -518,6 +526,11 @@ fz_decode_tiff_strips(fz_context *ctx, struct tiff *tiff) case 34677: fz_decode_tiff_sgilog24(ctx, tiff, stm, wp, wlen, tiff->imagewidth); break; + case 32809: + if (tiff->bitspersample != 4) + fz_throw(ctx, FZ_ERROR_GENERIC, "invalid bits per pixel in thunder encoding"); + fz_decode_tiff_thunder(ctx, tiff, stm, wp, wlen, tiff->imagewidth); + break; default: fz_throw(ctx, FZ_ERROR_GENERIC, "unknown TIFF compression: %d", tiff->compression); } |