Coverage Report

Created: 2024-07-05 06:13

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