summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mupdf/fitz/filter.h1
-rw-r--r--source/fitz/filter-thunder.c153
-rw-r--r--source/fitz/load-tiff.c13
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);
}