1#include "mupdf/fitz.h"
2
3/* 4bit greyscale Thunderscan decoding */
4
5typedef struct fz_thunder_s fz_thunder;
6
7struct fz_thunder_s
8{
9 fz_stream *chain;
10 int lastpixel;
11 int run;
12 int pixel;
13
14 int len;
15 unsigned char *buffer;
16};
17
18static int
19next_thunder(fz_context *ctx, fz_stream *stm, size_t max)
20{
21 fz_thunder *state = stm->state;
22 unsigned char *p = state->buffer;
23 unsigned char *ep;
24 int c, v, i, pixels, index;
25
26 if (max > (size_t)state->len)
27 max = (size_t)state->len;
28
29 ep = p + max;
30
31 c = 0;
32 while (p < ep && c >= 0)
33 {
34 pixels = 0;
35 v = 0;
36
37 while (pixels < 2)
38 {
39 if (state->run > 0)
40 {
41 v <<= 4;
42 v |= state->pixel & 0xf;
43 state->pixel >>= 4;
44 state->run--;
45 pixels++;
46
47 if (state->run > 2)
48 state->pixel |= ((state->pixel >> 4) & 0xf) << 8;
49 }
50 else
51 {
52 c = fz_read_byte(ctx, state->chain);
53 if (c < 0)
54 break;
55
56 switch ((c >> 6) & 0x3)
57 {
58 case 0x0: /* run of pixels identical to last pixel */
59 state->run = c;
60 state->pixel = (state->lastpixel << 8) | (state->lastpixel << 4) | (state->lastpixel << 0);
61 break;
62
63 case 0x1: /* three pixels with 2bit deltas to last pixel */
64 for (i = 0; i < 3; i++)
65 {
66 static const int deltas[] = { 0, 1, 0, -1 };
67 index = (c >> (4 - i * 2)) & 0x3;
68 if (index == 2)
69 continue;
70
71 state->lastpixel = (state->lastpixel + deltas[index]) & 0xf;
72 state->pixel <<= 4;
73 state->pixel |= state->lastpixel;
74 state->run++;
75 }
76 break;
77
78 case 0x2: /* two pixels with 3bit deltas to last pixel */
79 for (i = 0; i < 2; i++)
80 {
81 static const int deltas[] = { 0, 1, 2, 3, 0, -3, -2, -1 };
82 index = (c >> (3 - i * 3)) & 0x7;
83 if (index == 4)
84 continue;
85
86 state->lastpixel = (state->lastpixel + deltas[index]) & 0xf;
87 state->pixel <<= 4;
88 state->pixel |= state->lastpixel;
89 state->run++;
90 }
91 break;
92
93 case 0x3: /* a single raw 4bit pixel */
94 state->run = 1;
95 state->pixel = c & 0xf;
96 state->lastpixel = state->pixel & 0xf;
97 break;
98 }
99 }
100 }
101
102 if (pixels)
103 *p++ = v;
104 }
105
106 stm->rp = state->buffer;
107 stm->wp = p;
108 stm->pos += p - state->buffer;
109
110 if (stm->rp != p)
111 return *stm->rp++;
112 return EOF;
113}
114
115static void
116close_thunder(fz_context *ctx, void *state_)
117{
118 fz_thunder *state = (fz_thunder *)state_;
119 fz_drop_stream(ctx, state->chain);
120 fz_free(ctx, state->buffer);
121 fz_free(ctx, state);
122}
123
124fz_stream *
125fz_open_thunder(fz_context *ctx, fz_stream *chain, int w)
126{
127 fz_thunder *state = fz_malloc_struct(ctx, fz_thunder);
128 fz_try(ctx)
129 {
130 state->run = 0;
131 state->pixel = 0;
132 state->lastpixel = 0;
133 state->len = w / 2;
134 state->buffer = fz_malloc(ctx, state->len);
135 state->chain = fz_keep_stream(ctx, chain);
136 }
137 fz_catch(ctx)
138 {
139 fz_free(ctx, state);
140 fz_rethrow(ctx);
141 }
142 return fz_new_stream(ctx, state, next_thunder, close_thunder);
143}
144