1#include "mupdf/fitz.h"
2
3#include <string.h>
4#include <limits.h>
5
6/* TODO: check if this works with 16bpp images */
7
8typedef struct fz_predict_s fz_predict;
9
10struct fz_predict_s
11{
12 fz_stream *chain;
13
14 int predictor;
15 int columns;
16 int colors;
17 int bpc;
18
19 int stride;
20 int bpp;
21 unsigned char *in;
22 unsigned char *out;
23 unsigned char *ref;
24 unsigned char *rp, *wp;
25
26 unsigned char buffer[4096];
27};
28
29static inline int getcomponent(unsigned char *line, int x, int bpc)
30{
31 switch (bpc)
32 {
33 case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1;
34 case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3;
35 case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15;
36 case 8: return line[x];
37 case 16: return (line[x<<1]<<8)+line[(x<<1)+1];
38 }
39 return 0;
40}
41
42static inline void putcomponent(unsigned char *buf, int x, int bpc, int value)
43{
44 switch (bpc)
45 {
46 case 1: buf[x >> 3] |= value << (7 - (x & 7)); break;
47 case 2: buf[x >> 2] |= value << ((3 - (x & 3)) << 1); break;
48 case 4: buf[x >> 1] |= value << ((1 - (x & 1)) << 2); break;
49 case 8: buf[x] = value; break;
50 case 16: buf[x<<1] = value>>8; buf[(x<<1)+1] = value; break;
51 }
52}
53
54static inline int paeth(int a, int b, int c)
55{
56 /* The definitions of ac and bc are correct, not a typo. */
57 int ac = b - c, bc = a - c, abcc = ac + bc;
58 int pa = fz_absi(ac);
59 int pb = fz_absi(bc);
60 int pc = fz_absi(abcc);
61 return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
62}
63
64static void
65fz_predict_tiff(fz_predict *state, unsigned char *out, unsigned char *in)
66{
67 int left[FZ_MAX_COLORS];
68 int i, k;
69 const int mask = (1 << state->bpc)-1;
70
71 for (k = 0; k < state->colors; k++)
72 left[k] = 0;
73
74 /* special fast case */
75 if (state->bpc == 8)
76 {
77 for (i = 0; i < state->columns; i++)
78 for (k = 0; k < state->colors; k++)
79 *out++ = left[k] = (*in++ + left[k]) & 0xFF;
80 return;
81 }
82
83 /* putcomponent assumes zeroed memory for bpc < 8 */
84 if (state->bpc < 8)
85 memset(out, 0, state->stride);
86
87 for (i = 0; i < state->columns; i++)
88 {
89 for (k = 0; k < state->colors; k++)
90 {
91 int a = getcomponent(in, i * state->colors + k, state->bpc);
92 int b = a + left[k];
93 int c = b & mask;
94 putcomponent(out, i * state->colors + k, state->bpc, c);
95 left[k] = c;
96 }
97 }
98}
99
100static void
101fz_predict_png(fz_context *ctx, fz_predict *state, unsigned char *out, unsigned char *in, size_t len, int predictor)
102{
103 int bpp = state->bpp;
104 size_t i;
105 unsigned char *ref = state->ref;
106
107 if ((size_t)bpp > len)
108 bpp = (int)len;
109
110 switch (predictor)
111 {
112 default:
113 fz_warn(ctx, "unknown png predictor %d, treating as none", predictor);
114 /* fallthrough */
115 case 0:
116 memcpy(out, in, len);
117 break;
118 case 1:
119 for (i = bpp; i > 0; i--)
120 {
121 *out++ = *in++;
122 }
123 for (i = len - bpp; i > 0; i--)
124 {
125 *out = *in++ + out[-bpp];
126 out++;
127 }
128 break;
129 case 2:
130 for (i = bpp; i > 0; i--)
131 {
132 *out++ = *in++ + *ref++;
133 }
134 for (i = len - bpp; i > 0; i--)
135 {
136 *out++ = *in++ + *ref++;
137 }
138 break;
139 case 3:
140 for (i = bpp; i > 0; i--)
141 {
142 *out++ = *in++ + (*ref++) / 2;
143 }
144 for (i = len - bpp; i > 0; i--)
145 {
146 *out = *in++ + (out[-bpp] + *ref++) / 2;
147 out++;
148 }
149 break;
150 case 4:
151 for (i = bpp; i > 0; i--)
152 {
153 *out++ = *in++ + paeth(0, *ref++, 0);
154 }
155 for (i = len - bpp; i > 0; i --)
156 {
157 *out = *in++ + paeth(out[-bpp], *ref, ref[-bpp]);
158 ref++;
159 out++;
160 }
161 break;
162 }
163}
164
165static int
166next_predict(fz_context *ctx, fz_stream *stm, size_t len)
167{
168 fz_predict *state = stm->state;
169 unsigned char *buf = state->buffer;
170 unsigned char *p = buf;
171 unsigned char *ep;
172 int ispng = state->predictor >= 10;
173 size_t n;
174
175 if (len >= sizeof(state->buffer))
176 len = sizeof(state->buffer);
177 ep = buf + len;
178
179 while (state->rp < state->wp && p < ep)
180 *p++ = *state->rp++;
181
182 while (p < ep)
183 {
184 n = fz_read(ctx, state->chain, state->in, state->stride + ispng);
185 if (n == 0)
186 break;
187
188 if (state->predictor == 1)
189 memcpy(state->out, state->in, n);
190 else if (state->predictor == 2)
191 fz_predict_tiff(state, state->out, state->in);
192 else
193 {
194 fz_predict_png(ctx, state, state->out, state->in + 1, n - 1, state->in[0]);
195 memcpy(state->ref, state->out, state->stride);
196 }
197
198 state->rp = state->out;
199 state->wp = state->out + n - ispng;
200
201 while (state->rp < state->wp && p < ep)
202 *p++ = *state->rp++;
203 }
204
205 stm->rp = buf;
206 stm->wp = p;
207 if (stm->rp == stm->wp)
208 return EOF;
209 stm->pos += p - buf;
210
211 return *stm->rp++;
212}
213
214static void
215close_predict(fz_context *ctx, void *state_)
216{
217 fz_predict *state = (fz_predict *)state_;
218 fz_drop_stream(ctx, state->chain);
219 fz_free(ctx, state->in);
220 fz_free(ctx, state->out);
221 fz_free(ctx, state->ref);
222 fz_free(ctx, state);
223}
224
225/* Default values: predictor = 1, columns = 1, colors = 1, bpc = 8 */
226fz_stream *
227fz_open_predict(fz_context *ctx, fz_stream *chain, int predictor, int columns, int colors, int bpc)
228{
229 fz_predict *state;
230
231 if (predictor < 1)
232 predictor = 1;
233 if (columns < 1)
234 columns = 1;
235 if (colors < 1)
236 colors = 1;
237 if (bpc < 1)
238 bpc = 8;
239
240 if (bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8 && bpc != 16)
241 fz_throw(ctx, FZ_ERROR_GENERIC, "invalid number of bits per component: %d", bpc);
242 if (colors > FZ_MAX_COLORS)
243 fz_throw(ctx, FZ_ERROR_GENERIC, "too many color components (%d > %d)", colors, FZ_MAX_COLORS);
244 if (columns >= INT_MAX / (bpc * colors))
245 fz_throw(ctx, FZ_ERROR_GENERIC, "too many columns lead to an integer overflow (%d)", columns);
246
247 if (predictor != 1 && predictor != 2 &&
248 predictor != 10 && predictor != 11 &&
249 predictor != 12 && predictor != 13 &&
250 predictor != 14 && predictor != 15)
251 {
252 fz_warn(ctx, "invalid predictor: %d", predictor);
253 predictor = 1;
254 }
255
256 state = fz_malloc_struct(ctx, fz_predict);
257 fz_try(ctx)
258 {
259 state->predictor = predictor;
260 state->columns = columns;
261 state->colors = colors;
262 state->bpc = bpc;
263
264 state->stride = (state->bpc * state->colors * state->columns + 7) / 8;
265 state->bpp = (state->bpc * state->colors + 7) / 8;
266
267 state->in = fz_malloc(ctx, state->stride + 1);
268 state->out = fz_malloc(ctx, state->stride);
269 state->ref = fz_malloc(ctx, state->stride);
270 state->rp = state->out;
271 state->wp = state->out;
272
273 memset(state->ref, 0, state->stride);
274
275 state->chain = fz_keep_stream(ctx, chain);
276 }
277 fz_catch(ctx)
278 {
279 fz_free(ctx, state->in);
280 fz_free(ctx, state->out);
281 fz_free(ctx, state);
282 fz_rethrow(ctx);
283 }
284
285 return fz_new_stream(ctx, state, next_predict, close_predict);
286}
287