Coverage Report

Created: 2026-08-14 07:34

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