Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4680 | right-hear | 1 | #include "fitz.h" |
2 | |||
3 | /* TODO: check if this works with 16bpp images */ |
||
4 | |||
5 | enum { MAXC = 32 }; |
||
6 | |||
7 | typedef struct fz_predict_s fz_predict; |
||
8 | |||
9 | struct fz_predict_s |
||
10 | { |
||
11 | fz_stream *chain; |
||
12 | |||
13 | int predictor; |
||
14 | int columns; |
||
15 | int colors; |
||
16 | int bpc; |
||
17 | |||
18 | int stride; |
||
19 | int bpp; |
||
20 | unsigned char *in; |
||
21 | unsigned char *out; |
||
22 | unsigned char *ref; |
||
23 | unsigned char *rp, *wp; |
||
24 | }; |
||
25 | |||
26 | static inline int getcomponent(unsigned char *line, int x, int bpc) |
||
27 | { |
||
28 | switch (bpc) |
||
29 | { |
||
30 | case 1: return (line[x >> 3] >> ( 7 - (x & 7) ) ) & 1; |
||
31 | case 2: return (line[x >> 2] >> ( ( 3 - (x & 3) ) << 1 ) ) & 3; |
||
32 | case 4: return (line[x >> 1] >> ( ( 1 - (x & 1) ) << 2 ) ) & 15; |
||
33 | case 8: return line[x]; |
||
34 | } |
||
35 | return 0; |
||
36 | } |
||
37 | |||
38 | |||
39 | static inline void putcomponent(unsigned char *buf, int x, int bpc, int value) |
||
40 | { |
||
41 | switch (bpc) |
||
42 | { |
||
43 | case 1: buf[x >> 3] |= value << (7 - (x & 7)); break; |
||
44 | case 2: buf[x >> 2] |= value << ((3 - (x & 3)) << 1); break; |
||
45 | case 4: buf[x >> 1] |= value << ((1 - (x & 1)) << 2); break; |
||
46 | case 8: buf[x] = value; break; |
||
47 | } |
||
48 | } |
||
49 | |||
50 | static inline int paeth(int a, int b, int c) |
||
51 | { |
||
52 | /* The definitions of ac and bc are correct, not a typo. */ |
||
53 | int ac = b - c, bc = a - c, abcc = ac + bc; |
||
54 | int pa = ABS(ac); |
||
55 | int pb = ABS(bc); |
||
56 | int pc = ABS(abcc); |
||
57 | return pa <= pb && pa <= pc ? a : pb <= pc ? b : c; |
||
58 | } |
||
59 | |||
60 | static void |
||
61 | fz_predict_tiff(fz_predict *state, unsigned char *out, unsigned char *in, int len) |
||
62 | { |
||
63 | int left[MAXC]; |
||
64 | int i, k; |
||
65 | |||
66 | for (k = 0; k < state->colors; k++) |
||
67 | left[k] = 0; |
||
68 | |||
69 | for (i = 0; i < state->columns; i++) |
||
70 | { |
||
71 | for (k = 0; k < state->colors; k++) |
||
72 | { |
||
73 | int a = getcomponent(in, i * state->colors + k, state->bpc); |
||
74 | int b = a + left[k]; |
||
75 | int c = b % (1 << state->bpc); |
||
76 | putcomponent(out, i * state->colors + k, state->bpc, c); |
||
77 | left[k] = c; |
||
78 | } |
||
79 | } |
||
80 | } |
||
81 | |||
82 | static void |
||
83 | fz_predict_png(fz_predict *state, unsigned char *out, unsigned char *in, int len, int predictor) |
||
84 | { |
||
85 | int bpp = state->bpp; |
||
86 | int i; |
||
87 | unsigned char *ref = state->ref; |
||
88 | |||
89 | switch (predictor) |
||
90 | { |
||
91 | case 0: |
||
92 | memcpy(out, in, len); |
||
93 | break; |
||
94 | case 1: |
||
95 | for (i = bpp; i > 0; i--) |
||
96 | { |
||
97 | *out++ = *in++; |
||
98 | } |
||
99 | for (i = len - bpp; i > 0; i--) |
||
100 | { |
||
101 | *out = *in++ + out[-bpp]; |
||
102 | out++; |
||
103 | } |
||
104 | break; |
||
105 | case 2: |
||
106 | for (i = bpp; i > 0; i--) |
||
107 | { |
||
108 | *out++ = *in++ + *ref++; |
||
109 | } |
||
110 | for (i = len - bpp; i > 0; i--) |
||
111 | { |
||
112 | *out++ = *in++ + *ref++; |
||
113 | } |
||
114 | break; |
||
115 | case 3: |
||
116 | for (i = bpp; i > 0; i--) |
||
117 | { |
||
118 | *out++ = *in++ + (*ref++) / 2; |
||
119 | } |
||
120 | for (i = len - bpp; i > 0; i--) |
||
121 | { |
||
122 | *out = *in++ + (out[-bpp] + *ref++) / 2; |
||
123 | out++; |
||
124 | } |
||
125 | break; |
||
126 | case 4: |
||
127 | for (i = bpp; i > 0; i--) |
||
128 | { |
||
129 | *out++ = *in++ + paeth(0, *ref++, 0); |
||
130 | } |
||
131 | for (i = len - bpp; i > 0; i --) |
||
132 | { |
||
133 | *out = *in++ + paeth(out[-bpp], *ref, ref[-bpp]); |
||
134 | ref++; |
||
135 | out++; |
||
136 | } |
||
137 | break; |
||
138 | } |
||
139 | } |
||
140 | |||
141 | static int |
||
142 | read_predict(fz_stream *stm, unsigned char *buf, int len) |
||
143 | { |
||
144 | fz_predict *state = stm->state; |
||
145 | unsigned char *p = buf; |
||
146 | unsigned char *ep = buf + len; |
||
147 | int ispng = state->predictor >= 10; |
||
148 | int n; |
||
149 | |||
150 | while (state->rp < state->wp && p < ep) |
||
151 | *p++ = *state->rp++; |
||
152 | |||
153 | while (p < ep) |
||
154 | { |
||
155 | n = fz_read(state->chain, state->in, state->stride + ispng); |
||
156 | if (n < 0) |
||
157 | return fz_rethrow(n, "read error in prediction filter"); |
||
158 | if (n == 0) |
||
159 | return p - buf; |
||
160 | |||
161 | if (state->predictor == 1) |
||
162 | memcpy(state->out, state->in, n); |
||
163 | else if (state->predictor == 2) |
||
164 | fz_predict_tiff(state, state->out, state->in, n); |
||
165 | else |
||
166 | { |
||
167 | fz_predict_png(state, state->out, state->in + 1, n - 1, state->in[0]); |
||
168 | memcpy(state->ref, state->out, state->stride); |
||
169 | } |
||
170 | |||
171 | state->rp = state->out; |
||
172 | state->wp = state->out + n - ispng; |
||
173 | |||
174 | while (state->rp < state->wp && p < ep) |
||
175 | *p++ = *state->rp++; |
||
176 | } |
||
177 | |||
178 | return p - buf; |
||
179 | } |
||
180 | |||
181 | static void |
||
182 | close_predict(fz_stream *stm) |
||
183 | { |
||
184 | fz_predict *state = stm->state; |
||
185 | fz_close(state->chain); |
||
186 | fz_free(state->in); |
||
187 | fz_free(state->out); |
||
188 | fz_free(state->ref); |
||
189 | fz_free(state); |
||
190 | } |
||
191 | |||
192 | fz_stream * |
||
193 | fz_open_predict(fz_stream *chain, fz_obj *params) |
||
194 | { |
||
195 | fz_predict *state; |
||
196 | fz_obj *obj; |
||
197 | |||
198 | state = fz_malloc(sizeof(fz_predict)); |
||
199 | state->chain = chain; |
||
200 | |||
201 | state->predictor = 1; |
||
202 | state->columns = 1; |
||
203 | state->colors = 1; |
||
204 | state->bpc = 8; |
||
205 | |||
206 | obj = fz_dict_gets(params, "Predictor"); |
||
207 | if (obj) |
||
208 | state->predictor = fz_to_int(obj); |
||
209 | |||
210 | if (state->predictor != 1 && state->predictor != 2 && |
||
211 | state->predictor != 10 && state->predictor != 11 && |
||
212 | state->predictor != 12 && state->predictor != 13 && |
||
213 | state->predictor != 14 && state->predictor != 15) |
||
214 | { |
||
215 | fz_warn("invalid predictor: %d", state->predictor); |
||
216 | state->predictor = 1; |
||
217 | } |
||
218 | |||
219 | obj = fz_dict_gets(params, "Columns"); |
||
220 | if (obj) |
||
221 | state->columns = fz_to_int(obj); |
||
222 | |||
223 | obj = fz_dict_gets(params, "Colors"); |
||
224 | if (obj) |
||
225 | state->colors = fz_to_int(obj); |
||
226 | |||
227 | obj = fz_dict_gets(params, "BitsPerComponent"); |
||
228 | if (obj) |
||
229 | state->bpc = fz_to_int(obj); |
||
230 | |||
231 | state->stride = (state->bpc * state->colors * state->columns + 7) / 8; |
||
232 | state->bpp = (state->bpc * state->colors + 7) / 8; |
||
233 | |||
234 | state->in = fz_malloc(state->stride + 1); |
||
235 | state->out = fz_malloc(state->stride); |
||
236 | state->ref = fz_malloc(state->stride); |
||
237 | state->rp = state->out; |
||
238 | state->wp = state->out; |
||
239 | |||
240 | memset(state->ref, 0, state->stride); |
||
241 | |||
242 | return fz_new_stream(state, read_predict, close_predict); |
||
243 | }>>>>>>><>>>>=>=>=>><>><>><>><>><>><>><> |