1 #include "mupdf/fitz.h"
2
3 #include <assert.h>
4
5 struct fz_halftone
6 {
7 int refs;
8 int n;
9 fz_pixmap *comp[1];
10 };
11
12 static fz_halftone *
fz_new_halftone(fz_context * ctx,int comps)13 fz_new_halftone(fz_context *ctx, int comps)
14 {
15 fz_halftone *ht;
16 int i;
17
18 ht = Memento_label(fz_malloc(ctx, sizeof(fz_halftone) + (comps-1)*sizeof(fz_pixmap *)), "fz_halftone");
19 ht->refs = 1;
20 ht->n = comps;
21 for (i = 0; i < comps; i++)
22 ht->comp[i] = NULL;
23
24 return ht;
25 }
26
27 fz_halftone *
fz_keep_halftone(fz_context * ctx,fz_halftone * ht)28 fz_keep_halftone(fz_context *ctx, fz_halftone *ht)
29 {
30 return fz_keep_imp(ctx, ht, &ht->refs);
31 }
32
33 void
fz_drop_halftone(fz_context * ctx,fz_halftone * ht)34 fz_drop_halftone(fz_context *ctx, fz_halftone *ht)
35 {
36 int i;
37 if (fz_drop_imp(ctx, ht, &ht->refs))
38 {
39 for (i = 0; i < ht->n; i++)
40 fz_drop_pixmap(ctx, ht->comp[i]);
41 fz_free(ctx, ht);
42 }
43 }
44
45 /* Default mono halftone, lifted from Ghostscript. */
46 /* The 0x00 entry has been changed to 0x01 to avoid problems with white
47 * pixels appearing in the output; as we use < 0 should not appear in the
48 * array. I think that gs scales this slightly and hence never actually uses
49 * the raw values here. */
50 static unsigned char mono_ht[] =
51 {
52 0x0E, 0x8E, 0x2E, 0xAE, 0x06, 0x86, 0x26, 0xA6, 0x0C, 0x8C, 0x2C, 0xAC, 0x04, 0x84, 0x24, 0xA4,
53 0xCE, 0x4E, 0xEE, 0x6E, 0xC6, 0x46, 0xE6, 0x66, 0xCC, 0x4C, 0xEC, 0x6C, 0xC4, 0x44, 0xE4, 0x64,
54 0x3E, 0xBE, 0x1E, 0x9E, 0x36, 0xB6, 0x16, 0x96, 0x3C, 0xBC, 0x1C, 0x9C, 0x34, 0xB4, 0x14, 0x94,
55 0xFE, 0x7E, 0xDE, 0x5E, 0xF6, 0x76, 0xD6, 0x56, 0xFC, 0x7C, 0xDC, 0x5C, 0xF4, 0x74, 0xD4, 0x54,
56 0x01, 0x81, 0x21, 0xA1, 0x09, 0x89, 0x29, 0xA9, 0x03, 0x83, 0x23, 0xA3, 0x0B, 0x8B, 0x2B, 0xAB,
57 0xC1, 0x41, 0xE1, 0x61, 0xC9, 0x49, 0xE9, 0x69, 0xC3, 0x43, 0xE3, 0x63, 0xCB, 0x4B, 0xEB, 0x6B,
58 0x31, 0xB1, 0x11, 0x91, 0x39, 0xB9, 0x19, 0x99, 0x33, 0xB3, 0x13, 0x93, 0x3B, 0xBB, 0x1B, 0x9B,
59 0xF1, 0x71, 0xD1, 0x51, 0xF9, 0x79, 0xD9, 0x59, 0xF3, 0x73, 0xD3, 0x53, 0xFB, 0x7B, 0xDB, 0x5B,
60 0x0D, 0x8D, 0x2D, 0xAD, 0x05, 0x85, 0x25, 0xA5, 0x0F, 0x8F, 0x2F, 0xAF, 0x07, 0x87, 0x27, 0xA7,
61 0xCD, 0x4D, 0xED, 0x6D, 0xC5, 0x45, 0xE5, 0x65, 0xCF, 0x4F, 0xEF, 0x6F, 0xC7, 0x47, 0xE7, 0x67,
62 0x3D, 0xBD, 0x1D, 0x9D, 0x35, 0xB5, 0x15, 0x95, 0x3F, 0xBF, 0x1F, 0x9F, 0x37, 0xB7, 0x17, 0x97,
63 0xFD, 0x7D, 0xDD, 0x5D, 0xF5, 0x75, 0xD5, 0x55, 0xFF, 0x7F, 0xDF, 0x5F, 0xF7, 0x77, 0xD7, 0x57,
64 0x02, 0x82, 0x22, 0xA2, 0x0A, 0x8A, 0x2A, 0xAA, 0x01 /*0x00*/, 0x80, 0x20, 0xA0, 0x08, 0x88, 0x28, 0xA8,
65 0xC2, 0x42, 0xE2, 0x62, 0xCA, 0x4A, 0xEA, 0x6A, 0xC0, 0x40, 0xE0, 0x60, 0xC8, 0x48, 0xE8, 0x68,
66 0x32, 0xB2, 0x12, 0x92, 0x3A, 0xBA, 0x1A, 0x9A, 0x30, 0xB0, 0x10, 0x90, 0x38, 0xB8, 0x18, 0x98,
67 0xF2, 0x72, 0xD2, 0x52, 0xFA, 0x7A, 0xDA, 0x5A, 0xF0, 0x70, 0xD0, 0x50, 0xF8, 0x78, 0xD8, 0x58
68 };
69
fz_default_halftone(fz_context * ctx,int num_comps)70 fz_halftone *fz_default_halftone(fz_context *ctx, int num_comps)
71 {
72 fz_halftone *ht = fz_new_halftone(ctx, num_comps);
73
74 fz_try(ctx)
75 {
76 int i;
77 for (i = 0; i < num_comps; i++)
78 ht->comp[i] = fz_new_pixmap_with_data(ctx, NULL, 16, 16, NULL, 1, 16, mono_ht);
79 }
80 fz_catch(ctx)
81 {
82 fz_drop_halftone(ctx, ht);
83 fz_rethrow(ctx);
84 }
85
86 return ht;
87 }
88
89 /* Finally, code to actually perform halftoning. */
make_ht_line(unsigned char * buf,fz_halftone * ht,int x,int y,int w)90 static void make_ht_line(unsigned char *buf, fz_halftone *ht, int x, int y, int w)
91 {
92 int k, n;
93 n = ht->n;
94 for (k = 0; k < n; k++)
95 {
96 fz_pixmap *tile = ht->comp[k];
97 unsigned char *b = buf++;
98 unsigned char *t;
99 unsigned char *tbase;
100 int px = x + tile->x;
101 int py = y + tile->y;
102 int tw = tile->w;
103 int th = tile->h;
104 int w2 = w;
105 int len;
106 px = px % tw;
107 if (px < 0)
108 px += tw;
109 py = py % th;
110 if (py < 0)
111 py += th;
112
113 assert(tile->n == 1);
114
115 /* Left hand section; from x to tile width */
116 tbase = tile->samples + (unsigned int)(py * tw);
117 t = tbase + px;
118 len = tw - px;
119 if (len > w2)
120 len = w2;
121 w2 -= len;
122 while (len--)
123 {
124 *b = *t++;
125 b += n;
126 }
127
128 /* Centre section - complete copies */
129 w2 -= tw;
130 while (w2 >= 0)
131 {
132 len = tw;
133 t = tbase;
134 while (len--)
135 {
136 *b = *t++;
137 b += n;
138 }
139 w2 -= tw;
140 }
141 w2 += tw;
142
143 /* Right hand section - stragglers */
144 t = tbase;
145 while (w2--)
146 {
147 *b = *t++;
148 b += n;
149 }
150 }
151 }
152
153 /* Inner mono thresholding code */
154 typedef void (threshold_fn)(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len);
155
156 #ifdef ARCH_ARM
157 static void
158 do_threshold_1(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len)
159 __attribute__((naked));
160
161 static void
do_threshold_1(const unsigned char * FZ_RESTRICT ht_line,const unsigned char * FZ_RESTRICT pixmap,unsigned char * FZ_RESTRICT out,int w,int ht_len)162 do_threshold_1(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len)
163 {
164 asm volatile(
165 ENTER_ARM
166 // Store one more reg that required to keep double stack alignment
167 ".syntax unified\n"
168 "stmfd r13!,{r4-r7,r9,r14} \n"
169 "@ r0 = ht_line \n"
170 "@ r1 = pixmap \n"
171 "@ r2 = out \n"
172 "@ r3 = w \n"
173 "@ <> = ht_len \n"
174 "ldr r9, [r13,#6*4] @ r9 = ht_len \n"
175 "subs r3, r3, #7 @ r3 = w -= 7 \n"
176 "ble 2f @ while (w > 0) { \n"
177 "mov r12,r9 @ r12= l = ht_len \n"
178 "b 1f \n"
179 "9: \n"
180 "strb r14,[r2], #1 @ *out++ = 0 \n"
181 "subs r12,r12,#8 @ r12 = l -= 8 \n"
182 "moveq r12,r9 @ if(l==0) l = ht_len \n"
183 "subeq r0, r0, r9 @ ht_line -= l \n"
184 "subs r3, r3, #8 @ w -= 8 \n"
185 "ble 2f @ } \n"
186 "1: \n"
187 "ldr r14,[r1], #4 @ r14= pixmap[0..3] \n"
188 "ldr r5, [r1], #4 @ r5 = pixmap[4..7] \n"
189 "ldrb r4, [r0], #8 @ r0 = ht_line += 8 \n"
190 "adds r14,r14,#1 @ set eq iff r14=-1 \n"
191 "addseq r5, r5, #1 @ set eq iff r14=r5=-1 \n"
192 "beq 9b @ white \n"
193 "ldrb r5, [r1, #-8] @ r5 = pixmap[0] \n"
194 "ldrb r6, [r0, #-7] @ r6 = ht_line[1] \n"
195 "ldrb r7, [r1, #-7] @ r7 = pixmap[1] \n"
196 "mov r14,#0 @ r14= h = 0 \n"
197 "cmp r5, r4 @ if (r5 < r4) \n"
198 "orrlt r14,r14,#0x80 @ h |= 0x80 \n"
199 "ldrb r4, [r0, #-6] @ r4 = ht_line[2] \n"
200 "ldrb r5, [r1, #-6] @ r5 = pixmap[2] \n"
201 "cmp r7, r6 @ if (r7 < r6) \n"
202 "orrlt r14,r14,#0x40 @ h |= 0x40 \n"
203 "ldrb r6, [r0, #-5] @ r6 = ht_line[3] \n"
204 "ldrb r7, [r1, #-5] @ r7 = pixmap[3] \n"
205 "cmp r5, r4 @ if (r5 < r4) \n"
206 "orrlt r14,r14,#0x20 @ h |= 0x20 \n"
207 "ldrb r4, [r0, #-4] @ r4 = ht_line[4] \n"
208 "ldrb r5, [r1, #-4] @ r5 = pixmap[4] \n"
209 "cmp r7, r6 @ if (r7 < r6) \n"
210 "orrlt r14,r14,#0x10 @ h |= 0x10 \n"
211 "ldrb r6, [r0, #-3] @ r6 = ht_line[5] \n"
212 "ldrb r7, [r1, #-3] @ r7 = pixmap[5] \n"
213 "cmp r5, r4 @ if (r5 < r4) \n"
214 "orrlt r14,r14,#0x08 @ h |= 0x08 \n"
215 "ldrb r4, [r0, #-2] @ r4 = ht_line[6] \n"
216 "ldrb r5, [r1, #-2] @ r5 = pixmap[6] \n"
217 "cmp r7, r6 @ if (r7 < r6) \n"
218 "orrlt r14,r14,#0x04 @ h |= 0x04 \n"
219 "ldrb r6, [r0, #-1] @ r6 = ht_line[7] \n"
220 "ldrb r7, [r1, #-1] @ r7 = pixmap[7] \n"
221 "cmp r5, r4 @ if (r5 < r4) \n"
222 "orrlt r14,r14,#0x02 @ h |= 0x02 \n"
223 "cmp r7, r6 @ if (r7 < r6) \n"
224 "orrlt r14,r14,#0x01 @ h |= 0x01 \n"
225 "subs r12,r12,#8 @ r12 = l -= 8 \n"
226 "strb r14,[r2], #1 @ *out++ = h \n"
227 "moveq r12,r9 @ if(l==0) l = ht_len \n"
228 "subeq r0, r0, r9 @ ht_line -= l \n"
229 "subs r3, r3, #8 @ w -= 8 \n"
230 "bgt 1b @ } \n"
231 "2: \n"
232 "adds r3, r3, #7 @ w += 7 \n"
233 "ble 4f @ if (w >= 0) { \n"
234 "ldrb r4, [r0], #1 @ r4 = ht_line[0] \n"
235 "ldrb r5, [r1], #1 @ r5 = pixmap[0] \n"
236 "mov r14, #0 @ r14= h = 0 \n"
237 "cmp r5, r4 @ if (r5 < r4) \n"
238 "orrlt r14,r14,#0x80 @ h |= 0x80 \n"
239 "cmp r3, #1 @ \n"
240 "ldrbgt r4, [r0], #1 @ r6 = ht_line[1] \n"
241 "ldrbgt r5, [r1], #1 @ r7 = pixmap[1] \n"
242 "ble 3f @ \n"
243 "cmp r5, r4 @ if (r5 < r4) \n"
244 "orrlt r14,r14,#0x40 @ h |= 0x40 \n"
245 "cmp r3, #2 @ \n"
246 "ldrbgt r4, [r0], #1 @ r6 = ht_line[2] \n"
247 "ldrbgt r5, [r1], #1 @ r7 = pixmap[2] \n"
248 "ble 3f @ \n"
249 "cmp r5, r4 @ if (r5 < r4) \n"
250 "orrlt r14,r14,#0x20 @ h |= 0x20 \n"
251 "cmp r3, #3 @ \n"
252 "ldrbgt r4, [r0], #1 @ r6 = ht_line[3] \n"
253 "ldrbgt r5, [r1], #1 @ r7 = pixmap[3] \n"
254 "ble 3f @ \n"
255 "cmp r5, r4 @ if (r5 < r4) \n"
256 "orrlt r14,r14,#0x10 @ h |= 0x10 \n"
257 "cmp r3, #4 @ \n"
258 "ldrbgt r4, [r0], #1 @ r6 = ht_line[4] \n"
259 "ldrbgt r5, [r1], #1 @ r7 = pixmap[4] \n"
260 "ble 3f @ \n"
261 "cmp r5, r4 @ if (r5 < r4) \n"
262 "orrlt r14,r14,#0x08 @ h |= 0x08 \n"
263 "cmp r3, #5 @ \n"
264 "ldrbgt r4, [r0], #1 @ r6 = ht_line[5] \n"
265 "ldrbgt r5, [r1], #1 @ r7 = pixmap[5] \n"
266 "ble 3f @ \n"
267 "cmp r5, r4 @ if (r5 < r4) \n"
268 "orrlt r14,r14,#0x04 @ h |= 0x04 \n"
269 "cmp r3, #6 @ \n"
270 "ldrbgt r4, [r0], #1 @ r6 = ht_line[6] \n"
271 "ldrbgt r5, [r1], #1 @ r7 = pixmap[6] \n"
272 "ble 3f @ \n"
273 "cmp r5, r4 @ if (r5 < r4) \n"
274 "orrlt r14,r14,#0x02 @ h |= 0x02 \n"
275 "3: \n"
276 "strb r14,[r2] @ *out = h \n"
277 "4: \n"
278 "ldmfd r13!,{r4-r7,r9,PC} @ pop, return to thumb \n"
279 ENTER_THUMB
280 );
281 }
282 #else
do_threshold_1(const unsigned char * FZ_RESTRICT ht_line,const unsigned char * FZ_RESTRICT pixmap,unsigned char * FZ_RESTRICT out,int w,int ht_len)283 static void do_threshold_1(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len)
284 {
285 int h;
286 int l = ht_len;
287
288 w -= 7;
289 while (w > 0)
290 {
291 h = 0;
292 if (pixmap[0] < ht_line[0])
293 h |= 0x80;
294 if (pixmap[1] < ht_line[1])
295 h |= 0x40;
296 if (pixmap[2] < ht_line[2])
297 h |= 0x20;
298 if (pixmap[3] < ht_line[3])
299 h |= 0x10;
300 if (pixmap[4] < ht_line[4])
301 h |= 0x08;
302 if (pixmap[5] < ht_line[5])
303 h |= 0x04;
304 if (pixmap[6] < ht_line[6])
305 h |= 0x02;
306 if (pixmap[7] < ht_line[7])
307 h |= 0x01;
308 pixmap += 8;
309 ht_line += 8;
310 l -= 8;
311 if (l == 0)
312 {
313 l = ht_len;
314 ht_line -= ht_len;
315 }
316 *out++ = h;
317 w -= 8;
318 }
319 if (w > -7)
320 {
321 h = 0;
322 if (pixmap[0] < ht_line[0])
323 h |= 0x80;
324 if (w > -6 && pixmap[1] < ht_line[1])
325 h |= 0x40;
326 if (w > -5 && pixmap[2] < ht_line[2])
327 h |= 0x20;
328 if (w > -4 && pixmap[3] < ht_line[3])
329 h |= 0x10;
330 if (w > -3 && pixmap[4] < ht_line[4])
331 h |= 0x08;
332 if (w > -2 && pixmap[5] < ht_line[5])
333 h |= 0x04;
334 if (w > -1 && pixmap[6] < ht_line[6])
335 h |= 0x02;
336 *out++ = h;
337 }
338 }
339 #endif
340
341 /*
342 Note that the tests in do_threshold_4 are inverted compared to those
343 in do_threshold_1. This is to allow for the fact that the CMYK
344 contone renderings have white = 0, whereas rgb, and greyscale have
345 white = 0xFF. Reversing these tests enables us to maintain that
346 BlackIs1 in bitmaps.
347 */
348 #ifdef ARCH_ARM
349 static void
350 do_threshold_4(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len)
351 __attribute__((naked));
352
353 static void
do_threshold_4(const unsigned char * FZ_RESTRICT ht_line,const unsigned char * FZ_RESTRICT pixmap,unsigned char * FZ_RESTRICT out,int w,int ht_len)354 do_threshold_4(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len)
355 {
356 asm volatile(
357 ENTER_ARM
358 // Store one more reg that required to keep double stack alignment
359 "stmfd r13!,{r4-r7,r9,r14} \n"
360 "@ r0 = ht_line \n"
361 "@ r1 = pixmap \n"
362 "@ r2 = out \n"
363 "@ r3 = w \n"
364 "@ <> = ht_len \n"
365 "ldr r9, [r13,#6*4] @ r9 = ht_len \n"
366 "subs r3, r3, #1 @ r3 = w -= 1 \n"
367 "ble 2f @ while (w > 0) { \n"
368 "mov r12,r9 @ r12= l = ht_len \n"
369 "b 1f @ \n"
370 "9: @ \n"
371 "strb r14,[r2], #1 @ *out++ = h \n"
372 "subs r12,r12,#2 @ r12 = l -= 2 \n"
373 "moveq r12,r9 @ if(l==0) l = ht_len \n"
374 "subeq r0, r0, r9, LSL #2 @ ht_line -= l \n"
375 "subs r3, r3, #2 @ w -= 2 \n"
376 "beq 2f @ } \n"
377 "blt 3f @ \n"
378 "1: \n"
379 "ldr r5, [r1], #4 @ r5 = pixmap[0..3] \n"
380 "ldr r7, [r1], #4 @ r7 = pixmap[4..7] \n"
381 "add r0, r0, #8 @ r0 = ht_line += 8 \n"
382 "mov r14,#0 @ r14= h = 0 \n"
383 "orrs r5, r5, r7 @ if (r5 | r7 == 0) \n"
384 "beq 9b @ white \n"
385 "ldrb r4, [r0, #-8] @ r4 = ht_line[0] \n"
386 "ldrb r5, [r1, #-8] @ r5 = pixmap[0] \n"
387 "ldrb r6, [r0, #-7] @ r6 = ht_line[1] \n"
388 "ldrb r7, [r1, #-7] @ r7 = pixmap[1] \n"
389 "cmp r4, r5 @ if (r4 < r5) \n"
390 "orrle r14,r14,#0x80 @ h |= 0x80 \n"
391 "ldrb r4, [r0, #-6] @ r4 = ht_line[2] \n"
392 "ldrb r5, [r1, #-6] @ r5 = pixmap[2] \n"
393 "cmp r6, r7 @ if (r6 < r7) \n"
394 "orrle r14,r14,#0x40 @ h |= 0x40 \n"
395 "ldrb r6, [r0, #-5] @ r6 = ht_line[3] \n"
396 "ldrb r7, [r1, #-5] @ r7 = pixmap[3] \n"
397 "cmp r4, r5 @ if (r4 < r5) \n"
398 "orrle r14,r14,#0x20 @ h |= 0x20 \n"
399 "ldrb r4, [r0, #-4] @ r4 = ht_line[4] \n"
400 "ldrb r5, [r1, #-4] @ r5 = pixmap[4] \n"
401 "cmp r6, r7 @ if (r6 < r7) \n"
402 "orrle r14,r14,#0x10 @ h |= 0x10 \n"
403 "ldrb r6, [r0, #-3] @ r6 = ht_line[5] \n"
404 "ldrb r7, [r1, #-3] @ r7 = pixmap[5] \n"
405 "cmp r4, r5 @ if (r4 < r5) \n"
406 "orrle r14,r14,#0x08 @ h |= 0x08 \n"
407 "ldrb r4, [r0, #-2] @ r4 = ht_line[6] \n"
408 "ldrb r5, [r1, #-2] @ r5 = pixmap[6] \n"
409 "cmp r6, r7 @ if (r6 < r7) \n"
410 "orrle r14,r14,#0x04 @ h |= 0x04 \n"
411 "ldrb r6, [r0, #-1] @ r6 = ht_line[7] \n"
412 "ldrb r7, [r1, #-1] @ r7 = pixmap[7] \n"
413 "cmp r4, r5 @ if (r4 < r5) \n"
414 "orrle r14,r14,#0x02 @ h |= 0x02 \n"
415 "cmp r6, r7 @ if (r7 < r6) \n"
416 "orrle r14,r14,#0x01 @ h |= 0x01 \n"
417 "subs r12,r12,#2 @ r12 = l -= 2 \n"
418 "strb r14,[r2], #1 @ *out++ = h \n"
419 "moveq r12,r9 @ if(l==0) l = ht_len \n"
420 "subeq r0, r0, r9, LSL #2 @ ht_line -= l \n"
421 "subs r3, r3, #2 @ w -= 2 \n"
422 "bgt 1b @ } \n"
423 "blt 3f @ \n"
424 "2: \n"
425 "ldrb r4, [r0], #1 @ r4 = ht_line[0] \n"
426 "ldrb r5, [r1], #1 @ r5 = pixmap[0] \n"
427 "mov r14, #0 @ r14= h = 0 \n"
428 "ldrb r6, [r0], #1 @ r6 = ht_line[1] \n"
429 "ldrb r7, [r1], #1 @ r7 = pixmap[1] \n"
430 "cmp r4, r5 @ if (r4 < r5) \n"
431 "orrle r14,r14,#0x80 @ h |= 0x80 \n"
432 "ldrb r4, [r0], #1 @ r6 = ht_line[2] \n"
433 "ldrb r5, [r1], #1 @ r7 = pixmap[2] \n"
434 "cmp r6, r7 @ if (r6 < r7) \n"
435 "orrle r14,r14,#0x40 @ h |= 0x40 \n"
436 "ldrb r6, [r0], #1 @ r6 = ht_line[1] \n"
437 "ldrb r7, [r1], #1 @ r7 = pixmap[3] \n"
438 "cmp r4, r5 @ if (r4 < r5) \n"
439 "orrle r14,r14,#0x20 @ h |= 0x20 \n"
440 "cmp r6, r7 @ if (r6 < r7) \n"
441 "orrle r14,r14,#0x10 @ h |= 0x10 \n"
442 "strb r14,[r2] @ *out = h \n"
443 "3: \n"
444 "ldmfd r13!,{r4-r7,r9,PC} @ pop, return to thumb \n"
445 ENTER_THUMB
446 );
447 }
448 #else
do_threshold_4(const unsigned char * FZ_RESTRICT ht_line,const unsigned char * FZ_RESTRICT pixmap,unsigned char * FZ_RESTRICT out,int w,int ht_len)449 static void do_threshold_4(const unsigned char * FZ_RESTRICT ht_line, const unsigned char * FZ_RESTRICT pixmap, unsigned char * FZ_RESTRICT out, int w, int ht_len)
450 {
451 int l = ht_len;
452
453 w--;
454 while (w > 0)
455 {
456 int h = 0;
457 if (pixmap[0] >= ht_line[0])
458 h |= 0x80;
459 if (pixmap[1] >= ht_line[1])
460 h |= 0x40;
461 if (pixmap[2] >= ht_line[2])
462 h |= 0x20;
463 if (pixmap[3] >= ht_line[3])
464 h |= 0x10;
465 if (pixmap[4] >= ht_line[4])
466 h |= 0x08;
467 if (pixmap[5] >= ht_line[5])
468 h |= 0x04;
469 if (pixmap[6] >= ht_line[6])
470 h |= 0x02;
471 if (pixmap[7] >= ht_line[7])
472 h |= 0x01;
473 *out++ = h;
474 l -= 2;
475 if (l == 0)
476 {
477 l = ht_len;
478 ht_line -= ht_len<<2;
479 }
480 pixmap += 8;
481 ht_line += 8;
482 w -= 2;
483 }
484 if (w == 0)
485 {
486 int h = 0;
487 if (pixmap[0] >= ht_line[0])
488 h |= 0x80;
489 if (pixmap[1] >= ht_line[1])
490 h |= 0x40;
491 if (pixmap[2] >= ht_line[2])
492 h |= 0x20;
493 if (pixmap[3] >= ht_line[3])
494 h |= 0x10;
495 *out = h;
496 }
497 }
498 #endif
499
fz_new_bitmap_from_pixmap(fz_context * ctx,fz_pixmap * pix,fz_halftone * ht)500 fz_bitmap *fz_new_bitmap_from_pixmap(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht)
501 {
502 return fz_new_bitmap_from_pixmap_band(ctx, pix, ht, 0);
503 }
504
505 /* TAOCP, vol 2, p337 */
gcd(int u,int v)506 static int gcd(int u, int v)
507 {
508 int r;
509
510 do
511 {
512 if (v == 0)
513 return u;
514 r = u % v;
515 u = v;
516 v = r;
517 }
518 while (1);
519 }
520
fz_new_bitmap_from_pixmap_band(fz_context * ctx,fz_pixmap * pix,fz_halftone * ht,int band_start)521 fz_bitmap *fz_new_bitmap_from_pixmap_band(fz_context *ctx, fz_pixmap *pix, fz_halftone *ht, int band_start)
522 {
523 fz_bitmap *out = NULL;
524 unsigned char *ht_line = NULL;
525 unsigned char *o, *p;
526 int w, h, x, y, n, pstride, ostride, lcm, i;
527 fz_halftone *ht_ = NULL;
528 threshold_fn *thresh;
529
530 fz_var(ht_line);
531
532 if (!pix)
533 return NULL;
534
535 if (pix->alpha != 0)
536 fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap may not have alpha channel to convert to bitmap");
537
538 n = pix->n;
539
540 switch(n)
541 {
542 case 1:
543 thresh = do_threshold_1;
544 break;
545 case 4:
546 thresh = do_threshold_4;
547 break;
548 default:
549 fz_throw(ctx, FZ_ERROR_GENERIC, "pixmap must be grayscale or CMYK to convert to bitmap");
550 return NULL;
551 }
552
553 if (ht == NULL)
554 ht_ = ht = fz_default_halftone(ctx, n);
555
556 /* Find the minimum length for the halftone line. This
557 * is the LCM of the halftone lengths and 8. (We need a
558 * multiple of 8 for the unrolled threshold routines - if
559 * we ever use SSE, we may need longer.) We use the fact
560 * that LCM(a,b) = a * b / GCD(a,b) and use euclids
561 * algorithm.
562 */
563 lcm = 8;
564 for (i = 0; i < ht->n; i++)
565 {
566 w = ht->comp[i]->w;
567 lcm = lcm / gcd(lcm, w) * w;
568 }
569
570 fz_try(ctx)
571 {
572 ht_line = fz_malloc(ctx, lcm * n);
573 out = fz_new_bitmap(ctx, pix->w, pix->h, n, pix->xres, pix->yres);
574 o = out->samples;
575 p = pix->samples;
576
577 h = pix->h;
578 x = pix->x;
579 y = pix->y + band_start;
580 w = pix->w;
581 ostride = out->stride;
582 pstride = pix->stride;
583 while (h--)
584 {
585 make_ht_line(ht_line, ht, x, y++, lcm);
586 thresh(ht_line, p, o, w, lcm);
587 o += ostride;
588 p += pstride;
589 }
590 }
591 fz_always(ctx)
592 {
593 fz_drop_halftone(ctx, ht_);
594 fz_free(ctx, ht_line);
595 }
596 fz_catch(ctx)
597 fz_rethrow(ctx);
598
599 return out;
600 }
601