eBookReaderSwitch/source/fitz/filter-thunder.c

144 lines
2.8 KiB
C
Raw Normal View History

#include "mupdf/fitz.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 > (size_t)state->len)
max = (size_t)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_drop_stream(ctx, state->chain);
fz_free(ctx, state->buffer);
fz_free(ctx, state);
}
fz_stream *
fz_open_thunder(fz_context *ctx, fz_stream *chain, int w)
{
fz_thunder *state = fz_malloc_struct(ctx, fz_thunder);
fz_try(ctx)
{
state->run = 0;
state->pixel = 0;
state->lastpixel = 0;
state->len = w / 2;
state->buffer = fz_malloc(ctx, state->len);
state->chain = fz_keep_stream(ctx, chain);
}
fz_catch(ctx)
{
fz_free(ctx, state);
fz_rethrow(ctx);
}
return fz_new_stream(ctx, state, next_thunder, close_thunder);
}