1 #include "mupdf/fitz.h"
2
3 #include "color-imp.h"
4
5 #include <assert.h>
6 #include <limits.h>
7 #include <string.h>
8 #include <math.h>
9
10 fz_pixmap *
fz_keep_pixmap(fz_context * ctx,fz_pixmap * pix)11 fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix)
12 {
13 return fz_keep_storable(ctx, &pix->storable);
14 }
15
16 void
fz_drop_pixmap(fz_context * ctx,fz_pixmap * pix)17 fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix)
18 {
19 fz_drop_storable(ctx, &pix->storable);
20 }
21
22 void
fz_drop_pixmap_imp(fz_context * ctx,fz_storable * pix_)23 fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix_)
24 {
25 fz_pixmap *pix = (fz_pixmap *)pix_;
26
27 fz_drop_colorspace(ctx, pix->colorspace);
28 fz_drop_separations(ctx, pix->seps);
29 if (pix->flags & FZ_PIXMAP_FLAG_FREE_SAMPLES)
30 fz_free(ctx, pix->samples);
31 fz_drop_pixmap(ctx, pix->underlying);
32 fz_free(ctx, pix);
33 }
34
35 fz_pixmap *
fz_new_pixmap_with_data(fz_context * ctx,fz_colorspace * colorspace,int w,int h,fz_separations * seps,int alpha,int stride,unsigned char * samples)36 fz_new_pixmap_with_data(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha, int stride, unsigned char *samples)
37 {
38 fz_pixmap *pix;
39 int s = fz_count_active_separations(ctx, seps);
40 int n;
41
42 if (w < 0 || h < 0)
43 fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal dimensions for pixmap %d %d", w, h);
44
45 n = alpha + s + fz_colorspace_n(ctx, colorspace);
46 if (stride < n*w && stride > -n*w)
47 fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal stride for pixmap (n=%d w=%d, stride=%d)", n, w, stride);
48 if (samples == NULL && stride < n*w)
49 fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal -ve stride for pixmap without data");
50 if (n > FZ_MAX_COLORS)
51 fz_throw(ctx, FZ_ERROR_GENERIC, "Illegal number of colorants");
52
53 pix = fz_malloc_struct(ctx, fz_pixmap);
54 FZ_INIT_STORABLE(pix, 1, fz_drop_pixmap_imp);
55 pix->x = 0;
56 pix->y = 0;
57 pix->w = w;
58 pix->h = h;
59 pix->alpha = alpha = !!alpha;
60 pix->flags = FZ_PIXMAP_FLAG_INTERPOLATE;
61 pix->xres = 96;
62 pix->yres = 96;
63 pix->colorspace = NULL;
64 pix->n = n;
65 pix->s = s;
66 pix->seps = fz_keep_separations(ctx, seps);
67 pix->stride = stride;
68
69 if (colorspace)
70 {
71 pix->colorspace = fz_keep_colorspace(ctx, colorspace);
72 }
73 else
74 {
75 assert(alpha || s);
76 }
77
78 pix->samples = samples;
79 if (!samples && pix->h > 0 && pix->w > 0)
80 {
81 fz_try(ctx)
82 {
83 if (pix->stride > INT_MAX / pix->h)
84 fz_throw(ctx, FZ_ERROR_GENERIC, "Overly large image");
85 pix->samples = Memento_label(fz_malloc(ctx, pix->h * pix->stride), "pixmap_data");
86 }
87 fz_catch(ctx)
88 {
89 fz_drop_separations(ctx, pix->seps);
90 fz_drop_colorspace(ctx, pix->colorspace);
91 fz_free(ctx, pix);
92 fz_rethrow(ctx);
93 }
94 pix->flags |= FZ_PIXMAP_FLAG_FREE_SAMPLES;
95 }
96
97 return pix;
98 }
99
100 fz_pixmap *
fz_new_pixmap(fz_context * ctx,fz_colorspace * colorspace,int w,int h,fz_separations * seps,int alpha)101 fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha)
102 {
103 int stride;
104 int s = fz_count_active_separations(ctx, seps);
105 int n;
106 if (!colorspace && s == 0) alpha = 1;
107 n = fz_colorspace_n(ctx, colorspace) + s + alpha;
108 if (w > INT_MAX / n)
109 fz_throw(ctx, FZ_ERROR_GENERIC, "Overly wide image");
110 stride = n * w;
111 return fz_new_pixmap_with_data(ctx, colorspace, w, h, seps, alpha, stride, NULL);
112 }
113
114 fz_pixmap *
fz_new_pixmap_with_bbox(fz_context * ctx,fz_colorspace * colorspace,fz_irect bbox,fz_separations * seps,int alpha)115 fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha)
116 {
117 fz_pixmap *pixmap;
118 pixmap = fz_new_pixmap(ctx, colorspace, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, seps, alpha);
119 pixmap->x = bbox.x0;
120 pixmap->y = bbox.y0;
121 return pixmap;
122 }
123
124 fz_pixmap *
fz_new_pixmap_with_bbox_and_data(fz_context * ctx,fz_colorspace * colorspace,fz_irect bbox,fz_separations * seps,int alpha,unsigned char * samples)125 fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha, unsigned char *samples)
126 {
127 int w = bbox.x1 - bbox.x0;
128 int stride;
129 int s = fz_count_active_separations(ctx, seps);
130 fz_pixmap *pixmap;
131 if (!colorspace && s == 0) alpha = 1;
132 stride = (fz_colorspace_n(ctx, colorspace) + s + alpha) * w;
133 pixmap = fz_new_pixmap_with_data(ctx, colorspace, w, bbox.y1 - bbox.y0, seps, alpha, stride, samples);
134 pixmap->x = bbox.x0;
135 pixmap->y = bbox.y0;
136 return pixmap;
137 }
138
fz_new_pixmap_from_pixmap(fz_context * ctx,fz_pixmap * pixmap,const fz_irect * rect)139 fz_pixmap *fz_new_pixmap_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, const fz_irect *rect)
140 {
141 fz_irect local_rect;
142 fz_pixmap *subpix;
143
144 if (!pixmap)
145 return NULL;
146
147 if (rect == NULL)
148 {
149 rect = &local_rect;
150 local_rect.x0 = pixmap->x;
151 local_rect.y0 = pixmap->y;
152 local_rect.x1 = pixmap->x + pixmap->w;
153 local_rect.y1 = pixmap->y + pixmap->h;
154 }
155 else if (rect->x0 < pixmap->x || rect->y0 < pixmap->y || rect->x1 > pixmap->x + pixmap->w || rect->y1 > pixmap->y + pixmap->h)
156 fz_throw(ctx, FZ_ERROR_GENERIC, "Pixmap region is not a subarea");
157
158 subpix = fz_malloc_struct(ctx, fz_pixmap);
159 *subpix = *pixmap;
160 subpix->storable.refs = 1;
161 subpix->x = rect->x0;
162 subpix->y = rect->y0;
163 subpix->w = rect->x1 - rect->x0;
164 subpix->h = rect->y1 - rect->y0;
165 subpix->samples += (rect->x0 - pixmap->x) + (rect->y0 - pixmap->y) * pixmap->stride;
166 subpix->underlying = fz_keep_pixmap(ctx, pixmap);
167 subpix->colorspace = fz_keep_colorspace(ctx, pixmap->colorspace);
168 subpix->seps = fz_keep_separations(ctx, pixmap->seps);
169 subpix->flags &= ~FZ_PIXMAP_FLAG_FREE_SAMPLES;
170
171 return subpix;
172 }
173
fz_clone_pixmap(fz_context * ctx,const fz_pixmap * old)174 fz_pixmap *fz_clone_pixmap(fz_context *ctx, const fz_pixmap *old)
175 {
176 fz_pixmap *pix = fz_new_pixmap_with_bbox(ctx, old->colorspace, fz_make_irect(old->x, old->y, old->w, old->h), old->seps, old->alpha);
177 memcpy(pix->samples, old->samples, pix->stride * pix->h);
178 return pix;
179 }
180
181 fz_irect
fz_pixmap_bbox(fz_context * ctx,const fz_pixmap * pix)182 fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix)
183 {
184 fz_irect bbox;
185 bbox.x0 = pix->x;
186 bbox.y0 = pix->y;
187 bbox.x1 = pix->x + pix->w;
188 bbox.y1 = pix->y + pix->h;
189 return bbox;
190 }
191
192 fz_irect
fz_pixmap_bbox_no_ctx(const fz_pixmap * pix)193 fz_pixmap_bbox_no_ctx(const fz_pixmap *pix)
194 {
195 fz_irect bbox;
196 bbox.x0 = pix->x;
197 bbox.y0 = pix->y;
198 bbox.x1 = pix->x + pix->w;
199 bbox.y1 = pix->y + pix->h;
200 return bbox;
201 }
202
203 fz_colorspace *
fz_pixmap_colorspace(fz_context * ctx,const fz_pixmap * pix)204 fz_pixmap_colorspace(fz_context *ctx, const fz_pixmap *pix)
205 {
206 if (!pix)
207 return NULL;
208 return pix->colorspace;
209 }
210
211 int
fz_pixmap_x(fz_context * ctx,const fz_pixmap * pix)212 fz_pixmap_x(fz_context *ctx, const fz_pixmap *pix)
213 {
214 return pix->x;
215 }
216
217 int
fz_pixmap_y(fz_context * ctx,const fz_pixmap * pix)218 fz_pixmap_y(fz_context *ctx, const fz_pixmap *pix)
219 {
220 return pix->y;
221 }
222
223 int
fz_pixmap_width(fz_context * ctx,const fz_pixmap * pix)224 fz_pixmap_width(fz_context *ctx, const fz_pixmap *pix)
225 {
226 return pix->w;
227 }
228
229 int
fz_pixmap_height(fz_context * ctx,const fz_pixmap * pix)230 fz_pixmap_height(fz_context *ctx, const fz_pixmap *pix)
231 {
232 return pix->h;
233 }
234
235 int
fz_pixmap_components(fz_context * ctx,const fz_pixmap * pix)236 fz_pixmap_components(fz_context *ctx, const fz_pixmap *pix)
237 {
238 return pix->n;
239 }
240
241 int
fz_pixmap_colorants(fz_context * ctx,const fz_pixmap * pix)242 fz_pixmap_colorants(fz_context *ctx, const fz_pixmap *pix)
243 {
244 return pix->n - pix->alpha - pix->s;
245 }
246
247 int
fz_pixmap_spots(fz_context * ctx,const fz_pixmap * pix)248 fz_pixmap_spots(fz_context *ctx, const fz_pixmap *pix)
249 {
250 return pix->s;
251 }
252
253 int
fz_pixmap_alpha(fz_context * ctx,const fz_pixmap * pix)254 fz_pixmap_alpha(fz_context *ctx, const fz_pixmap *pix)
255 {
256 return pix->alpha;
257 }
258
259 int
fz_pixmap_stride(fz_context * ctx,const fz_pixmap * pix)260 fz_pixmap_stride(fz_context *ctx, const fz_pixmap *pix)
261 {
262 return pix->stride;
263 }
264
265 unsigned char *
fz_pixmap_samples(fz_context * ctx,const fz_pixmap * pix)266 fz_pixmap_samples(fz_context *ctx, const fz_pixmap *pix)
267 {
268 if (!pix)
269 return NULL;
270 return pix->samples;
271 }
272
273 /*
274 The slowest routine in most CMYK rendering profiles.
275 We therefore spend some effort to improve it. Rather than
276 writing bytes, we write uint32_t's.
277 */
278 #ifdef ARCH_ARM
279 static void
280 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value)
281 __attribute__((naked));
282
283 static void
clear_cmyka_bitmap_ARM(uint32_t * samples,int c,int value)284 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value)
285 {
286 asm volatile(
287 ENTER_ARM
288 "stmfd r13!,{r4-r6,r14} \n"
289 "@ r0 = samples \n"
290 "@ r1 = c \n"
291 "@ r2 = value \n"
292 "mov r3, #255 \n"
293 "mov r12,#0 @ r12= 0 \n"
294 "subs r1, r1, #3 \n"
295 "ble 2f \n"
296 "str r12,[r13,#-20]! \n"
297 "str r12,[r13,#4] \n"
298 "str r12,[r13,#8] \n"
299 "str r12,[r13,#12] \n"
300 "str r12,[r13,#16] \n"
301 "strb r2, [r13,#3] \n"
302 "strb r3, [r13,#4] \n"
303 "strb r2, [r13,#8] \n"
304 "strb r3, [r13,#9] \n"
305 "strb r2, [r13,#13] \n"
306 "strb r3, [r13,#14] \n"
307 "strb r2, [r13,#18] \n"
308 "strb r3, [r13,#19] \n"
309 "ldmfd r13!,{r4,r5,r6,r12,r14} \n"
310 "1: \n"
311 "stmia r0!,{r4,r5,r6,r12,r14} \n"
312 "subs r1, r1, #4 \n"
313 "bgt 1b \n"
314 "2: \n"
315 "adds r1, r1, #3 \n"
316 "ble 4f \n"
317 "3: \n"
318 "strb r12,[r0], #1 \n"
319 "strb r12,[r0], #1 \n"
320 "strb r12,[r0], #1 \n"
321 "strb r2, [r0], #1 \n"
322 "strb r3, [r0], #1 \n"
323 "subs r1, r1, #1 \n"
324 "bgt 3b \n"
325 "4: \n"
326 "ldmfd r13!,{r4-r6,PC} \n"
327 ENTER_THUMB
328 );
329 }
330 #endif
331
332 static void
clear_cmyk_bitmap(unsigned char * samples,int w,int h,int spots,int stride,int value,int alpha)333 clear_cmyk_bitmap(unsigned char *samples, int w, int h, int spots, int stride, int value, int alpha)
334 {
335 uint32_t *s = (uint32_t *)(void *)samples;
336 uint8_t *t;
337
338 if (w < 0 || h < 0)
339 return;
340
341 if (spots)
342 {
343 int x, i;
344 spots += 4;
345 stride -= w * (spots + alpha);
346 for (; h > 0; h--)
347 {
348 for (x = w; x > 0; x--)
349 {
350 for (i = spots; i > 0; i--)
351 *samples++ = value;
352 if (alpha)
353 *samples++ = 255;
354 }
355 samples += stride;
356 }
357 return;
358 }
359
360 if (alpha)
361 {
362 int c = w;
363 stride -= w*5;
364 if (stride == 0)
365 {
366 #ifdef ARCH_ARM
367 clear_cmyka_bitmap_ARM(s, c, alpha);
368 return;
369 #else
370 /* We can do it all fast (except for maybe a few stragglers) */
371 union
372 {
373 uint8_t bytes[20];
374 uint32_t words[5];
375 } d;
376
377 c *= h;
378 h = 1;
379
380 d.words[0] = 0;
381 d.words[1] = 0;
382 d.words[2] = 0;
383 d.words[3] = 0;
384 d.words[4] = 0;
385 d.bytes[3] = value;
386 d.bytes[4] = 255;
387 d.bytes[8] = value;
388 d.bytes[9] = 255;
389 d.bytes[13] = value;
390 d.bytes[14] = 255;
391 d.bytes[18] = value;
392 d.bytes[19] = 255;
393
394 c -= 3;
395 {
396 const uint32_t a0 = d.words[0];
397 const uint32_t a1 = d.words[1];
398 const uint32_t a2 = d.words[2];
399 const uint32_t a3 = d.words[3];
400 const uint32_t a4 = d.words[4];
401 while (c > 0)
402 {
403 *s++ = a0;
404 *s++ = a1;
405 *s++ = a2;
406 *s++ = a3;
407 *s++ = a4;
408 c -= 4;
409 }
410 }
411 c += 3;
412 #endif
413 }
414 t = (unsigned char *)s;
415 w = c;
416 while (h--)
417 {
418 c = w;
419 while (c > 0)
420 {
421 *t++ = 0;
422 *t++ = 0;
423 *t++ = 0;
424 *t++ = value;
425 *t++ = 255;
426 c--;
427 }
428 t += stride;
429 }
430 }
431 else
432 {
433 stride -= w*4;
434 if ((stride & 3) == 0)
435 {
436 size_t W = w;
437 if (stride == 0)
438 {
439 W *= h;
440 h = 1;
441 }
442 W *= 4;
443 if (value == 0)
444 {
445 while (h--)
446 {
447 memset(s, 0, W);
448 s += (stride>>2);
449 }
450 }
451 else
452 {
453 /* We can do it all fast */
454 union
455 {
456 uint8_t bytes[4];
457 uint32_t word;
458 } d;
459
460 d.word = 0;
461 d.bytes[3] = value;
462 {
463 const uint32_t a0 = d.word;
464 while (h--)
465 {
466 size_t WW = W >> 2;
467 while (WW--)
468 {
469 *s++ = a0;
470 }
471 s += (stride>>2);
472 }
473 }
474 }
475 }
476 else
477 {
478 t = (unsigned char *)s;
479 while (h--)
480 {
481 int c = w;
482 while (c > 0)
483 {
484 *t++ = 0;
485 *t++ = 0;
486 *t++ = 0;
487 *t++ = value;
488 c--;
489 }
490 t += stride;
491 }
492 }
493 }
494 }
495
496 void
fz_clear_pixmap(fz_context * ctx,fz_pixmap * pix)497 fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix)
498 {
499 int stride = pix->w * pix->n;
500 int h = pix->h;
501 unsigned char *s = pix->samples;
502 if (stride == pix->stride)
503 {
504 stride *= h;
505 h = 1;
506 }
507 if (pix->alpha || fz_colorspace_is_subtractive(ctx, pix->colorspace))
508 {
509 while (h--)
510 {
511 memset(s, 0, (unsigned int)stride);
512 s += pix->stride;
513 }
514 }
515 else if (pix->s == 0)
516 {
517 while (h--)
518 {
519 memset(s, 0xff, (unsigned int)stride);
520 s += pix->stride;
521 }
522 }
523 else
524 {
525 /* Horrible, slow case: additive with spots */
526 int w = stride/pix->n;
527 int spots = pix->s;
528 int colorants = pix->n - spots; /* We know there is no alpha */
529 while (h--)
530 {
531 int w2 = w;
532 while (w2--)
533 {
534 int i = colorants;
535 do
536 {
537 *s++ = 0xff;
538 i--;
539 }
540 while (i != 0);
541
542 i = spots;
543 do
544 {
545 *s++ = 0;
546 i--;
547 }
548 while (i != 0);
549 }
550 }
551 }
552 }
553
554 void
fz_clear_pixmap_with_value(fz_context * ctx,fz_pixmap * pix,int value)555 fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value)
556 {
557 unsigned char *s;
558 int w, h, n, stride, len;
559 int alpha = pix->alpha;
560
561 w = pix->w;
562 h = pix->h;
563 if (w < 0 || h < 0)
564 return;
565
566 /* CMYK needs special handling (and potentially any other subtractive colorspaces) */
567 if (fz_colorspace_n(ctx, pix->colorspace) == 4)
568 {
569 clear_cmyk_bitmap(pix->samples, w, h, pix->s, pix->stride, 255-value, pix->alpha);
570 return;
571 }
572
573 n = pix->n;
574 stride = pix->stride;
575 len = w * n;
576
577 s = pix->samples;
578 if (value == 255 || !alpha)
579 {
580 if (stride == len)
581 {
582 len *= h;
583 h = 1;
584 }
585 while (h--)
586 {
587 memset(s, value, (unsigned int)len);
588 s += stride;
589 }
590 }
591 else
592 {
593 int k, x, y;
594 stride -= len;
595 for (y = 0; y < pix->h; y++)
596 {
597 for (x = 0; x < pix->w; x++)
598 {
599 for (k = 0; k < pix->n - 1; k++)
600 *s++ = value;
601 if (alpha)
602 *s++ = 255;
603 }
604 s += stride;
605 }
606 }
607 }
608
609 void
fz_fill_pixmap_with_color(fz_context * ctx,fz_pixmap * pix,fz_colorspace * colorspace,float * color,fz_color_params color_params)610 fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *colorspace, float *color, fz_color_params color_params)
611 {
612 float colorfv[FZ_MAX_COLORS];
613 unsigned char colorbv[FZ_MAX_COLORS];
614 int i, n, a, s, x, y, w, h;
615
616 n = fz_colorspace_n(ctx, pix->colorspace);
617 a = pix->alpha;
618 s = pix->s;
619 fz_convert_color(ctx, colorspace, color, pix->colorspace, colorfv, NULL, color_params);
620 for (i = 0; i < n; ++i)
621 colorbv[i] = colorfv[i] * 255;
622
623 w = pix->w;
624 h = pix->h;
625 for (y = 0; y < h; ++y)
626 {
627 unsigned char *p = pix->samples + y * pix->stride;
628 for (x = 0; x < w; ++x)
629 {
630 for (i = 0; i < n; ++i)
631 *p++ = colorbv[i];
632 for (i = 0; i < s; ++i)
633 *p++ = 0;
634 if (a)
635 *p++ = 255;
636 }
637 }
638 }
639
640 void
fz_copy_pixmap_rect(fz_context * ctx,fz_pixmap * dest,fz_pixmap * src,fz_irect b,const fz_default_colorspaces * default_cs)641 fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_irect b, const fz_default_colorspaces *default_cs)
642 {
643 unsigned char *srcp;
644 unsigned char *destp;
645 int y, w, destspan, srcspan;
646
647 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
648 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, src));
649 w = b.x1 - b.x0;
650 y = b.y1 - b.y0;
651 if (w <= 0 || y <= 0)
652 return;
653
654 srcspan = src->stride;
655 srcp = src->samples + (unsigned int)(srcspan * (b.y0 - src->y) + src->n * (b.x0 - src->x));
656 destspan = dest->stride;
657 destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));
658
659 if (src->n == dest->n)
660 {
661 w *= src->n;
662 do
663 {
664 memcpy(destp, srcp, w);
665 srcp += srcspan;
666 destp += destspan;
667 }
668 while (--y);
669 }
670 else
671 {
672 fz_pixmap fake_src = *src;
673 fake_src.x = b.x0;
674 fake_src.y = b.y0;
675 fake_src.w = w;
676 fake_src.h = y;
677 fake_src.samples = srcp;
678 fz_convert_pixmap_samples(ctx, dest, &fake_src, NULL, default_cs, fz_default_color_params, 0);
679 }
680 }
681
682 void
fz_clear_pixmap_rect_with_value(fz_context * ctx,fz_pixmap * dest,int value,fz_irect b)683 fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_irect b)
684 {
685 unsigned char *destp;
686 int x, y, w, k, destspan;
687
688 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
689 w = b.x1 - b.x0;
690 y = b.y1 - b.y0;
691 if (w <= 0 || y <= 0)
692 return;
693
694 destspan = dest->stride;
695 destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));
696
697 /* CMYK needs special handling (and potentially any other subtractive colorspaces) */
698 if (fz_colorspace_n(ctx, dest->colorspace) == 4)
699 {
700 value = 255 - value;
701 do
702 {
703 unsigned char *s = destp;
704 for (x = 0; x < w; x++)
705 {
706 *s++ = 0;
707 *s++ = 0;
708 *s++ = 0;
709 *s++ = value;
710 *s++ = 255;
711 }
712 destp += destspan;
713 }
714 while (--y);
715 return;
716 }
717
718 if (value == 255)
719 {
720 do
721 {
722 memset(destp, 255, (unsigned int)(w * dest->n));
723 destp += destspan;
724 }
725 while (--y);
726 }
727 else
728 {
729 do
730 {
731 unsigned char *s = destp;
732 for (x = 0; x < w; x++)
733 {
734 for (k = 0; k < dest->n - 1; k++)
735 *s++ = value;
736 *s++ = 255;
737 }
738 destp += destspan;
739 }
740 while (--y);
741 }
742 }
743
744 void
fz_premultiply_pixmap(fz_context * ctx,fz_pixmap * pix)745 fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix)
746 {
747 unsigned char *s = pix->samples;
748 unsigned char a;
749 int k, x, y;
750 int stride = pix->stride - pix->w * pix->n;
751
752 if (!pix->alpha)
753 return;
754
755 for (y = 0; y < pix->h; y++)
756 {
757 for (x = 0; x < pix->w; x++)
758 {
759 a = s[pix->n - 1];
760 for (k = 0; k < pix->n - 1; k++)
761 s[k] = fz_mul255(s[k], a);
762 s += pix->n;
763 }
764 s += stride;
765 }
766 }
767
768 fz_pixmap *
fz_alpha_from_gray(fz_context * ctx,fz_pixmap * gray)769 fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray)
770 {
771 fz_pixmap *alpha;
772 unsigned char *sp, *dp;
773 int w, h, sstride, dstride;
774
775 assert(gray->n == 1);
776
777 alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray), 0, 1);
778 dp = alpha->samples;
779 dstride = alpha->stride;
780 sp = gray->samples;
781 sstride = gray->stride;
782
783 h = gray->h;
784 w = gray->w;
785 while (h--)
786 {
787 memcpy(dp, sp, w);
788 sp += sstride;
789 dp += dstride;
790 }
791
792 return alpha;
793 }
794
795 void
fz_tint_pixmap(fz_context * ctx,fz_pixmap * pix,int black,int white)796 fz_tint_pixmap(fz_context *ctx, fz_pixmap *pix, int black, int white)
797 {
798 unsigned char *s = pix->samples;
799 int n = pix->n;
800 int x, y, save;
801 int rb = (black>>16)&255;
802 int gb = (black>>8)&255;
803 int bb = (black)&255;
804 int rw = (white>>16)&255;
805 int gw = (white>>8)&255;
806 int bw = (white)&255;
807 int rm = (rw - rb);
808 int gm = (gw - gb);
809 int bm = (bw - bb);
810
811 switch (fz_colorspace_type(ctx, pix->colorspace))
812 {
813 case FZ_COLORSPACE_GRAY:
814 gw = (rw + gw + bw) / 3;
815 gb = (rb + gb + bb) / 3;
816 gm = gw - gb;
817 for (y = 0; y < pix->h; y++)
818 {
819 for (x = 0; x < pix->w; x++)
820 {
821 *s = gb + fz_mul255(*s, gm);
822 s += n;
823 }
824 s += pix->stride - pix->w * n;
825 }
826 break;
827
828 case FZ_COLORSPACE_BGR:
829 save = rm; rm = bm; bm = save;
830 save = rb; rb = bb; bb = save;
831 /* fall through */
832 case FZ_COLORSPACE_RGB:
833 for (y = 0; y < pix->h; y++)
834 {
835 for (x = 0; x < pix->w; x++)
836 {
837 s[0] = rb + fz_mul255(s[0], rm);
838 s[1] = gb + fz_mul255(s[1], gm);
839 s[2] = bb + fz_mul255(s[2], bm);
840 s += n;
841 }
842 s += pix->stride - pix->w * n;
843 }
844 break;
845
846 default:
847 fz_throw(ctx, FZ_ERROR_GENERIC, "can only tint RGB, BGR and Gray pixmaps");
848 break;
849 }
850 }
851
852 /* Invert luminance in RGB/BGR pixmap, but keep the colors as is. */
invert_luminance(int type,unsigned char * s)853 static inline void invert_luminance(int type, unsigned char *s)
854 {
855 int r, g, b, y;
856
857 /* Convert to YUV */
858 if (type == FZ_COLORSPACE_RGB)
859 {
860 r = s[0];
861 g = s[1];
862 b = s[2];
863 }
864 else
865 {
866 r = s[2];
867 g = s[1];
868 b = s[0];
869 }
870
871 y = (39336 * r + 76884 * g + 14900 * b + 32768)>>16;
872 y = 259-y;
873 r += y;
874 g += y;
875 b += y;
876
877 if (type == FZ_COLORSPACE_RGB)
878 {
879 s[0] = r > 255 ? 255 : r < 0 ? 0 : r;
880 s[1] = g > 255 ? 255 : g < 0 ? 0 : g;
881 s[2] = b > 255 ? 255 : b < 0 ? 0 : b;
882 }
883 else
884 {
885 s[2] = r > 255 ? 255 : r < 0 ? 0 : r;
886 s[1] = g > 255 ? 255 : g < 0 ? 0 : g;
887 s[0] = b > 255 ? 255 : b < 0 ? 0 : b;
888 }
889 }
890
891 void
fz_invert_pixmap_luminance(fz_context * ctx,fz_pixmap * pix)892 fz_invert_pixmap_luminance(fz_context *ctx, fz_pixmap *pix)
893 {
894 unsigned char *s = pix->samples;
895 int x, y, n = pix->n;
896 int type = pix->colorspace ? pix->colorspace->type : FZ_COLORSPACE_NONE;
897
898 if (type == FZ_COLORSPACE_GRAY)
899 {
900 fz_invert_pixmap(ctx, pix);
901 }
902 else if (type == FZ_COLORSPACE_RGB || type == FZ_COLORSPACE_BGR)
903 {
904 for (y = 0; y < pix->h; y++)
905 {
906 for (x = 0; x < pix->w; x++)
907 {
908 invert_luminance(type, s);
909 s += n;
910 }
911 s += pix->stride - pix->w * n;
912 }
913 }
914 else
915 {
916 fz_throw(ctx, FZ_ERROR_GENERIC, "can only invert luminance of Gray and RGB pixmaps");
917 }
918 }
919
920 void
fz_invert_pixmap(fz_context * ctx,fz_pixmap * pix)921 fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix)
922 {
923 unsigned char *s = pix->samples;
924 int k, x, y;
925 int n1 = pix->n - pix->alpha;
926 int n = pix->n;
927
928 for (y = 0; y < pix->h; y++)
929 {
930 for (x = 0; x < pix->w; x++)
931 {
932 for (k = 0; k < n1; k++)
933 s[k] = 255 - s[k];
934 s += n;
935 }
936 s += pix->stride - pix->w * n;
937 }
938 }
939
fz_invert_pixmap_rect(fz_context * ctx,fz_pixmap * image,fz_irect rect)940 void fz_invert_pixmap_rect(fz_context *ctx, fz_pixmap *image, fz_irect rect)
941 {
942 unsigned char *p;
943 int x, y, n;
944
945 int x0 = fz_clampi(rect.x0 - image->x, 0, image->w);
946 int x1 = fz_clampi(rect.x1 - image->x, 0, image->w);
947 int y0 = fz_clampi(rect.y0 - image->y, 0, image->h);
948 int y1 = fz_clampi(rect.y1 - image->y, 0, image->h);
949
950 for (y = y0; y < y1; y++)
951 {
952 p = image->samples + (unsigned int)((y * image->stride) + (x0 * image->n));
953 for (x = x0; x < x1; x++)
954 {
955 for (n = image->n; n > 1; n--, p++)
956 *p = 255 - *p;
957 p++;
958 }
959 }
960 }
961
962 void
fz_gamma_pixmap(fz_context * ctx,fz_pixmap * pix,float gamma)963 fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma)
964 {
965 unsigned char gamma_map[256];
966 unsigned char *s = pix->samples;
967 int n1 = pix->n - pix->alpha;
968 int n = pix->n;
969 int k, x, y;
970
971 for (k = 0; k < 256; k++)
972 gamma_map[k] = pow(k / 255.0f, gamma) * 255;
973
974 for (y = 0; y < pix->h; y++)
975 {
976 for (x = 0; x < pix->w; x++)
977 {
978 for (k = 0; k < n1; k++)
979 s[k] = gamma_map[s[k]];
980 s += n;
981 }
982 s += pix->stride - pix->w * n;
983 }
984 }
985
986 size_t
fz_pixmap_size(fz_context * ctx,fz_pixmap * pix)987 fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
988 {
989 if (pix == NULL)
990 return 0;
991 return sizeof(*pix) + (size_t)pix->n * pix->w * pix->h;
992 }
993
994 fz_pixmap *
fz_convert_pixmap(fz_context * ctx,const fz_pixmap * pix,fz_colorspace * ds,fz_colorspace * prf,fz_default_colorspaces * default_cs,fz_color_params color_params,int keep_alpha)995 fz_convert_pixmap(fz_context *ctx, const fz_pixmap *pix, fz_colorspace *ds, fz_colorspace *prf, fz_default_colorspaces *default_cs, fz_color_params color_params, int keep_alpha)
996 {
997 fz_pixmap *cvt;
998
999 if (!ds && !keep_alpha)
1000 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot both throw away and keep alpha");
1001
1002 cvt = fz_new_pixmap(ctx, ds, pix->w, pix->h, pix->seps, keep_alpha && pix->alpha);
1003
1004 cvt->xres = pix->xres;
1005 cvt->yres = pix->yres;
1006 cvt->x = pix->x;
1007 cvt->y = pix->y;
1008 if (pix->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1009 cvt->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1010 else
1011 cvt->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1012
1013 fz_try(ctx)
1014 {
1015 fz_convert_pixmap_samples(ctx, pix, cvt, prf, default_cs, color_params, 1);
1016 }
1017 fz_catch(ctx)
1018 {
1019 fz_drop_pixmap(ctx, cvt);
1020 fz_rethrow(ctx);
1021 }
1022
1023 return cvt;
1024 }
1025
1026 fz_pixmap *
fz_new_pixmap_from_8bpp_data(fz_context * ctx,int x,int y,int w,int h,unsigned char * sp,int span)1027 fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1028 {
1029 fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1030 int stride = pixmap->stride;
1031 unsigned char *s = pixmap->samples;
1032 pixmap->x = x;
1033 pixmap->y = y;
1034
1035 for (y = 0; y < h; y++)
1036 {
1037 memcpy(s, sp + y * span, w);
1038 s += stride;
1039 }
1040
1041 return pixmap;
1042 }
1043
1044 fz_pixmap *
fz_new_pixmap_from_1bpp_data(fz_context * ctx,int x,int y,int w,int h,unsigned char * sp,int span)1045 fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1046 {
1047 fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1048 int stride = pixmap->stride - pixmap->w;
1049 pixmap->x = x;
1050 pixmap->y = y;
1051
1052 for (y = 0; y < h; y++)
1053 {
1054 unsigned char *out = pixmap->samples + y * w;
1055 unsigned char *in = sp + y * span;
1056 unsigned char bit = 0x80;
1057 int ww = w;
1058 while (ww--)
1059 {
1060 *out++ = (*in & bit) ? 255 : 0;
1061 bit >>= 1;
1062 if (bit == 0)
1063 bit = 0x80, in++;
1064 }
1065 out += stride;
1066 }
1067
1068 return pixmap;
1069 }
1070
1071 int
fz_is_pixmap_monochrome(fz_context * ctx,fz_pixmap * pixmap)1072 fz_is_pixmap_monochrome(fz_context *ctx, fz_pixmap *pixmap)
1073 {
1074 int n = pixmap->n;
1075 int w = pixmap->w;
1076 int h = pixmap->h;
1077 unsigned char *s = pixmap->samples;
1078 int x;
1079
1080 if (n != 1)
1081 return 0;
1082
1083 while (h--)
1084 {
1085 for (x = 0; x < w; ++x)
1086 {
1087 unsigned char v = s[x];
1088 if (v != 0 && v != 255)
1089 return 0;
1090 }
1091 s += pixmap->stride;
1092 }
1093
1094 return 1;
1095 }
1096
1097 #ifdef ARCH_ARM
1098 static void
1099 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1100 int n, int fwd, int back, int back2, int fwd2,
1101 int divX, int back4, int fwd4, int fwd3,
1102 int divY, int back5, int divXY)
1103 __attribute__((naked));
1104
1105 static void
fz_subsample_pixmap_ARM(unsigned char * ptr,int w,int h,int f,int factor,int n,int fwd,int back,int back2,int fwd2,int divX,int back4,int fwd4,int fwd3,int divY,int back5,int divXY)1106 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1107 int n, int fwd, int back, int back2, int fwd2,
1108 int divX, int back4, int fwd4, int fwd3,
1109 int divY, int back5, int divXY)
1110 {
1111 asm volatile(
1112 ENTER_ARM
1113 "stmfd r13!,{r1,r4-r11,r14} \n"
1114 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1115 "@ r0 = src = ptr \n"
1116 "@ r1 = w \n"
1117 "@ r2 = h \n"
1118 "@ r3 = f \n"
1119 "mov r9, r0 @ r9 = dst = ptr \n"
1120 "ldr r6, [r13,#4*12] @ r6 = fwd \n"
1121 "ldr r7, [r13,#4*13] @ r7 = back \n"
1122 "subs r2, r2, r3 @ r2 = h -= f \n"
1123 "blt 11f @ Skip if less than a full row \n"
1124 "1: @ for (y = h; y > 0; y--) { \n"
1125 "ldr r1, [r13] @ r1 = w \n"
1126 "subs r1, r1, r3 @ r1 = w -= f \n"
1127 "blt 6f @ Skip if less than a full col \n"
1128 "ldr r4, [r13,#4*10] @ r4 = factor \n"
1129 "ldr r8, [r13,#4*14] @ r8 = back2 \n"
1130 "ldr r12,[r13,#4*15] @ r12= fwd2 \n"
1131 "2: @ for (x = w; x > 0; x--) { \n"
1132 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1133 "3: @ \n"
1134 "mov r14,#0 @ r14= v = 0 \n"
1135 "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n"
1136 "4: @ \n"
1137 "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n"
1138 "5: @ \n"
1139 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n"
1140 "subs r5, r5, #1<<16 @ xx-- \n"
1141 "add r14,r14,r11 @ v += r11 \n"
1142 "bgt 5b @ } \n"
1143 "sub r0, r0, r7 @ src -= back \n"
1144 "adds r5, r5, #1<<8 @ yy-- \n"
1145 "blt 4b @ } \n"
1146 "mov r14,r14,LSR r4 @ r14 = v >>= factor \n"
1147 "strb r14,[r9], #1 @ *d++ = r14 \n"
1148 "sub r0, r0, r8 @ s -= back2 \n"
1149 "subs r5, r5, #1 @ n-- \n"
1150 "bgt 3b @ } \n"
1151 "add r0, r0, r12 @ s += fwd2 \n"
1152 "subs r1, r1, r3 @ x -= f \n"
1153 "bge 2b @ } \n"
1154 "6: @ Less than a full column left \n"
1155 "adds r1, r1, r3 @ x += f \n"
1156 "beq 11f @ if (x == 0) next row \n"
1157 "@ r0 = src \n"
1158 "@ r1 = x \n"
1159 "@ r2 = y \n"
1160 "@ r3 = f \n"
1161 "@ r4 = factor \n"
1162 "@ r6 = fwd \n"
1163 "@ r7 = back \n"
1164 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1165 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1166 "ldr r4, [r13,#4*16] @ r4 = divX \n"
1167 "ldr r8, [r13,#4*17] @ r8 = back4 \n"
1168 "ldr r12,[r13,#4*18] @ r12= fwd4 \n"
1169 "8: @ \n"
1170 "mov r14,#0 @ r14= v = 0 \n"
1171 "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n"
1172 "9: @ \n"
1173 "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n"
1174 "10: @ \n"
1175 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n"
1176 "subs r5, r5, #1<<16 @ xx-- \n"
1177 "add r14,r14,r11 @ v += r11 \n"
1178 "bgt 10b @ } \n"
1179 "sub r0, r0, r7 @ src -= back \n"
1180 "adds r5, r5, #1<<8 @ yy-- \n"
1181 "blt 9b @ } \n"
1182 "mul r14,r4, r14 @ r14= v *= divX \n"
1183 "mov r14,r14,LSR #16 @ r14= v >>= 16 \n"
1184 "strb r14,[r9], #1 @ *d++ = r14 \n"
1185 "sub r0, r0, r8 @ s -= back4 \n"
1186 "subs r5, r5, #1 @ n-- \n"
1187 "bgt 8b @ } \n"
1188 "add r0, r0, r12 @ s += fwd4 \n"
1189 "11: @ \n"
1190 "ldr r14,[r13,#4*19] @ r14 = fwd3 \n"
1191 "subs r2, r2, r3 @ h -= f \n"
1192 "add r0, r0, r14 @ s += fwd3 \n"
1193 "bge 1b @ } \n"
1194 "adds r2, r2, r3 @ h += f \n"
1195 "beq 21f @ if no stray row, end \n"
1196 "@ So doing one last (partial) row \n"
1197 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1198 "@ r0 = src = ptr \n"
1199 "@ r1 = w \n"
1200 "@ r2 = h \n"
1201 "@ r3 = f \n"
1202 "@ r4 = factor \n"
1203 "@ r5 = n \n"
1204 "@ r6 = fwd \n"
1205 "12: @ for (y = h; y > 0; y--) { \n"
1206 "ldr r1, [r13] @ r1 = w \n"
1207 "ldr r7, [r13,#4*21] @ r7 = back5 \n"
1208 "ldr r8, [r13,#4*14] @ r8 = back2 \n"
1209 "subs r1, r1, r3 @ r1 = w -= f \n"
1210 "blt 17f @ Skip if less than a full col \n"
1211 "ldr r4, [r13,#4*20] @ r4 = divY \n"
1212 "ldr r12,[r13,#4*15] @ r12= fwd2 \n"
1213 "13: @ for (x = w; x > 0; x--) { \n"
1214 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1215 "14: @ \n"
1216 "mov r14,#0 @ r14= v = 0 \n"
1217 "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n"
1218 "15: @ \n"
1219 "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n"
1220 "16: @ \n"
1221 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n"
1222 "subs r5, r5, #1<<16 @ xx-- \n"
1223 "add r14,r14,r11 @ v += r11 \n"
1224 "bgt 16b @ } \n"
1225 "sub r0, r0, r7 @ src -= back5 \n"
1226 "adds r5, r5, #1<<8 @ yy-- \n"
1227 "blt 15b @ } \n"
1228 "mul r14,r4, r14 @ r14 = x *= divY \n"
1229 "mov r14,r14,LSR #16 @ r14 = v >>= 16 \n"
1230 "strb r14,[r9], #1 @ *d++ = r14 \n"
1231 "sub r0, r0, r8 @ s -= back2 \n"
1232 "subs r5, r5, #1 @ n-- \n"
1233 "bgt 14b @ } \n"
1234 "add r0, r0, r12 @ s += fwd2 \n"
1235 "subs r1, r1, r3 @ x -= f \n"
1236 "bge 13b @ } \n"
1237 "17: @ Less than a full column left \n"
1238 "adds r1, r1, r3 @ x += f \n"
1239 "beq 21f @ if (x == 0) end \n"
1240 "@ r0 = src \n"
1241 "@ r1 = x \n"
1242 "@ r2 = y \n"
1243 "@ r3 = f \n"
1244 "@ r4 = factor \n"
1245 "@ r6 = fwd \n"
1246 "@ r7 = back5 \n"
1247 "@ r8 = back2 \n"
1248 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1249 "ldr r4, [r13,#4*22] @ r4 = divXY \n"
1250 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1251 "ldr r8, [r13,#4*17] @ r8 = back4 \n"
1252 "18: @ \n"
1253 "mov r14,#0 @ r14= v = 0 \n"
1254 "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n"
1255 "19: @ \n"
1256 "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n"
1257 "20: @ \n"
1258 "ldrb r11,[r0],r6 @ r11= *src src += fwd \n"
1259 "subs r5, r5, #1<<16 @ xx-- \n"
1260 "add r14,r14,r11 @ v += r11 \n"
1261 "bgt 20b @ } \n"
1262 "sub r0, r0, r7 @ src -= back5 \n"
1263 "adds r5, r5, #1<<8 @ yy-- \n"
1264 "blt 19b @ } \n"
1265 "mul r14,r4, r14 @ r14= v *= divX \n"
1266 "mov r14,r14,LSR #16 @ r14= v >>= 16 \n"
1267 "strb r14,[r9], #1 @ *d++ = r14 \n"
1268 "sub r0, r0, r8 @ s -= back4 \n"
1269 "subs r5, r5, #1 @ n-- \n"
1270 "bgt 18b @ } \n"
1271 "21: @ \n"
1272 "ldmfd r13!,{r1,r4-r11,PC} @ pop, return to thumb \n"
1273 ENTER_THUMB
1274 );
1275 }
1276
1277 #endif
1278
1279 void
fz_subsample_pixmap(fz_context * ctx,fz_pixmap * tile,int factor)1280 fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor)
1281 {
1282 int dst_w, dst_h, w, h, fwd, fwd2, fwd3, back, back2, n, f;
1283 unsigned char *s, *d;
1284 #ifndef ARCH_ARM
1285 int x, y, xx, yy, nn;
1286 #endif
1287
1288 if (!tile)
1289 return;
1290
1291 assert(tile->stride >= tile->w * tile->n);
1292
1293 s = d = tile->samples;
1294 f = 1<<factor;
1295 w = tile->w;
1296 h = tile->h;
1297 n = tile->n;
1298 dst_w = (w + f-1)>>factor;
1299 dst_h = (h + f-1)>>factor;
1300 fwd = tile->stride;
1301 back = f*fwd-n;
1302 back2 = f*n-1;
1303 fwd2 = (f-1)*n;
1304 fwd3 = (f-1)*fwd + (int)tile->stride - w * n;
1305 factor *= 2;
1306 #ifdef ARCH_ARM
1307 {
1308 int strayX = w%f;
1309 int divX = (strayX ? 65536/(strayX*f) : 0);
1310 int fwd4 = (strayX-1) * n;
1311 int back4 = strayX*n-1;
1312 int strayY = h%f;
1313 int divY = (strayY ? 65536/(strayY*f) : 0);
1314 int back5 = fwd * strayY - n;
1315 int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0);
1316 fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back,
1317 back2, fwd2, divX, back4, fwd4, fwd3,
1318 divY, back5, divXY);
1319 }
1320 #else
1321 for (y = h - f; y >= 0; y -= f)
1322 {
1323 for (x = w - f; x >= 0; x -= f)
1324 {
1325 for (nn = n; nn > 0; nn--)
1326 {
1327 int v = 0;
1328 for (xx = f; xx > 0; xx--)
1329 {
1330 for (yy = f; yy > 0; yy--)
1331 {
1332 v += *s;
1333 s += fwd;
1334 }
1335 s -= back;
1336 }
1337 *d++ = v >> factor;
1338 s -= back2;
1339 }
1340 s += fwd2;
1341 }
1342 /* Do any strays */
1343 x += f;
1344 if (x > 0)
1345 {
1346 int div = x * f;
1347 int fwd4 = (x-1) * n;
1348 int back4 = x*n-1;
1349 for (nn = n; nn > 0; nn--)
1350 {
1351 int v = 0;
1352 for (xx = x; xx > 0; xx--)
1353 {
1354 for (yy = f; yy > 0; yy--)
1355 {
1356 v += *s;
1357 s += fwd;
1358 }
1359 s -= back;
1360 }
1361 *d++ = v / div;
1362 s -= back4;
1363 }
1364 s += fwd4;
1365 }
1366 s += fwd3;
1367 }
1368 /* Do any stray line */
1369 y += f;
1370 if (y > 0)
1371 {
1372 int div = y * f;
1373 int back5 = fwd * y - n;
1374 for (x = w - f; x >= 0; x -= f)
1375 {
1376 for (nn = n; nn > 0; nn--)
1377 {
1378 int v = 0;
1379 for (xx = f; xx > 0; xx--)
1380 {
1381 for (yy = y; yy > 0; yy--)
1382 {
1383 v += *s;
1384 s += fwd;
1385 }
1386 s -= back5;
1387 }
1388 *d++ = v / div;
1389 s -= back2;
1390 }
1391 s += fwd2;
1392 }
1393 /* Do any stray at the end of the stray line */
1394 x += f;
1395 if (x > 0)
1396 {
1397 int back4 = x * n - 1;
1398 div = x * y;
1399 for (nn = n; nn > 0; nn--)
1400 {
1401 int v = 0;
1402 for (xx = x; xx > 0; xx--)
1403 {
1404 for (yy = y; yy > 0; yy--)
1405 {
1406 v += *s;
1407 s += fwd;
1408 }
1409 s -= back5;
1410 }
1411 *d++ = v / div;
1412 s -= back4;
1413 }
1414 }
1415 }
1416 #endif
1417 tile->w = dst_w;
1418 tile->h = dst_h;
1419 tile->stride = dst_w * n;
1420 if (dst_h > INT_MAX / (dst_w * n))
1421 fz_throw(ctx, FZ_ERROR_MEMORY, "pixmap too large");
1422 tile->samples = fz_realloc(ctx, tile->samples, (size_t)dst_h * dst_w * n);
1423 }
1424
1425 void
fz_set_pixmap_resolution(fz_context * ctx,fz_pixmap * pix,int xres,int yres)1426 fz_set_pixmap_resolution(fz_context *ctx, fz_pixmap *pix, int xres, int yres)
1427 {
1428 pix->xres = xres;
1429 pix->yres = yres;
1430 }
1431
1432 /*
1433 Return the md5 digest for a pixmap
1434 */
1435 void
fz_md5_pixmap(fz_context * ctx,fz_pixmap * pix,unsigned char digest[16])1436 fz_md5_pixmap(fz_context *ctx, fz_pixmap *pix, unsigned char digest[16])
1437 {
1438 fz_md5 md5;
1439
1440 fz_md5_init(&md5);
1441 if (pix)
1442 {
1443 unsigned char *s = pix->samples;
1444 int h = pix->h;
1445 int ss = pix->stride;
1446 int len = pix->w * pix->n;
1447 while (h--)
1448 {
1449 fz_md5_update(&md5, s, len);
1450 s += ss;
1451 }
1452 }
1453 fz_md5_final(&md5, digest);
1454 }
1455
1456 #ifdef HAVE_VALGRIND
fz_valgrind_pixmap(const fz_pixmap * pix)1457 int fz_valgrind_pixmap(const fz_pixmap *pix)
1458 {
1459 int w, h, n, total;
1460 int ww, hh, nn;
1461 int stride;
1462 const unsigned char *p = pix->samples;
1463
1464 if (pix == NULL)
1465 return 0;
1466
1467 total = 0;
1468 ww = pix->w;
1469 hh = pix->h;
1470 nn = pix->n;
1471 stride = pix->stride - ww*nn;
1472 for (h = 0; h < hh; h++)
1473 {
1474 for (w = 0; w < ww; w++)
1475 for (n = 0; n < nn; n++)
1476 if (*p++) total ++;
1477 p += stride;
1478 }
1479 return total;
1480 }
1481 #endif /* HAVE_VALGRIND */
1482
1483 fz_pixmap *
fz_convert_indexed_pixmap_to_base(fz_context * ctx,const fz_pixmap * src)1484 fz_convert_indexed_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
1485 {
1486 fz_pixmap *dst;
1487 fz_colorspace *base;
1488 const unsigned char *s;
1489 unsigned char *d;
1490 int y, x, k, n, high;
1491 unsigned char *lookup;
1492 int s_line_inc, d_line_inc;
1493
1494 if (src->colorspace->type != FZ_COLORSPACE_INDEXED)
1495 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot convert non-indexed pixmap");
1496 if (src->n != 1 + src->alpha)
1497 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot convert indexed pixmap mis-matching components");
1498
1499 base = src->colorspace->u.indexed.base;
1500 high = src->colorspace->u.indexed.high;
1501 lookup = src->colorspace->u.indexed.lookup;
1502 n = base->n;
1503
1504 dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
1505 s = src->samples;
1506 d = dst->samples;
1507 s_line_inc = src->stride - src->w * src->n;
1508 d_line_inc = dst->stride - dst->w * dst->n;
1509
1510 if (src->alpha)
1511 {
1512 for (y = 0; y < src->h; y++)
1513 {
1514 for (x = 0; x < src->w; x++)
1515 {
1516 int v = *s++;
1517 int a = *s++;
1518 int aa = a + (a>>7);
1519 v = fz_mini(v, high);
1520 for (k = 0; k < n; k++)
1521 *d++ = (aa * lookup[v * n + k] + 128)>>8;
1522 *d++ = a;
1523 }
1524 s += s_line_inc;
1525 d += d_line_inc;
1526 }
1527 }
1528 else
1529 {
1530 for (y = 0; y < src->h; y++)
1531 {
1532 for (x = 0; x < src->w; x++)
1533 {
1534 int v = *s++;
1535 v = fz_mini(v, high);
1536 for (k = 0; k < n; k++)
1537 *d++ = lookup[v * n + k];
1538 }
1539 s += s_line_inc;
1540 d += d_line_inc;
1541 }
1542 }
1543
1544 if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1545 dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1546 else
1547 dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1548
1549 return dst;
1550 }
1551
1552 fz_pixmap *
fz_convert_separation_pixmap_to_base(fz_context * ctx,const fz_pixmap * src)1553 fz_convert_separation_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
1554 {
1555 fz_pixmap *dst;
1556 fz_colorspace *ss, *base;
1557 const unsigned char *s;
1558 unsigned char *d;
1559 int y, x, k, sn, bn, a;
1560 float src_v[FZ_MAX_COLORS];
1561 float base_v[FZ_MAX_COLORS];
1562 int s_line_inc, d_line_inc;
1563
1564 ss = src->colorspace;
1565
1566 if (ss->type != FZ_COLORSPACE_SEPARATION)
1567 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot expand non-separation pixmap");
1568 if (src->n != ss->n + src->alpha)
1569 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot expand separation pixmap mis-matching alpha channel");
1570
1571 base = ss->u.separation.base;
1572 dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
1573 fz_clear_pixmap(ctx, dst);
1574 fz_try(ctx)
1575 {
1576 s = src->samples;
1577 d = dst->samples;
1578 s_line_inc = src->stride - src->w * src->n;
1579 d_line_inc = dst->stride - dst->w * dst->n;
1580 sn = ss->n;
1581 bn = base->n;
1582
1583 if (base->type == FZ_COLORSPACE_LAB)
1584 {
1585 if (src->alpha)
1586 {
1587 for (y = 0; y < src->h; y++)
1588 {
1589 for (x = 0; x < src->w; x++)
1590 {
1591 for (k = 0; k < sn; ++k)
1592 src_v[k] = *s++ / 255.0f;
1593 a = *s++;
1594 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1595 *d++ = (base_v[0] / 100) * 255.0f;
1596 *d++ = base_v[1] + 128;
1597 *d++ = base_v[2] + 128;
1598 *d++ = a;
1599 }
1600 s += s_line_inc;
1601 d += d_line_inc;
1602 }
1603 }
1604 else
1605 {
1606 for (y = 0; y < src->h; y++)
1607 {
1608 for (x = 0; x < src->w; x++)
1609 {
1610 for (k = 0; k < sn; ++k)
1611 src_v[k] = *s++ / 255.0f;
1612 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1613 *d++ = (base_v[0] / 100) * 255.0f;
1614 *d++ = base_v[1] + 128;
1615 *d++ = base_v[2] + 128;
1616 }
1617 s += s_line_inc;
1618 d += d_line_inc;
1619 }
1620 }
1621 }
1622 else
1623 {
1624 if (src->alpha)
1625 {
1626 for (y = 0; y < src->h; y++)
1627 {
1628 for (x = 0; x < src->w; x++)
1629 {
1630 for (k = 0; k < sn; ++k)
1631 src_v[k] = *s++ / 255.0f;
1632 a = *s++;
1633 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1634 for (k = 0; k < bn; ++k)
1635 *d++ = base_v[k] * 255.0f;
1636 *d++ = a;
1637 }
1638 s += s_line_inc;
1639 d += d_line_inc;
1640 }
1641 }
1642 else
1643 {
1644 for (y = 0; y < src->h; y++)
1645 {
1646 for (x = 0; x < src->w; x++)
1647 {
1648 for (k = 0; k < sn; ++k)
1649 src_v[k] = *s++ / 255.0f;
1650 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1651 for (k = 0; k < bn; ++k)
1652 *d++ = base_v[k] * 255.0f;
1653 }
1654 s += s_line_inc;
1655 d += d_line_inc;
1656 }
1657 }
1658 }
1659
1660 if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1661 dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1662 else
1663 dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1664 }
1665 fz_catch(ctx)
1666 {
1667 fz_drop_pixmap(ctx, dst);
1668 fz_rethrow(ctx);
1669 }
1670
1671 return dst;
1672 }
1673