comparison mupdf-source/source/fitz/pixmap.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 // Copyright (C) 2004-2025 Artifex Software, Inc.
2 //
3 // This file is part of MuPDF.
4 //
5 // MuPDF is free software: you can redistribute it and/or modify it under the
6 // terms of the GNU Affero General Public License as published by the Free
7 // Software Foundation, either version 3 of the License, or (at your option)
8 // any later version.
9 //
10 // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU Affero General Public License
16 // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
17 //
18 // Alternative licensing terms are available from the licensor.
19 // For commercial licensing, see <https://www.artifex.com/> or contact
20 // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
21 // CA 94129, USA, for further information.
22
23 #include "mupdf/fitz.h"
24
25 #include "color-imp.h"
26 #include "pixmap-imp.h"
27
28 #include <assert.h>
29 #include <limits.h>
30 #include <string.h>
31 #include <math.h>
32 #include <float.h>
33
34 fz_pixmap *
35 fz_keep_pixmap(fz_context *ctx, fz_pixmap *pix)
36 {
37 return fz_keep_storable(ctx, &pix->storable);
38 }
39
40 void
41 fz_drop_pixmap(fz_context *ctx, fz_pixmap *pix)
42 {
43 fz_drop_storable(ctx, &pix->storable);
44 }
45
46 void
47 fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix_)
48 {
49 fz_pixmap *pix = (fz_pixmap *)pix_;
50
51 fz_drop_colorspace(ctx, pix->colorspace);
52 fz_drop_separations(ctx, pix->seps);
53 if (pix->flags & FZ_PIXMAP_FLAG_FREE_SAMPLES)
54 fz_free(ctx, pix->samples);
55 fz_drop_pixmap(ctx, pix->underlying);
56 fz_free(ctx, pix);
57 }
58
59 fz_pixmap *
60 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)
61 {
62 fz_pixmap *pix;
63 int s = fz_count_active_separations(ctx, seps);
64 int n;
65
66 if (w < 0 || h < 0)
67 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal dimensions for pixmap %d %d", w, h);
68
69 n = alpha + s + fz_colorspace_n(ctx, colorspace);
70 if (stride < n*w && stride > -n*w)
71 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal stride for pixmap (n=%d w=%d, stride=%d)", n, w, stride);
72 if (samples == NULL && stride < n*w)
73 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal -ve stride for pixmap without data");
74 if (n > FZ_MAX_COLORS)
75 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal number of colorants");
76
77 pix = fz_malloc_struct(ctx, fz_pixmap);
78 FZ_INIT_STORABLE(pix, 1, fz_drop_pixmap_imp);
79 pix->x = 0;
80 pix->y = 0;
81 pix->w = w;
82 pix->h = h;
83 pix->alpha = alpha = !!alpha;
84 pix->flags = FZ_PIXMAP_FLAG_INTERPOLATE;
85 pix->xres = 96;
86 pix->yres = 96;
87 pix->colorspace = NULL;
88 pix->n = n;
89 pix->s = s;
90 pix->seps = fz_keep_separations(ctx, seps);
91 pix->stride = stride;
92
93 if (colorspace)
94 {
95 pix->colorspace = fz_keep_colorspace(ctx, colorspace);
96 }
97 else
98 {
99 assert(alpha || s);
100 }
101
102 pix->samples = samples;
103 if (!samples && pix->h > 0 && pix->w > 0)
104 {
105 fz_try(ctx)
106 {
107 if ((size_t)pix->stride > SIZE_MAX / (size_t)pix->h)
108 fz_throw(ctx, FZ_ERROR_LIMIT, "Overly large image");
109 pix->samples = Memento_label(fz_malloc(ctx, pix->h * pix->stride), "pixmap_data");
110 }
111 fz_catch(ctx)
112 {
113 fz_drop_separations(ctx, pix->seps);
114 fz_drop_colorspace(ctx, pix->colorspace);
115 fz_free(ctx, pix);
116 fz_rethrow(ctx);
117 }
118 pix->flags |= FZ_PIXMAP_FLAG_FREE_SAMPLES;
119 }
120
121 return pix;
122 }
123
124 fz_pixmap *
125 fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha)
126 {
127 int stride;
128 int s = fz_count_active_separations(ctx, seps);
129 int n;
130 if (!colorspace && s == 0) alpha = 1;
131 n = fz_colorspace_n(ctx, colorspace) + s + alpha;
132 if (w > INT_MAX / n)
133 fz_throw(ctx, FZ_ERROR_LIMIT, "Overly wide image");
134 stride = n * w;
135 return fz_new_pixmap_with_data(ctx, colorspace, w, h, seps, alpha, stride, NULL);
136 }
137
138 fz_pixmap *
139 fz_new_pixmap_with_bbox(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha)
140 {
141 fz_pixmap *pixmap;
142 pixmap = fz_new_pixmap(ctx, colorspace, fz_irect_width(bbox), fz_irect_height(bbox), seps, alpha);
143 pixmap->x = bbox.x0;
144 pixmap->y = bbox.y0;
145 return pixmap;
146 }
147
148 fz_pixmap *
149 fz_new_pixmap_with_bbox_and_data(fz_context *ctx, fz_colorspace *colorspace, fz_irect bbox, fz_separations *seps, int alpha, unsigned char *samples)
150 {
151 int w = fz_irect_width(bbox);
152 int stride;
153 int s = fz_count_active_separations(ctx, seps);
154 fz_pixmap *pixmap;
155 if (!colorspace && s == 0) alpha = 1;
156 stride = (fz_colorspace_n(ctx, colorspace) + s + alpha) * w;
157 pixmap = fz_new_pixmap_with_data(ctx, colorspace, w, fz_irect_height(bbox), seps, alpha, stride, samples);
158 pixmap->x = bbox.x0;
159 pixmap->y = bbox.y0;
160 return pixmap;
161 }
162
163 fz_pixmap *fz_new_pixmap_from_pixmap(fz_context *ctx, fz_pixmap *pixmap, const fz_irect *rect)
164 {
165 fz_irect local_rect;
166 fz_pixmap *subpix;
167
168 if (!pixmap)
169 return NULL;
170
171 if (rect == NULL)
172 {
173 rect = &local_rect;
174 local_rect.x0 = pixmap->x;
175 local_rect.y0 = pixmap->y;
176 local_rect.x1 = pixmap->x + pixmap->w;
177 local_rect.y1 = pixmap->y + pixmap->h;
178 }
179 else if (rect->x0 < pixmap->x || rect->y0 < pixmap->y || rect->x1 > pixmap->x + pixmap->w || rect->y1 > pixmap->y + pixmap->h)
180 fz_throw(ctx, FZ_ERROR_ARGUMENT, "Pixmap region is not a subarea");
181
182 subpix = fz_malloc_struct(ctx, fz_pixmap);
183 *subpix = *pixmap;
184 subpix->storable.refs = 1;
185 subpix->x = rect->x0;
186 subpix->y = rect->y0;
187 subpix->w = fz_irect_width(*rect);
188 subpix->h = fz_irect_height(*rect);
189 subpix->samples += (rect->x0 - pixmap->x) + (rect->y0 - pixmap->y) * pixmap->stride;
190 subpix->underlying = fz_keep_pixmap(ctx, pixmap);
191 subpix->colorspace = fz_keep_colorspace(ctx, pixmap->colorspace);
192 subpix->seps = fz_keep_separations(ctx, pixmap->seps);
193 subpix->flags &= ~FZ_PIXMAP_FLAG_FREE_SAMPLES;
194
195 return subpix;
196 }
197
198 fz_pixmap *fz_clone_pixmap(fz_context *ctx, const fz_pixmap *old)
199 {
200 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);
201 memcpy(pix->samples, old->samples, pix->stride * pix->h);
202 return pix;
203 }
204
205 fz_irect
206 fz_pixmap_bbox(fz_context *ctx, const fz_pixmap *pix)
207 {
208 fz_irect bbox;
209 bbox.x0 = pix->x;
210 bbox.y0 = pix->y;
211 bbox.x1 = pix->x + pix->w;
212 bbox.y1 = pix->y + pix->h;
213 return bbox;
214 }
215
216 fz_irect
217 fz_pixmap_bbox_no_ctx(const fz_pixmap *pix)
218 {
219 fz_irect bbox;
220 bbox.x0 = pix->x;
221 bbox.y0 = pix->y;
222 bbox.x1 = pix->x + pix->w;
223 bbox.y1 = pix->y + pix->h;
224 return bbox;
225 }
226
227 fz_colorspace *
228 fz_pixmap_colorspace(fz_context *ctx, const fz_pixmap *pix)
229 {
230 if (!pix)
231 return NULL;
232 return pix->colorspace;
233 }
234
235 int
236 fz_pixmap_x(fz_context *ctx, const fz_pixmap *pix)
237 {
238 return pix->x;
239 }
240
241 int
242 fz_pixmap_y(fz_context *ctx, const fz_pixmap *pix)
243 {
244 return pix->y;
245 }
246
247 int
248 fz_pixmap_width(fz_context *ctx, const fz_pixmap *pix)
249 {
250 return pix->w;
251 }
252
253 int
254 fz_pixmap_height(fz_context *ctx, const fz_pixmap *pix)
255 {
256 return pix->h;
257 }
258
259 int
260 fz_pixmap_components(fz_context *ctx, const fz_pixmap *pix)
261 {
262 return pix->n;
263 }
264
265 int
266 fz_pixmap_colorants(fz_context *ctx, const fz_pixmap *pix)
267 {
268 return pix->n - pix->alpha - pix->s;
269 }
270
271 int
272 fz_pixmap_spots(fz_context *ctx, const fz_pixmap *pix)
273 {
274 return pix->s;
275 }
276
277 int
278 fz_pixmap_alpha(fz_context *ctx, const fz_pixmap *pix)
279 {
280 return pix->alpha;
281 }
282
283 int
284 fz_pixmap_stride(fz_context *ctx, const fz_pixmap *pix)
285 {
286 return pix->stride;
287 }
288
289 unsigned char *
290 fz_pixmap_samples(fz_context *ctx, const fz_pixmap *pix)
291 {
292 if (!pix)
293 return NULL;
294 return pix->samples;
295 }
296
297 /*
298 The slowest routine in most CMYK rendering profiles.
299 We therefore spend some effort to improve it. Rather than
300 writing bytes, we write uint32_t's.
301 */
302 #ifdef ARCH_ARM
303 static void
304 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value)
305 __attribute__((naked));
306
307 static void
308 clear_cmyka_bitmap_ARM(uint32_t *samples, int c, int value)
309 {
310 asm volatile(
311 ENTER_ARM
312 "stmfd r13!,{r4-r6,r14} \n"
313 "@ r0 = samples \n"
314 "@ r1 = c \n"
315 "@ r2 = value \n"
316 "mov r3, #255 \n"
317 "mov r12,#0 @ r12= 0 \n"
318 "subs r1, r1, #3 \n"
319 "ble 2f \n"
320 "str r12,[r13,#-20]! \n"
321 "str r12,[r13,#4] \n"
322 "str r12,[r13,#8] \n"
323 "str r12,[r13,#12] \n"
324 "str r12,[r13,#16] \n"
325 "strb r2, [r13,#3] \n"
326 "strb r3, [r13,#4] \n"
327 "strb r2, [r13,#8] \n"
328 "strb r3, [r13,#9] \n"
329 "strb r2, [r13,#13] \n"
330 "strb r3, [r13,#14] \n"
331 "strb r2, [r13,#18] \n"
332 "strb r3, [r13,#19] \n"
333 "ldmfd r13!,{r4,r5,r6,r12,r14} \n"
334 "1: \n"
335 "stmia r0!,{r4,r5,r6,r12,r14} \n"
336 "subs r1, r1, #4 \n"
337 "bgt 1b \n"
338 "2: \n"
339 "adds r1, r1, #3 \n"
340 "ble 4f \n"
341 "3: \n"
342 "strb r12,[r0], #1 \n"
343 "strb r12,[r0], #1 \n"
344 "strb r12,[r0], #1 \n"
345 "strb r2, [r0], #1 \n"
346 "strb r3, [r0], #1 \n"
347 "subs r1, r1, #1 \n"
348 "bgt 3b \n"
349 "4: \n"
350 "ldmfd r13!,{r4-r6,PC} \n"
351 ENTER_THUMB
352 );
353 }
354 #endif
355
356 static void
357 clear_cmyk_bitmap(unsigned char *samples, int w, int h, int spots, int stride, int value, int alpha)
358 {
359 uint32_t *s = (uint32_t *)(void *)samples;
360 uint8_t *t;
361
362 if (w < 0 || h < 0)
363 return;
364
365 if (spots)
366 {
367 int x, i;
368 spots += 4;
369 stride -= w * (spots + alpha);
370 for (; h > 0; h--)
371 {
372 for (x = w; x > 0; x--)
373 {
374 for (i = spots; i > 0; i--)
375 *samples++ = value;
376 if (alpha)
377 *samples++ = 255;
378 }
379 samples += stride;
380 }
381 return;
382 }
383
384 if (alpha)
385 {
386 int c = w;
387 stride -= w*5;
388 if (stride == 0)
389 {
390 #ifdef ARCH_ARM
391 clear_cmyka_bitmap_ARM(s, c, alpha);
392 return;
393 #else
394 /* We can do it all fast (except for maybe a few stragglers) */
395 union
396 {
397 uint8_t bytes[20];
398 uint32_t words[5];
399 } d;
400
401 c *= h;
402 h = 1;
403
404 d.words[0] = 0;
405 d.words[1] = 0;
406 d.words[2] = 0;
407 d.words[3] = 0;
408 d.words[4] = 0;
409 d.bytes[3] = value;
410 d.bytes[4] = 255;
411 d.bytes[8] = value;
412 d.bytes[9] = 255;
413 d.bytes[13] = value;
414 d.bytes[14] = 255;
415 d.bytes[18] = value;
416 d.bytes[19] = 255;
417
418 c -= 3;
419 {
420 const uint32_t a0 = d.words[0];
421 const uint32_t a1 = d.words[1];
422 const uint32_t a2 = d.words[2];
423 const uint32_t a3 = d.words[3];
424 const uint32_t a4 = d.words[4];
425 while (c > 0)
426 {
427 *s++ = a0;
428 *s++ = a1;
429 *s++ = a2;
430 *s++ = a3;
431 *s++ = a4;
432 c -= 4;
433 }
434 }
435 c += 3;
436 #endif
437 }
438 t = (unsigned char *)s;
439 w = c;
440 while (h--)
441 {
442 c = w;
443 while (c > 0)
444 {
445 *t++ = 0;
446 *t++ = 0;
447 *t++ = 0;
448 *t++ = value;
449 *t++ = 255;
450 c--;
451 }
452 t += stride;
453 }
454 }
455 else
456 {
457 stride -= w*4;
458 if ((stride & 3) == 0)
459 {
460 size_t W = w;
461 if (stride == 0)
462 {
463 W *= h;
464 h = 1;
465 }
466 W *= 4;
467 if (value == 0)
468 {
469 while (h--)
470 {
471 memset(s, 0, W);
472 s += (stride>>2);
473 }
474 }
475 else
476 {
477 /* We can do it all fast */
478 union
479 {
480 uint8_t bytes[4];
481 uint32_t word;
482 } d;
483
484 d.word = 0;
485 d.bytes[3] = value;
486 {
487 const uint32_t a0 = d.word;
488 while (h--)
489 {
490 size_t WW = W >> 2;
491 while (WW--)
492 {
493 *s++ = a0;
494 }
495 s += (stride>>2);
496 }
497 }
498 }
499 }
500 else
501 {
502 t = (unsigned char *)s;
503 while (h--)
504 {
505 int c = w;
506 while (c > 0)
507 {
508 *t++ = 0;
509 *t++ = 0;
510 *t++ = 0;
511 *t++ = value;
512 c--;
513 }
514 t += stride;
515 }
516 }
517 }
518 }
519
520 void
521 fz_clear_pixmap(fz_context *ctx, fz_pixmap *pix)
522 {
523 ptrdiff_t stride = pix->w * (ptrdiff_t)pix->n;
524 int h = pix->h;
525 unsigned char *s = pix->samples;
526 if (stride == pix->stride)
527 {
528 stride *= h;
529 h = 1;
530 }
531 if (pix->alpha || fz_colorspace_is_subtractive(ctx, pix->colorspace))
532 {
533 while (h--)
534 {
535 memset(s, 0, stride);
536 s += pix->stride;
537 }
538 }
539 else if (pix->s == 0)
540 {
541 while (h--)
542 {
543 memset(s, 0xff, stride);
544 s += pix->stride;
545 }
546 }
547 else
548 {
549 /* Horrible, slow case: additive with spots */
550 size_t w = stride/pix->n;
551 int spots = pix->s;
552 int colorants = pix->n - spots; /* We know there is no alpha */
553 while (h--)
554 {
555 size_t w2 = w;
556 while (w2--)
557 {
558 int i = colorants;
559 do
560 {
561 *s++ = 0xff;
562 i--;
563 }
564 while (i != 0);
565
566 i = spots;
567 do
568 {
569 *s++ = 0;
570 i--;
571 }
572 while (i != 0);
573 }
574 }
575 }
576 }
577
578 void
579 fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value)
580 {
581 unsigned char *s;
582 int w, h, n;
583 ptrdiff_t stride, len;
584 int alpha = pix->alpha;
585
586 w = pix->w;
587 h = pix->h;
588 if (w < 0 || h < 0)
589 return;
590
591 /* CMYK needs special handling (and potentially any other subtractive colorspaces) */
592 if (fz_colorspace_n(ctx, pix->colorspace) == 4)
593 {
594 clear_cmyk_bitmap(pix->samples, w, h, pix->s, pix->stride, 255-value, pix->alpha);
595 return;
596 }
597
598 n = pix->n;
599 stride = pix->stride;
600 len = (ptrdiff_t)w * n;
601
602 s = pix->samples;
603 if (value == 255 || !alpha)
604 {
605 if (stride == len)
606 {
607 len *= h;
608 h = 1;
609 }
610 while (h--)
611 {
612 memset(s, value, len);
613 s += stride;
614 }
615 }
616 else
617 {
618 int k, x, y;
619 stride -= len;
620 for (y = 0; y < pix->h; y++)
621 {
622 for (x = 0; x < pix->w; x++)
623 {
624 for (k = 0; k < pix->n - 1; k++)
625 *s++ = value;
626 if (alpha)
627 *s++ = 255;
628 }
629 s += stride;
630 }
631 }
632 }
633
634 void
635 fz_fill_pixmap_with_color(fz_context *ctx, fz_pixmap *pix, fz_colorspace *colorspace, float *color, fz_color_params color_params)
636 {
637 float colorfv[FZ_MAX_COLORS];
638 unsigned char colorbv[FZ_MAX_COLORS];
639 int i, n, a, s, x, y, w, h;
640
641 n = fz_colorspace_n(ctx, pix->colorspace);
642 a = pix->alpha;
643 s = pix->s;
644 fz_convert_color(ctx, colorspace, color, pix->colorspace, colorfv, NULL, color_params);
645 for (i = 0; i < n; ++i)
646 colorbv[i] = colorfv[i] * 255;
647
648 w = pix->w;
649 h = pix->h;
650 for (y = 0; y < h; ++y)
651 {
652 unsigned char *p = pix->samples + y * pix->stride;
653 for (x = 0; x < w; ++x)
654 {
655 for (i = 0; i < n; ++i)
656 *p++ = colorbv[i];
657 for (i = 0; i < s; ++i)
658 *p++ = 0;
659 if (a)
660 *p++ = 255;
661 }
662 }
663 }
664
665 void
666 fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_irect b, const fz_default_colorspaces *default_cs)
667 {
668 unsigned char *srcp;
669 unsigned char *destp;
670 unsigned int y, w;
671 size_t destspan, srcspan;
672
673 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
674 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, src));
675 if (fz_is_empty_irect(b))
676 return;
677 w = (unsigned int)(b.x1 - b.x0);
678 y = (unsigned int)(b.y1 - b.y0);
679
680 srcspan = src->stride;
681 srcp = src->samples + srcspan * (b.y0 - src->y) + (b.x0 - src->x) * (size_t)src->n;
682 destspan = dest->stride;
683 destp = dest->samples + destspan * (b.y0 - dest->y) + (b.x0 - dest->x) * (size_t)dest->n;
684
685 if (src->n == dest->n)
686 {
687 w *= src->n;
688 do
689 {
690 memcpy(destp, srcp, w);
691 srcp += srcspan;
692 destp += destspan;
693 }
694 while (--y);
695 }
696 else
697 {
698 fz_pixmap fake_src = *src;
699 fake_src.x = b.x0;
700 fake_src.y = b.y0;
701 fake_src.w = w;
702 fake_src.h = y;
703 fake_src.samples = srcp;
704 fz_convert_pixmap_samples(ctx, &fake_src, dest, NULL, default_cs, fz_default_color_params, 0);
705 }
706 }
707
708 void
709 fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_irect b)
710 {
711 unsigned char *destp;
712 int x, y, w, k;
713 size_t destspan;
714
715 b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
716 w = b.x1 - b.x0;
717 y = b.y1 - b.y0;
718 if (w <= 0 || y <= 0)
719 return;
720
721 destspan = dest->stride;
722 destp = dest->samples + destspan * (b.y0 - dest->y) + (b.x0 - dest->x) * (size_t)dest->n;
723
724 /* CMYK needs special handling (and potentially any other subtractive colorspaces) */
725 if (fz_colorspace_n(ctx, dest->colorspace) == 4)
726 {
727 value = 255 - value;
728 do
729 {
730 unsigned char *s = destp;
731 for (x = 0; x < w; x++)
732 {
733 *s++ = 0;
734 *s++ = 0;
735 *s++ = 0;
736 *s++ = value;
737 *s++ = 255;
738 }
739 destp += destspan;
740 }
741 while (--y);
742 return;
743 }
744
745 if (value == 255)
746 {
747 do
748 {
749 memset(destp, 255, w * (size_t)dest->n);
750 destp += destspan;
751 }
752 while (--y);
753 }
754 else
755 {
756 do
757 {
758 unsigned char *s = destp;
759 for (x = 0; x < w; x++)
760 {
761 for (k = 0; k < dest->n - 1; k++)
762 *s++ = value;
763 *s++ = 255;
764 }
765 destp += destspan;
766 }
767 while (--y);
768 }
769 }
770
771 void
772 fz_premultiply_pixmap(fz_context *ctx, fz_pixmap *pix)
773 {
774 unsigned char *s = pix->samples;
775 unsigned char a;
776 int k, x, y;
777 size_t stride = pix->stride - pix->w * (size_t)pix->n;
778
779 if (!pix->alpha)
780 return;
781
782 for (y = 0; y < pix->h; y++)
783 {
784 for (x = 0; x < pix->w; x++)
785 {
786 a = s[pix->n - 1];
787 for (k = 0; k < pix->n - 1; k++)
788 s[k] = fz_mul255(s[k], a);
789 s += pix->n;
790 }
791 s += stride;
792 }
793 }
794
795 fz_pixmap *
796 fz_alpha_from_gray(fz_context *ctx, fz_pixmap *gray)
797 {
798 fz_pixmap *alpha;
799 unsigned char *sp, *dp;
800 int w, h, sstride, dstride;
801
802 assert(gray->n == 1);
803
804 alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray), 0, 1);
805 dp = alpha->samples;
806 dstride = alpha->stride;
807 sp = gray->samples;
808 sstride = gray->stride;
809
810 h = gray->h;
811 w = gray->w;
812 while (h--)
813 {
814 memcpy(dp, sp, w);
815 sp += sstride;
816 dp += dstride;
817 }
818
819 return alpha;
820 }
821
822 void
823 fz_tint_pixmap(fz_context *ctx, fz_pixmap *pix, int black, int white)
824 {
825 unsigned char *s = pix->samples;
826 int n = pix->n;
827 int x, y, save;
828 int rb = (black>>16)&255;
829 int gb = (black>>8)&255;
830 int bb = (black)&255;
831 int rw = (white>>16)&255;
832 int gw = (white>>8)&255;
833 int bw = (white)&255;
834 int rm = (rw - rb);
835 int gm = (gw - gb);
836 int bm = (bw - bb);
837
838 switch (fz_colorspace_type(ctx, pix->colorspace))
839 {
840 case FZ_COLORSPACE_GRAY:
841 gw = (rw + gw + bw) / 3;
842 gb = (rb + gb + bb) / 3;
843 gm = gw - gb;
844 for (y = 0; y < pix->h; y++)
845 {
846 for (x = 0; x < pix->w; x++)
847 {
848 *s = gb + fz_mul255(*s, gm);
849 s += n;
850 }
851 s += pix->stride - pix->w * n;
852 }
853 break;
854
855 case FZ_COLORSPACE_BGR:
856 save = rm; rm = bm; bm = save;
857 save = rb; rb = bb; bb = save;
858 /* fall through */
859 case FZ_COLORSPACE_RGB:
860 for (y = 0; y < pix->h; y++)
861 {
862 for (x = 0; x < pix->w; x++)
863 {
864 s[0] = rb + fz_mul255(s[0], rm);
865 s[1] = gb + fz_mul255(s[1], gm);
866 s[2] = bb + fz_mul255(s[2], bm);
867 s += n;
868 }
869 s += pix->stride - pix->w * n;
870 }
871 break;
872
873 default:
874 fz_throw(ctx, FZ_ERROR_ARGUMENT, "can only tint RGB, BGR and Gray pixmaps");
875 break;
876 }
877 }
878
879 /* Invert luminance in RGB/BGR pixmap, but keep the colors as is. */
880 static inline void invert_luminance(int type, unsigned char *s)
881 {
882 int r, g, b, y;
883
884 /* Convert to YUV */
885 if (type == FZ_COLORSPACE_RGB)
886 {
887 r = s[0];
888 g = s[1];
889 b = s[2];
890 }
891 else
892 {
893 r = s[2];
894 g = s[1];
895 b = s[0];
896 }
897
898 y = (39336 * r + 76884 * g + 14900 * b + 32768)>>16;
899 y = 259-y;
900 r += y;
901 g += y;
902 b += y;
903
904 if (type == FZ_COLORSPACE_RGB)
905 {
906 s[0] = r > 255 ? 255 : r < 0 ? 0 : r;
907 s[1] = g > 255 ? 255 : g < 0 ? 0 : g;
908 s[2] = b > 255 ? 255 : b < 0 ? 0 : b;
909 }
910 else
911 {
912 s[2] = r > 255 ? 255 : r < 0 ? 0 : r;
913 s[1] = g > 255 ? 255 : g < 0 ? 0 : g;
914 s[0] = b > 255 ? 255 : b < 0 ? 0 : b;
915 }
916 }
917
918 void
919 fz_invert_pixmap_luminance(fz_context *ctx, fz_pixmap *pix)
920 {
921 unsigned char *s = pix->samples;
922 int x, y, n = pix->n;
923 int type = pix->colorspace ? pix->colorspace->type : FZ_COLORSPACE_NONE;
924
925 if (type == FZ_COLORSPACE_GRAY)
926 {
927 fz_invert_pixmap(ctx, pix);
928 }
929 else if (type == FZ_COLORSPACE_RGB || type == FZ_COLORSPACE_BGR)
930 {
931 for (y = 0; y < pix->h; y++)
932 {
933 for (x = 0; x < pix->w; x++)
934 {
935 invert_luminance(type, s);
936 s += n;
937 }
938 s += pix->stride - pix->w * n;
939 }
940 }
941 else
942 {
943 fz_throw(ctx, FZ_ERROR_ARGUMENT, "can only invert luminance of Gray and RGB pixmaps");
944 }
945 }
946
947 void
948 fz_invert_pixmap(fz_context *ctx, fz_pixmap *pix)
949 {
950 fz_irect rect = { pix->x, pix->y, pix->x + pix->w, pix->y + pix->h };
951 fz_invert_pixmap_rect(ctx, pix, rect);
952 }
953
954 void
955 fz_invert_pixmap_alpha(fz_context *ctx, fz_pixmap *pix)
956 {
957 unsigned char *s = pix->samples;
958 int x, y;
959 int n1 = pix->n - pix->alpha;
960 int n = pix->n;
961
962 if (!pix->alpha)
963 return;
964
965 for (y = 0; y < pix->h; y++)
966 {
967 s += n1;
968 for (x = 0; x < pix->w; x++)
969 {
970 *s = 255 - *s;
971 s += n;
972 }
973 s += pix->stride - pix->w * n;
974 }
975 }
976
977 void fz_invert_pixmap_rect(fz_context *ctx, fz_pixmap *pix, fz_irect rect)
978 {
979 int x0 = fz_clampi(rect.x0 - pix->x, 0, pix->w);
980 int x1 = fz_clampi(rect.x1 - pix->x, 0, pix->w);
981 int y0 = fz_clampi(rect.y0 - pix->y, 0, pix->h);
982 int y1 = fz_clampi(rect.y1 - pix->y, 0, pix->h);
983
984 int x, y;
985 int n = pix->n;
986 int s = pix->s;
987 int cmyk = (pix->colorspace && pix->colorspace->type == FZ_COLORSPACE_CMYK);
988
989 if (cmyk)
990 {
991 /* For cmyk, we're storing: (a.c, a.m, a.y, a.k, a)
992 * So, a.r = a - a.c - a.k
993 * a.g = a - a.m - a.k
994 * a.b = a - a.y - a.k
995 * Invert that:
996 * a.R = a.c + a.k
997 * a.G = a.m + a.k
998 * a.B = a.y + a.k
999 * Convert that back to cmy
1000 * a.C = a - a.c - a.k;
1001 * a.M = a - a.m - a.k;
1002 * a.Y = a - a.y - a.k;
1003 * Extract K:
1004 * a.K' = min(a.C, a.M, a.Y)
1005 * = a - a.k - max(a.c, a.m, a.y)
1006 * a.C' = a.C - a.K' = a - a.c - a.k - (a - a.k - max(a.c, a.m, a.y)) = max(a.c, a.m, a.y) - a.c
1007 * a.M' = a.M - a.K' = a - a.m - a.k - (a - a.k - max(a.c, a.m, a.y)) = max(a.c, a.m, a.y) - a.m
1008 * a.Y' = a.Y - a.K' = a - a.y - a.k - (a - a.k - max(a.c, a.m, a.y)) = max(a.c, a.m, a.y) - a.y
1009 * */
1010 if (pix->alpha)
1011 {
1012 int n1 = pix->n - pix->alpha - s;
1013 for (y = y0; y < y1; y++)
1014 {
1015 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n));
1016 for (x = x0; x < x1; x++)
1017 {
1018 int ac = d[0];
1019 int am = d[1];
1020 int ay = d[2];
1021 int ak = d[3];
1022 int a = d[n1];
1023 int mx = fz_maxi(fz_maxi(ac, am), ay);
1024 d[0] = mx-ac;
1025 d[1] = mx-am;
1026 d[2] = mx-ay;
1027 ak = a - ak - mx;
1028 if (ak < 0)
1029 ak = 0;
1030 d[3] = ak;
1031 d += n;
1032 }
1033 }
1034 }
1035 else
1036 {
1037 for (y = y0; y < y1; y++)
1038 {
1039 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n));
1040 for (x = x0; x < x1; x++)
1041 {
1042 int c = d[0];
1043 int m = d[1];
1044 int ye = d[2];
1045 int k = d[3];
1046 int mx = fz_maxi(fz_maxi(c, m), ye);
1047 d[0] = mx-c;
1048 d[1] = mx-m;
1049 d[2] = mx-ye;
1050 k = 255 - k - mx;
1051 if (k < 0)
1052 k = 0;
1053 d[3] = k;
1054 d += n;
1055 }
1056 }
1057 }
1058 }
1059 else if (pix->alpha)
1060 {
1061 int n1 = pix->n - pix->alpha - s;
1062 for (y = y0; y < y1; y++)
1063 {
1064 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n));
1065 for (x = x0; x < x1; x++)
1066 {
1067 int a = d[n1];
1068 int k;
1069 for (k = 0; k < n1; k++)
1070 d[k] = a - d[k];
1071 d += n;
1072 }
1073 }
1074 }
1075 else if (s)
1076 {
1077 int n1 = pix->n - s;
1078 for (y = y0; y < y1; y++)
1079 {
1080 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n));
1081 for (x = x0; x < x1; x++)
1082 {
1083 int k;
1084 for (k = 0; k < n1; k++)
1085 d[k] = 255 - d[k];
1086 d += n;
1087 }
1088 }
1089 }
1090 else
1091 {
1092 for (y = y0; y < y1; y++)
1093 {
1094 unsigned char *d = pix->samples + ((y * (size_t)pix->stride) + (x0 * (size_t)pix->n));
1095 for (x = x0; x < x1; x++)
1096 {
1097 int k;
1098 for (k = 0; k < n; k++)
1099 d[k] = 255 - d[k];
1100 d += n;
1101 }
1102 }
1103 }
1104 }
1105
1106 void
1107 fz_invert_pixmap_raw(fz_context *ctx, fz_pixmap *pix)
1108 {
1109 unsigned char *s = pix->samples;
1110 int k, x, y;
1111 int n1 = pix->n - pix->alpha;
1112 int n = pix->n;
1113
1114 for (y = 0; y < pix->h; y++)
1115 {
1116 for (x = 0; x < pix->w; x++)
1117 {
1118 for (k = 0; k < n1; k++)
1119 s[k] = 255 - s[k];
1120 s += n;
1121 }
1122 s += pix->stride - pix->w * n;
1123 }
1124 }
1125
1126 void
1127 fz_gamma_pixmap(fz_context *ctx, fz_pixmap *pix, float gamma)
1128 {
1129 unsigned char gamma_map[256];
1130 unsigned char *s = pix->samples;
1131 int n1 = pix->n - pix->alpha;
1132 int n = pix->n;
1133 int k, x, y;
1134
1135 for (k = 0; k < 256; k++)
1136 gamma_map[k] = powf(k / 255.0f, gamma) * 255;
1137
1138 for (y = 0; y < pix->h; y++)
1139 {
1140 for (x = 0; x < pix->w; x++)
1141 {
1142 for (k = 0; k < n1; k++)
1143 s[k] = gamma_map[s[k]];
1144 s += n;
1145 }
1146 s += pix->stride - pix->w * n;
1147 }
1148 }
1149
1150 size_t
1151 fz_pixmap_size(fz_context *ctx, fz_pixmap * pix)
1152 {
1153 if (pix == NULL)
1154 return 0;
1155 return sizeof(*pix) + (size_t)pix->n * pix->w * pix->h;
1156 }
1157
1158 fz_pixmap *
1159 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)
1160 {
1161 fz_pixmap *cvt;
1162
1163 if (!ds && !keep_alpha)
1164 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot both throw away and keep alpha");
1165
1166 cvt = fz_new_pixmap(ctx, ds, pix->w, pix->h, pix->seps, keep_alpha && pix->alpha);
1167
1168 cvt->xres = pix->xres;
1169 cvt->yres = pix->yres;
1170 cvt->x = pix->x;
1171 cvt->y = pix->y;
1172 if (pix->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1173 cvt->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1174 else
1175 cvt->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1176
1177 fz_try(ctx)
1178 {
1179 fz_convert_pixmap_samples(ctx, pix, cvt, prf, default_cs, color_params, 1);
1180 }
1181 fz_catch(ctx)
1182 {
1183 fz_drop_pixmap(ctx, cvt);
1184 fz_rethrow(ctx);
1185 }
1186
1187 return cvt;
1188 }
1189
1190 fz_pixmap *
1191 fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1192 {
1193 fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1194 int stride = pixmap->stride;
1195 unsigned char *s = pixmap->samples;
1196 pixmap->x = x;
1197 pixmap->y = y;
1198
1199 for (y = 0; y < h; y++)
1200 {
1201 memcpy(s, sp + y * span, w);
1202 s += stride;
1203 }
1204
1205 return pixmap;
1206 }
1207
1208 fz_pixmap *
1209 fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1210 {
1211 fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1212 int stride = pixmap->stride - pixmap->w;
1213 pixmap->x = x;
1214 pixmap->y = y;
1215
1216 for (y = 0; y < h; y++)
1217 {
1218 unsigned char *out = pixmap->samples + y * w;
1219 unsigned char *in = sp + y * span;
1220 unsigned char bit = 0x80;
1221 int ww = w;
1222 while (ww--)
1223 {
1224 *out++ = (*in & bit) ? 255 : 0;
1225 bit >>= 1;
1226 if (bit == 0)
1227 bit = 0x80, in++;
1228 }
1229 out += stride;
1230 }
1231
1232 return pixmap;
1233 }
1234
1235 static float
1236 calc_percentile(int *hist, float thr, float scale, float minval, float maxval)
1237 {
1238 float prct;
1239 int k = 0, count = 0;
1240
1241 while (count < thr)
1242 count += hist[k++];
1243
1244 if (k <= 0)
1245 prct = k;
1246 else
1247 {
1248 float c0 = count - thr;
1249 float c1 = thr - (count - hist[k - 1]);
1250 prct = (c1 * k + c0 * (k - 1)) / (c0 + c1);
1251 }
1252
1253 prct /= scale;
1254 prct += minval;
1255 return fz_clamp(prct, minval, maxval);
1256 }
1257
1258 static void
1259 calc_percentiles(fz_context *ctx, float *samples, size_t nsamples, float *minprct, float *maxprct)
1260 {
1261 float minval, maxval, scale;
1262 size_t size, k;
1263 int *hist;
1264
1265 minval = maxval = samples[0];
1266 for (k = 1; k < nsamples; k++)
1267 {
1268 minval = fz_min(minval, samples[k]);
1269 maxval = fz_max(maxval, samples[k]);
1270 }
1271
1272 if (minval - maxval == 0)
1273 {
1274 *minprct = *maxprct = minval;
1275 return;
1276 }
1277
1278 size = fz_minz(65535, nsamples);
1279 scale = (size - 1) / (maxval - minval);
1280
1281 hist = fz_calloc(ctx, size, sizeof(int));
1282
1283 *minprct = 0;
1284 *maxprct = 0;
1285
1286 for (k = 0; k < nsamples; k++)
1287 hist[(uint16_t) (scale * (samples[k] - minval))]++;
1288
1289 *minprct = calc_percentile(hist, 0.01f * nsamples, scale, minval, maxval);
1290 *maxprct = calc_percentile(hist, 0.99f * nsamples, scale, minval, maxval);
1291
1292 fz_free(ctx, hist);
1293 }
1294
1295 /* Tone mapping according to "Consistent Tone Reproduction" by Min H. Kim and Jan Kautz. */
1296 fz_pixmap *
1297 fz_new_pixmap_from_float_data(fz_context *ctx, fz_colorspace *cs, int w, int h, float *samples)
1298 {
1299 fz_pixmap *pixmap = NULL;
1300 unsigned char *dp;
1301 float *sample;
1302 float minsample, maxsample, mu;
1303 float k1, d0, sigma, sigmasq2;
1304 float minprct, maxprct, range;
1305 size_t k, nsamples;
1306 int y;
1307 #define KIMKAUTZC1 (3.0f)
1308 #define KIMKAUTZC2 (0.5f)
1309 #define MAXLD (logf(300.0f))
1310 #define MINLD (logf(0.3f))
1311
1312 pixmap = fz_new_pixmap(ctx, cs, w, h, NULL, 0);
1313 if (w > 0 && h > 0 && pixmap->n > 0)
1314 {
1315 fz_try(ctx)
1316 {
1317 nsamples = (size_t) w * h;
1318 if ((size_t) pixmap->n > SIZE_MAX / nsamples)
1319 fz_throw(ctx, FZ_ERROR_LIMIT, "too many floating point samples to convert to pixmap");
1320 nsamples *= pixmap->n;
1321
1322 mu = 0;
1323 minsample = FLT_MAX;
1324 maxsample = -FLT_MAX;
1325
1326 for (k = 0; k < nsamples; k++)
1327 {
1328 float v = logf(samples[k] == 0 ? FLT_MIN : samples[k]);
1329 mu += v;
1330 minsample = fz_min(minsample, v);
1331 maxsample = fz_max(maxsample, v);
1332 }
1333
1334 mu /= nsamples;
1335 d0 = maxsample - minsample;
1336 k1 = (MAXLD - MINLD) / d0;
1337 sigma = d0 / KIMKAUTZC1;
1338 sigmasq2 = sigma * sigma * 2;
1339
1340 for (k = 0; k < nsamples; k++)
1341 {
1342 float samplemu = samples[k] - mu;
1343 float samplemu2 = samplemu * samplemu;
1344 float fw = expf(-samplemu2 / sigmasq2);
1345 float k2 = (1 - k1) * fw + k1;
1346 samples[k] = expf(KIMKAUTZC2 * k2 * (logf(samples[k] == 0 ? FLT_MIN : samples[k]) - mu) + mu);
1347 }
1348
1349 calc_percentiles(ctx, samples, nsamples, &minprct, &maxprct);
1350 range = maxprct - minprct;
1351
1352 dp = pixmap->samples + pixmap->stride * (h - 1);
1353 sample = samples;
1354
1355 for (y = 0; y < h; y++)
1356 {
1357 unsigned char *dpp = dp;
1358
1359 for (k = 0; k < (size_t) w * pixmap->n; k++)
1360 *dpp++ = 255.0f * (fz_clamp(*sample++, minprct, maxprct) - minprct) / range;
1361
1362 dp -= pixmap->stride;
1363 }
1364 }
1365 fz_catch(ctx)
1366 {
1367 fz_drop_pixmap(ctx, pixmap);
1368 fz_rethrow(ctx);
1369 }
1370 }
1371
1372 return pixmap;
1373 }
1374
1375 fz_pixmap *
1376 fz_new_pixmap_from_alpha_channel(fz_context *ctx, fz_pixmap *src)
1377 {
1378 fz_pixmap *dst;
1379 int w, h, n, x;
1380 unsigned char *sp, *dp;
1381
1382 if (!src->alpha)
1383 return NULL;
1384
1385 dst = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, src), NULL, 1);
1386 w = src->w;
1387 h = src->h;
1388 n = src->n;
1389 sp = src->samples + n - 1;
1390 dp = dst->samples;
1391
1392 while (h--)
1393 {
1394 unsigned char *s = sp;
1395 unsigned char *d = dp;
1396 for (x = 0; x < w; ++x)
1397 {
1398 *d++ = *s;
1399 s += n;
1400 }
1401 sp += src->stride;
1402 dp += dst->stride;
1403 }
1404
1405 return dst;
1406 }
1407
1408 fz_pixmap *
1409 fz_new_pixmap_from_color_and_mask(fz_context *ctx, fz_pixmap *color, fz_pixmap *mask)
1410 {
1411 fz_pixmap *dst;
1412 int w = color->w;
1413 int h = color->h;
1414 int n = color->n;
1415 int x, y, k;
1416
1417 if (color->alpha)
1418 fz_throw(ctx, FZ_ERROR_ARGUMENT, "color pixmap must not have an alpha channel");
1419 if (mask->n != 1)
1420 fz_throw(ctx, FZ_ERROR_ARGUMENT, "mask pixmap must have exactly one channel");
1421 if (mask->w != color->w || mask->h != color->h)
1422 fz_throw(ctx, FZ_ERROR_ARGUMENT, "color and mask pixmaps must be the same size");
1423
1424 dst = fz_new_pixmap_with_bbox(ctx, color->colorspace, fz_pixmap_bbox(ctx, color), NULL, 1);
1425
1426 for (y = 0; y < h; ++y)
1427 {
1428 unsigned char *cs = &color->samples[y * color->stride];
1429 unsigned char *ms = &mask->samples[y * mask->stride];
1430 unsigned char *ds = &dst->samples[y * dst->stride];
1431 for (x = 0; x < w; ++x)
1432 {
1433 unsigned char a = *ms++;
1434 for (k = 0; k < n; ++k)
1435 *ds++ = fz_mul255(*cs++, a);
1436 *ds++ = a;
1437 }
1438 }
1439
1440 return dst;
1441 }
1442
1443 int
1444 fz_is_pixmap_monochrome(fz_context *ctx, fz_pixmap *pixmap)
1445 {
1446 int n = pixmap->n;
1447 int w = pixmap->w;
1448 int h = pixmap->h;
1449 unsigned char *s = pixmap->samples;
1450 int x;
1451
1452 if (n != 1)
1453 return 0;
1454
1455 while (h--)
1456 {
1457 for (x = 0; x < w; ++x)
1458 {
1459 unsigned char v = s[x];
1460 if (v != 0 && v != 255)
1461 return 0;
1462 }
1463 s += pixmap->stride;
1464 }
1465
1466 return 1;
1467 }
1468
1469 #ifdef ARCH_ARM
1470 static void
1471 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1472 int n, int fwd, int back, int back2, int fwd2,
1473 int divX, int back4, int fwd4, int fwd3,
1474 int divY, int back5, int divXY)
1475 __attribute__((naked));
1476
1477 static void
1478 fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1479 int n, int fwd, int back, int back2, int fwd2,
1480 int divX, int back4, int fwd4, int fwd3,
1481 int divY, int back5, int divXY)
1482 {
1483 asm volatile(
1484 ENTER_ARM
1485 "stmfd r13!,{r1,r4-r11,r14} \n"
1486 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1487 "@ r0 = src = ptr \n"
1488 "@ r1 = w \n"
1489 "@ r2 = h \n"
1490 "@ r3 = f \n"
1491 "mov r9, r0 @ r9 = dst = ptr \n"
1492 "ldr r6, [r13,#4*12] @ r6 = fwd \n"
1493 "ldr r7, [r13,#4*13] @ r7 = back \n"
1494 "subs r2, r2, r3 @ r2 = h -= f \n"
1495 "blt 12f @ Skip if less than a full row \n"
1496 "1: @ for (y = h; y > 0; y--) { \n"
1497 "ldr r1, [r13] @ r1 = w \n"
1498 "subs r1, r1, r3 @ r1 = w -= f \n"
1499 "blt 6f @ Skip if less than a full col \n"
1500 "ldr r4, [r13,#4*10] @ r4 = factor \n"
1501 "ldr r8, [r13,#4*14] @ r8 = back2 \n"
1502 "ldr r12,[r13,#4*15] @ r12= fwd2 \n"
1503 "2: @ for (x = w; x > 0; x--) { \n"
1504 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1505 "3: @ \n"
1506 "mov r14,#0 @ r14= v = 0 \n"
1507 "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n"
1508 "4: @ \n"
1509 "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n"
1510 "5: @ \n"
1511 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n"
1512 "subs r5, r5, #1<<16 @ xx-- \n"
1513 "add r14,r14,r11 @ v += r11 \n"
1514 "bgt 5b @ } \n"
1515 "sub r0, r0, r7 @ src -= back \n"
1516 "adds r5, r5, #1<<8 @ yy-- \n"
1517 "blt 4b @ } \n"
1518 "mov r14,r14,LSR r4 @ r14 = v >>= factor \n"
1519 "strb r14,[r9], #1 @ *d++ = r14 \n"
1520 "sub r0, r0, r8 @ s -= back2 \n"
1521 "subs r5, r5, #1 @ n-- \n"
1522 "bgt 3b @ } \n"
1523 "add r0, r0, r12 @ s += fwd2 \n"
1524 "subs r1, r1, r3 @ x -= f \n"
1525 "bge 2b @ } \n"
1526 "6: @ Less than a full column left \n"
1527 "adds r1, r1, r3 @ x += f \n"
1528 "beq 11f @ if (x == 0) next row \n"
1529 "@ r0 = src \n"
1530 "@ r1 = x \n"
1531 "@ r2 = y \n"
1532 "@ r3 = f \n"
1533 "@ r4 = factor \n"
1534 "@ r6 = fwd \n"
1535 "@ r7 = back \n"
1536 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1537 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1538 "ldr r4, [r13,#4*16] @ r4 = divX \n"
1539 "ldr r8, [r13,#4*17] @ r8 = back4 \n"
1540 "ldr r12,[r13,#4*18] @ r12= fwd4 \n"
1541 "8: @ \n"
1542 "mov r14,#0 @ r14= v = 0 \n"
1543 "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n"
1544 "9: @ \n"
1545 "add r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n"
1546 "10: @ \n"
1547 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n"
1548 "subs r5, r5, #1<<16 @ xx-- \n"
1549 "add r14,r14,r11 @ v += r11 \n"
1550 "bgt 10b @ } \n"
1551 "sub r0, r0, r7 @ src -= back \n"
1552 "adds r5, r5, #1<<8 @ yy-- \n"
1553 "blt 9b @ } \n"
1554 "mul r14,r4, r14 @ r14= v *= divX \n"
1555 "mov r14,r14,LSR #16 @ r14= v >>= 16 \n"
1556 "strb r14,[r9], #1 @ *d++ = r14 \n"
1557 "sub r0, r0, r8 @ s -= back4 \n"
1558 "subs r5, r5, #1 @ n-- \n"
1559 "bgt 8b @ } \n"
1560 "add r0, r0, r12 @ s += fwd4 \n"
1561 "11: @ \n"
1562 "ldr r14,[r13,#4*19] @ r14 = fwd3 \n"
1563 "subs r2, r2, r3 @ h -= f \n"
1564 "add r0, r0, r14 @ s += fwd3 \n"
1565 "bge 1b @ } \n"
1566 "12: \n"
1567 "adds r2, r2, r3 @ h += f \n"
1568 "beq 21f @ if no stray row, end \n"
1569 "@ So doing one last (partial) row \n"
1570 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1571 "@ r0 = src = ptr \n"
1572 "@ r1 = w \n"
1573 "@ r2 = h \n"
1574 "@ r3 = f \n"
1575 "@ r4 = factor \n"
1576 "@ r5 = n \n"
1577 "@ r6 = fwd \n"
1578 " @ for (y = h; y > 0; y--) { \n"
1579 "ldr r1, [r13] @ r1 = w \n"
1580 "ldr r7, [r13,#4*21] @ r7 = back5 \n"
1581 "ldr r8, [r13,#4*14] @ r8 = back2 \n"
1582 "subs r1, r1, r3 @ r1 = w -= f \n"
1583 "blt 17f @ Skip if less than a full col \n"
1584 "ldr r4, [r13,#4*20] @ r4 = divY \n"
1585 "ldr r12,[r13,#4*15] @ r12= fwd2 \n"
1586 "13: @ for (x = w; x > 0; x--) { \n"
1587 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1588 "14: @ \n"
1589 "mov r14,#0 @ r14= v = 0 \n"
1590 "sub r5, r5, r3, LSL #8 @ for (xx = f; xx > 0; x--) { \n"
1591 "15: @ \n"
1592 "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n"
1593 "16: @ \n"
1594 "ldrb r11,[r0], r6 @ r11= *src src += fwd \n"
1595 "subs r5, r5, #1<<16 @ xx-- \n"
1596 "add r14,r14,r11 @ v += r11 \n"
1597 "bgt 16b @ } \n"
1598 "sub r0, r0, r7 @ src -= back5 \n"
1599 "adds r5, r5, #1<<8 @ yy-- \n"
1600 "blt 15b @ } \n"
1601 "mul r14,r4, r14 @ r14 = x *= divY \n"
1602 "mov r14,r14,LSR #16 @ r14 = v >>= 16 \n"
1603 "strb r14,[r9], #1 @ *d++ = r14 \n"
1604 "sub r0, r0, r8 @ s -= back2 \n"
1605 "subs r5, r5, #1 @ n-- \n"
1606 "bgt 14b @ } \n"
1607 "add r0, r0, r12 @ s += fwd2 \n"
1608 "subs r1, r1, r3 @ x -= f \n"
1609 "bge 13b @ } \n"
1610 "17: @ Less than a full column left \n"
1611 "adds r1, r1, r3 @ x += f \n"
1612 "beq 21f @ if (x == 0) end \n"
1613 "@ r0 = src \n"
1614 "@ r1 = x \n"
1615 "@ r2 = y \n"
1616 "@ r3 = f \n"
1617 "@ r4 = factor \n"
1618 "@ r6 = fwd \n"
1619 "@ r7 = back5 \n"
1620 "@ r8 = back2 \n"
1621 "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1622 "ldr r4, [r13,#4*22] @ r4 = divXY \n"
1623 "ldr r5, [r13,#4*11] @ for (nn = n; nn > 0; n--) { \n"
1624 "ldr r8, [r13,#4*17] @ r8 = back4 \n"
1625 "18: @ \n"
1626 "mov r14,#0 @ r14= v = 0 \n"
1627 "sub r5, r5, r1, LSL #8 @ for (xx = x; xx > 0; x--) { \n"
1628 "19: @ \n"
1629 "add r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n"
1630 "20: @ \n"
1631 "ldrb r11,[r0],r6 @ r11= *src src += fwd \n"
1632 "subs r5, r5, #1<<16 @ xx-- \n"
1633 "add r14,r14,r11 @ v += r11 \n"
1634 "bgt 20b @ } \n"
1635 "sub r0, r0, r7 @ src -= back5 \n"
1636 "adds r5, r5, #1<<8 @ yy-- \n"
1637 "blt 19b @ } \n"
1638 "mul r14,r4, r14 @ r14= v *= divX \n"
1639 "mov r14,r14,LSR #16 @ r14= v >>= 16 \n"
1640 "strb r14,[r9], #1 @ *d++ = r14 \n"
1641 "sub r0, r0, r8 @ s -= back4 \n"
1642 "subs r5, r5, #1 @ n-- \n"
1643 "bgt 18b @ } \n"
1644 "21: @ \n"
1645 "ldmfd r13!,{r1,r4-r11,PC} @ pop, return to thumb \n"
1646 ENTER_THUMB
1647 );
1648 }
1649
1650 #endif
1651
1652 void
1653 fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor)
1654 {
1655 int f;
1656
1657 if (!tile)
1658 return;
1659
1660 assert(tile->stride >= tile->w * tile->n);
1661
1662 fz_subsample_pixblock(tile->samples, tile->w, tile->h, tile->n, factor, tile->stride);
1663
1664 f = 1<<factor;
1665 tile->w = (tile->w + f-1)>>factor;
1666 tile->h = (tile->h + f-1)>>factor;
1667 tile->stride = tile->w * (size_t)tile->n;
1668 /* Redundant test? We only ever make pixmaps smaller! */
1669 if (tile->h > INT_MAX / (tile->w * tile->n))
1670 fz_throw(ctx, FZ_ERROR_LIMIT, "pixmap too large");
1671 tile->samples = fz_realloc(ctx, tile->samples, (size_t)tile->h * tile->w * tile->n);
1672 }
1673
1674 void
1675 fz_subsample_pixblock(unsigned char *s, int w, int h, int n, int factor, ptrdiff_t stride)
1676 {
1677 int fwd, fwd2, fwd3, back, back2, f;
1678 unsigned char *d;
1679 #ifndef ARCH_ARM
1680 int x, y, xx, yy, nn;
1681 #endif
1682
1683 d = s;
1684 f = 1<<factor;
1685 fwd = stride;
1686 back = f*fwd-n;
1687 back2 = f*n-1;
1688 fwd2 = (f-1)*n;
1689 fwd3 = (f-1)*fwd + (int)stride - w * n;
1690 factor *= 2;
1691 #ifdef ARCH_ARM
1692 {
1693 int strayX = w%f;
1694 int divX = (strayX ? 65536/(strayX*f) : 0);
1695 int fwd4 = (strayX-1) * n;
1696 int back4 = strayX*n-1;
1697 int strayY = h%f;
1698 int divY = (strayY ? 65536/(strayY*f) : 0);
1699 int back5 = fwd * strayY - n;
1700 int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0);
1701 fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back,
1702 back2, fwd2, divX, back4, fwd4, fwd3,
1703 divY, back5, divXY);
1704 }
1705 #else
1706 for (y = h - f; y >= 0; y -= f)
1707 {
1708 for (x = w - f; x >= 0; x -= f)
1709 {
1710 for (nn = n; nn > 0; nn--)
1711 {
1712 int v = 0;
1713 for (xx = f; xx > 0; xx--)
1714 {
1715 for (yy = f; yy > 0; yy--)
1716 {
1717 v += *s;
1718 s += fwd;
1719 }
1720 s -= back;
1721 }
1722 *d++ = v >> factor;
1723 s -= back2;
1724 }
1725 s += fwd2;
1726 }
1727 /* Do any strays */
1728 x += f;
1729 if (x > 0)
1730 {
1731 int div = x * f;
1732 int fwd4 = (x-1) * n;
1733 int back4 = x*n-1;
1734 for (nn = n; nn > 0; nn--)
1735 {
1736 int v = 0;
1737 for (xx = x; xx > 0; xx--)
1738 {
1739 for (yy = f; yy > 0; yy--)
1740 {
1741 v += *s;
1742 s += fwd;
1743 }
1744 s -= back;
1745 }
1746 *d++ = v / div;
1747 s -= back4;
1748 }
1749 s += fwd4;
1750 }
1751 s += fwd3;
1752 }
1753 /* Do any stray line */
1754 y += f;
1755 if (y > 0)
1756 {
1757 int div = y * f;
1758 int back5 = fwd * y - n;
1759 for (x = w - f; x >= 0; x -= f)
1760 {
1761 for (nn = n; nn > 0; nn--)
1762 {
1763 int v = 0;
1764 for (xx = f; xx > 0; xx--)
1765 {
1766 for (yy = y; yy > 0; yy--)
1767 {
1768 v += *s;
1769 s += fwd;
1770 }
1771 s -= back5;
1772 }
1773 *d++ = v / div;
1774 s -= back2;
1775 }
1776 s += fwd2;
1777 }
1778 /* Do any stray at the end of the stray line */
1779 x += f;
1780 if (x > 0)
1781 {
1782 int back4 = x * n - 1;
1783 div = x * y;
1784 for (nn = n; nn > 0; nn--)
1785 {
1786 int v = 0;
1787 for (xx = x; xx > 0; xx--)
1788 {
1789 for (yy = y; yy > 0; yy--)
1790 {
1791 v += *s;
1792 s += fwd;
1793 }
1794 s -= back5;
1795 }
1796 *d++ = v / div;
1797 s -= back4;
1798 }
1799 }
1800 }
1801 #endif
1802 }
1803
1804 void
1805 fz_set_pixmap_resolution(fz_context *ctx, fz_pixmap *pix, int xres, int yres)
1806 {
1807 pix->xres = xres;
1808 pix->yres = yres;
1809 }
1810
1811 /*
1812 Return the md5 digest for a pixmap
1813 */
1814 void
1815 fz_md5_pixmap(fz_context *ctx, fz_pixmap *pix, unsigned char digest[16])
1816 {
1817 fz_md5 md5;
1818
1819 fz_md5_init(&md5);
1820 if (pix)
1821 {
1822 unsigned char *s = pix->samples;
1823 int h = pix->h;
1824 int ss = pix->stride;
1825 int len = pix->w * pix->n;
1826 while (h--)
1827 {
1828 fz_md5_update(&md5, s, len);
1829 s += ss;
1830 }
1831 }
1832 fz_md5_final(&md5, digest);
1833 }
1834
1835 #ifdef HAVE_VALGRIND
1836 int fz_valgrind_pixmap(const fz_pixmap *pix)
1837 {
1838 int w, h, n, total;
1839 int ww, hh, nn;
1840 int stride;
1841 const unsigned char *p = pix->samples;
1842
1843 if (pix == NULL)
1844 return 0;
1845
1846 total = 0;
1847 ww = pix->w;
1848 hh = pix->h;
1849 nn = pix->n;
1850 stride = pix->stride - ww*nn;
1851 for (h = 0; h < hh; h++)
1852 {
1853 for (w = 0; w < ww; w++)
1854 for (n = 0; n < nn; n++)
1855 if (*p++) total ++;
1856 p += stride;
1857 }
1858 return total;
1859 }
1860 #endif /* HAVE_VALGRIND */
1861
1862 fz_pixmap *
1863 fz_convert_indexed_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
1864 {
1865 fz_pixmap *dst;
1866 fz_colorspace *base;
1867 const unsigned char *s;
1868 unsigned char *d;
1869 int y, x, k, n, high;
1870 unsigned char *lookup;
1871 ptrdiff_t s_line_inc, d_line_inc;
1872
1873 if (src->colorspace->type != FZ_COLORSPACE_INDEXED)
1874 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot convert non-indexed pixmap");
1875 if (src->n != 1 + src->alpha)
1876 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot convert indexed pixmap mis-matching components");
1877
1878 base = src->colorspace->u.indexed.base;
1879 high = src->colorspace->u.indexed.high;
1880 lookup = src->colorspace->u.indexed.lookup;
1881 n = base->n;
1882
1883 dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
1884 s = src->samples;
1885 d = dst->samples;
1886 s_line_inc = src->stride - src->w * (ptrdiff_t)src->n;
1887 d_line_inc = dst->stride - dst->w * (ptrdiff_t)dst->n;
1888
1889 if (src->alpha)
1890 {
1891 for (y = 0; y < src->h; y++)
1892 {
1893 for (x = 0; x < src->w; x++)
1894 {
1895 int v = *s++;
1896 int a = *s++;
1897 int aa = a + (a>>7);
1898 v = fz_mini(v, high);
1899 for (k = 0; k < n; k++)
1900 *d++ = (aa * lookup[v * n + k] + 128)>>8;
1901 *d++ = a;
1902 }
1903 s += s_line_inc;
1904 d += d_line_inc;
1905 }
1906 }
1907 else
1908 {
1909 for (y = 0; y < src->h; y++)
1910 {
1911 for (x = 0; x < src->w; x++)
1912 {
1913 int v = *s++;
1914 v = fz_mini(v, high);
1915 for (k = 0; k < n; k++)
1916 *d++ = lookup[v * n + k];
1917 }
1918 s += s_line_inc;
1919 d += d_line_inc;
1920 }
1921 }
1922
1923 if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1924 dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1925 else
1926 dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1927
1928 return dst;
1929 }
1930
1931 fz_pixmap *
1932 fz_convert_separation_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
1933 {
1934 fz_pixmap *dst;
1935 fz_colorspace *ss, *base;
1936 const unsigned char *s;
1937 unsigned char *d;
1938 int y, x, k, sn, bn, a;
1939 float src_v[FZ_MAX_COLORS];
1940 float base_v[FZ_MAX_COLORS];
1941 ptrdiff_t s_line_inc, d_line_inc;
1942
1943 ss = src->colorspace;
1944
1945 if (ss->type != FZ_COLORSPACE_SEPARATION)
1946 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot expand non-separation pixmap");
1947 if (src->n != ss->n + src->alpha)
1948 fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot expand separation pixmap mis-matching alpha channel");
1949
1950 base = ss->u.separation.base;
1951 dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
1952 fz_clear_pixmap(ctx, dst);
1953 fz_try(ctx)
1954 {
1955 s = src->samples;
1956 d = dst->samples;
1957 s_line_inc = src->stride - src->w * (ptrdiff_t)src->n;
1958 d_line_inc = dst->stride - dst->w * (ptrdiff_t)dst->n;
1959 sn = ss->n;
1960 bn = base->n;
1961
1962 if (base->type == FZ_COLORSPACE_LAB)
1963 {
1964 if (src->alpha)
1965 {
1966 for (y = 0; y < src->h; y++)
1967 {
1968 for (x = 0; x < src->w; x++)
1969 {
1970 for (k = 0; k < sn; ++k)
1971 src_v[k] = *s++ / 255.0f;
1972 a = *s++;
1973 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1974 *d++ = (base_v[0] / 100) * 255.0f;
1975 *d++ = base_v[1] + 128;
1976 *d++ = base_v[2] + 128;
1977 *d++ = a;
1978 }
1979 s += s_line_inc;
1980 d += d_line_inc;
1981 }
1982 }
1983 else
1984 {
1985 for (y = 0; y < src->h; y++)
1986 {
1987 for (x = 0; x < src->w; x++)
1988 {
1989 for (k = 0; k < sn; ++k)
1990 src_v[k] = *s++ / 255.0f;
1991 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
1992 *d++ = (base_v[0] / 100) * 255.0f;
1993 *d++ = base_v[1] + 128;
1994 *d++ = base_v[2] + 128;
1995 }
1996 s += s_line_inc;
1997 d += d_line_inc;
1998 }
1999 }
2000 }
2001 else
2002 {
2003 if (src->alpha)
2004 {
2005 for (y = 0; y < src->h; y++)
2006 {
2007 for (x = 0; x < src->w; x++)
2008 {
2009 for (k = 0; k < sn; ++k)
2010 src_v[k] = *s++ / 255.0f;
2011 a = *s++;
2012 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
2013 for (k = 0; k < bn; ++k)
2014 *d++ = base_v[k] * 255.0f;
2015 *d++ = a;
2016 }
2017 s += s_line_inc;
2018 d += d_line_inc;
2019 }
2020 }
2021 else
2022 {
2023 for (y = 0; y < src->h; y++)
2024 {
2025 for (x = 0; x < src->w; x++)
2026 {
2027 for (k = 0; k < sn; ++k)
2028 src_v[k] = *s++ / 255.0f;
2029 ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
2030 for (k = 0; k < bn; ++k)
2031 *d++ = base_v[k] * 255.0f;
2032 }
2033 s += s_line_inc;
2034 d += d_line_inc;
2035 }
2036 }
2037 }
2038
2039 if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
2040 dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
2041 else
2042 dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
2043 }
2044 fz_catch(ctx)
2045 {
2046 fz_drop_pixmap(ctx, dst);
2047 fz_rethrow(ctx);
2048 }
2049
2050 return dst;
2051 }