Coverage Report

Created: 2026-11-12 07:07

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
478k
{
45
478k
  if (pix)
46
233k
    fz_drop_storable(ctx, &pix->storable);
47
478k
}
48
49
void
50
fz_drop_pixmap_imp(fz_context *ctx, fz_storable *pix_)
51
229k
{
52
229k
  fz_pixmap *pix = (fz_pixmap *)pix_;
53
54
229k
  fz_drop_colorspace(ctx, pix->colorspace);
55
229k
  fz_drop_separations(ctx, pix->seps);
56
229k
  if (pix->flags & FZ_PIXMAP_FLAG_FREE_SAMPLES)
57
212k
    fz_free(ctx, pix->samples);
58
229k
  fz_drop_pixmap(ctx, pix->underlying);
59
229k
  fz_free(ctx, pix);
60
229k
}
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
229k
{
65
229k
  fz_pixmap *pix;
66
229k
  int s = fz_count_active_separations(ctx, seps);
67
229k
  int n;
68
69
229k
  if (w < 0 || h < 0)
70
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal dimensions for pixmap %d %d", w, h);
71
72
229k
  n = alpha + s + fz_colorspace_n(ctx, colorspace);
73
229k
  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
229k
  if (samples == NULL && stride < n*w)
76
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal -ve stride for pixmap without data");
77
229k
  if (n > FZ_MAX_COLORS)
78
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "Illegal number of colorants");
79
80
229k
  pix = fz_malloc_struct(ctx, fz_pixmap);
81
229k
  FZ_INIT_STORABLE(pix, 1, fz_drop_pixmap_imp);
82
229k
  pix->x = 0;
83
229k
  pix->y = 0;
84
229k
  pix->w = w;
85
229k
  pix->h = h;
86
229k
  pix->alpha = alpha = !!alpha;
87
229k
  pix->flags = FZ_PIXMAP_FLAG_INTERPOLATE;
88
229k
  pix->xres = 96;
89
229k
  pix->yres = 96;
90
229k
  pix->colorspace = NULL;
91
229k
  pix->n = n;
92
229k
  pix->s = s;
93
229k
  pix->seps = fz_keep_separations(ctx, seps);
94
229k
  pix->stride = stride;
95
96
229k
  if (colorspace)
97
121k
  {
98
121k
    pix->colorspace = fz_keep_colorspace(ctx, colorspace);
99
121k
  }
100
108k
  else
101
108k
  {
102
108k
    assert(alpha || s);
103
108k
  }
104
105
229k
  pix->samples = samples;
106
229k
  if (!samples && pix->h > 0 && pix->w > 0)
107
212k
  {
108
425k
    fz_try(ctx)
109
425k
    {
110
212k
      if ((size_t)pix->stride > SIZE_MAX / (size_t)pix->h)
111
0
        fz_throw(ctx, FZ_ERROR_LIMIT, "Overly large image");
112
212k
      if (pix->h * pix->stride > FZ_MAX_SAMPLES)
113
0
        fz_throw(ctx, FZ_ERROR_LIMIT, "Overly large image");
114
212k
      pix->samples = Memento_label(fz_malloc(ctx, pix->h * pix->stride), "pixmap_data");
115
212k
    }
116
425k
    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
212k
    pix->flags |= FZ_PIXMAP_FLAG_FREE_SAMPLES;
124
212k
  }
125
126
229k
  return pix;
127
229k
}
128
129
fz_pixmap *
130
fz_new_pixmap(fz_context *ctx, fz_colorspace *colorspace, int w, int h, fz_separations *seps, int alpha)
131
229k
{
132
229k
  int stride;
133
229k
  int s = fz_count_active_separations(ctx, seps);
134
229k
  int n;
135
229k
  if (!colorspace && s == 0) alpha = 1;
136
229k
  n = fz_colorspace_n(ctx, colorspace) + s + alpha;
137
229k
  if (w > INT_MAX / n)
138
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "Overly wide image");
139
229k
  stride = n * w;
140
229k
  return fz_new_pixmap_with_data(ctx, colorspace, w, h, seps, alpha, stride, NULL);
141
229k
}
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
138k
{
146
138k
  fz_pixmap *pixmap;
147
138k
  pixmap = fz_new_pixmap(ctx, colorspace, fz_irect_width(bbox), fz_irect_height(bbox), seps, alpha);
148
138k
  pixmap->x = bbox.x0;
149
138k
  pixmap->y = bbox.y0;
150
138k
  return pixmap;
151
138k
}
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
181k
{
213
181k
  fz_irect bbox;
214
181k
  bbox.x0 = pix->x;
215
181k
  bbox.y0 = pix->y;
216
181k
  bbox.x1 = pix->x + pix->w;
217
181k
  bbox.y1 = pix->y + pix->h;
218
181k
  return bbox;
219
181k
}
220
221
fz_irect
222
fz_pixmap_bbox_no_ctx(const fz_pixmap *pix)
223
1.78M
{
224
1.78M
  fz_irect bbox;
225
1.78M
  bbox.x0 = pix->x;
226
1.78M
  bbox.y0 = pix->y;
227
1.78M
  bbox.x1 = pix->x + pix->w;
228
1.78M
  bbox.y1 = pix->y + pix->h;
229
1.78M
  return bbox;
230
1.78M
}
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
2
{
267
2
  return pix->n;
268
2
}
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
2
{
291
2
  return pix->stride;
292
2
}
293
294
unsigned char *
295
fz_pixmap_samples(fz_context *ctx, const fz_pixmap *pix)
296
2
{
297
2
  if (!pix)
298
0
    return NULL;
299
2
  return pix->samples;
300
2
}
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
55.8k
{
528
55.8k
  ptrdiff_t stride = pix->w * (ptrdiff_t)pix->n;
529
55.8k
  int h = pix->h;
530
55.8k
  unsigned char *s = pix->samples;
531
55.8k
  if (stride == pix->stride)
532
55.8k
  {
533
55.8k
    stride *= h;
534
55.8k
    h = 1;
535
55.8k
  }
536
55.8k
  if (pix->alpha || fz_colorspace_is_subtractive(ctx, pix->colorspace))
537
55.8k
  {
538
111k
    while (h--)
539
55.8k
    {
540
55.8k
      memset(s, 0, stride);
541
55.8k
      s += pix->stride;
542
55.8k
    }
543
55.8k
  }
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
55.8k
}
582
583
void
584
fz_clear_pixmap_with_value(fz_context *ctx, fz_pixmap *pix, int value)
585
3.04k
{
586
3.04k
  unsigned char *s;
587
3.04k
  int w, h, n;
588
3.04k
  ptrdiff_t stride, len;
589
3.04k
  int alpha = pix->alpha;
590
591
3.04k
  w = pix->w;
592
3.04k
  h = pix->h;
593
3.04k
  if (w < 0 || h < 0)
594
0
    return;
595
596
  /* CMYK needs special handling (and potentially any other subtractive colorspaces) */
597
3.04k
  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
3.04k
  n = pix->n;
604
3.04k
  stride = pix->stride;
605
3.04k
  len = (ptrdiff_t)w * n;
606
607
3.04k
  s = pix->samples;
608
3.04k
  if (value == 255 || !alpha)
609
3.04k
  {
610
3.04k
    if (stride == len)
611
3.04k
    {
612
3.04k
      len *= h;
613
3.04k
      h = 1;
614
3.04k
    }
615
6.08k
    while (h--)
616
3.04k
    {
617
3.04k
      memset(s, value, len);
618
3.04k
      s += stride;
619
3.04k
    }
620
3.04k
  }
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
3.04k
}
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
29.9k
{
673
29.9k
  unsigned char *srcp;
674
29.9k
  unsigned char *destp;
675
29.9k
  unsigned int y, w;
676
29.9k
  size_t destspan, srcspan;
677
678
29.9k
  b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
679
29.9k
  b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, src));
680
29.9k
  if (fz_is_empty_irect(b))
681
2.52k
    return;
682
27.3k
  w = (unsigned int)(b.x1 - b.x0);
683
27.3k
  y = (unsigned int)(b.y1 - b.y0);
684
685
27.3k
  srcspan = src->stride;
686
27.3k
  srcp = src->samples + srcspan * (b.y0 - src->y) + (b.x0 - src->x) * (size_t)src->n;
687
27.3k
  destspan = dest->stride;
688
27.3k
  destp = dest->samples + destspan * (b.y0 - dest->y) + (b.x0 - dest->x) * (size_t)dest->n;
689
690
27.3k
  if (src->n == dest->n)
691
27.3k
  {
692
27.3k
    w *= src->n;
693
27.3k
    do
694
240k
    {
695
240k
      memcpy(destp, srcp, w);
696
240k
      srcp += srcspan;
697
240k
      destp += destspan;
698
240k
    }
699
240k
    while (--y);
700
27.3k
  }
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
27.3k
}
712
713
void
714
fz_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_irect b)
715
66
{
716
66
  unsigned char *destp;
717
66
  int x, y, w, k;
718
66
  size_t destspan;
719
720
66
  b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));
721
66
  w = b.x1 - b.x0;
722
66
  y = b.y1 - b.y0;
723
66
  if (w <= 0 || y <= 0)
724
0
    return;
725
726
66
  destspan = dest->stride;
727
66
  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
66
  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
66
  if (value == 255)
751
66
  {
752
66
    do
753
24.6k
    {
754
24.6k
      memset(destp, 255, w * (size_t)dest->n);
755
24.6k
      destp += destspan;
756
24.6k
    }
757
24.6k
    while (--y);
758
66
  }
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
66
}
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.53k
{
803
2.53k
  fz_pixmap *alpha;
804
2.53k
  unsigned char *sp, *dp;
805
2.53k
  int w, h, sstride, dstride;
806
807
2.53k
  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.53k
  alpha = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, gray), 0, 1);
811
2.53k
  dp = alpha->samples;
812
2.53k
  dstride = alpha->stride;
813
2.53k
  sp = gray->samples;
814
2.53k
  sstride = gray->stride;
815
816
2.53k
  h = gray->h;
817
2.53k
  w = gray->w;
818
19.4k
  while (h--)
819
16.9k
  {
820
16.9k
    memcpy(dp, sp, w);
821
16.9k
    sp += sstride;
822
16.9k
    dp += dstride;
823
16.9k
  }
824
825
2.53k
  return alpha;
826
2.53k
}
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
229k
{
1205
229k
  if (pix == NULL)
1206
144
    return 0;
1207
229k
  return sizeof(*pix) + (size_t)pix->n * pix->w * pix->h;
1208
229k
}
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
7.40k
{
1213
7.40k
  fz_pixmap *cvt;
1214
7.40k
  int src_alpha = pix->alpha;
1215
1216
7.40k
  if (!ds && !keep_alpha)
1217
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot both throw away and keep alpha");
1218
1219
7.40k
  if (pix->colorspace == NULL)
1220
0
  {
1221
    /* Alpha only pixmaps are treated as devicegray, with no alpha. */
1222
0
    src_alpha = 0;
1223
0
  }
1224
1225
7.40k
  cvt = fz_new_pixmap(ctx, ds, pix->w, pix->h, pix->seps, keep_alpha && src_alpha);
1226
1227
7.40k
  cvt->xres = pix->xres;
1228
7.40k
  cvt->yres = pix->yres;
1229
7.40k
  cvt->x = pix->x;
1230
7.40k
  cvt->y = pix->y;
1231
7.40k
  if (pix->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
1232
7.40k
    cvt->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
1233
1
  else
1234
1
    cvt->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
1235
1236
14.8k
  fz_try(ctx)
1237
14.8k
  {
1238
7.40k
    fz_convert_pixmap_samples(ctx, pix, cvt, prf, default_cs, color_params, 1);
1239
7.40k
  }
1240
14.8k
  fz_catch(ctx)
1241
0
  {
1242
0
    fz_drop_pixmap(ctx, cvt);
1243
0
    fz_rethrow(ctx);
1244
0
  }
1245
1246
7.40k
  return cvt;
1247
7.40k
}
1248
1249
fz_pixmap *
1250
fz_new_pixmap_from_8bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1251
73.3k
{
1252
73.3k
  fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1253
73.3k
  int stride = pixmap->stride;
1254
73.3k
  unsigned char *s = pixmap->samples;
1255
73.3k
  pixmap->x = x;
1256
73.3k
  pixmap->y = y;
1257
1258
509k
  for (y = 0; y < h; y++)
1259
436k
  {
1260
436k
    if (w)
1261
436k
      memcpy(s, sp + y * span, w);
1262
436k
    s += stride;
1263
436k
  }
1264
1265
73.3k
  return pixmap;
1266
73.3k
}
1267
1268
fz_pixmap *
1269
fz_new_pixmap_from_1bpp_data(fz_context *ctx, int x, int y, int w, int h, unsigned char *sp, int span)
1270
0
{
1271
0
  fz_pixmap *pixmap = fz_new_pixmap(ctx, NULL, w, h, NULL, 1);
1272
0
  int stride = pixmap->stride - pixmap->w;
1273
0
  pixmap->x = x;
1274
0
  pixmap->y = y;
1275
1276
0
  for (y = 0; y < h; y++)
1277
0
  {
1278
0
    unsigned char *out = pixmap->samples + y * w;
1279
0
    unsigned char *in = sp + y * span;
1280
0
    unsigned char bit = 0x80;
1281
0
    int ww = w;
1282
0
    while (ww--)
1283
0
    {
1284
0
      *out++ = (*in & bit) ? 255 : 0;
1285
0
      bit >>= 1;
1286
0
      if (bit == 0)
1287
0
        bit = 0x80, in++;
1288
0
    }
1289
0
    out += stride;
1290
0
  }
1291
1292
0
  return pixmap;
1293
0
}
1294
1295
static float
1296
calc_percentile(int *hist, float thr, float scale, float minval, float maxval)
1297
0
{
1298
0
  float prct;
1299
0
  int k = 0, count = 0;
1300
1301
0
  while (count < thr)
1302
0
    count += hist[k++];
1303
1304
0
  if (k <= 0)
1305
0
    prct = k;
1306
0
  else
1307
0
  {
1308
0
    float c0 = count - thr;
1309
0
    float c1 = thr - (count - hist[k - 1]);
1310
0
    prct = (c1 * k + c0 * (k - 1)) / (c0 + c1);
1311
0
  }
1312
1313
0
  prct /= scale;
1314
0
  prct += minval;
1315
0
  return fz_clamp(prct, minval, maxval);
1316
0
}
1317
1318
static void
1319
calc_percentiles(fz_context *ctx, float *samples, size_t nsamples, float *minprct, float *maxprct)
1320
0
{
1321
0
  float minval, maxval, scale;
1322
0
  size_t size, k;
1323
0
  int *hist;
1324
1325
0
  minval = maxval = samples[0];
1326
0
  for (k = 1; k < nsamples; k++)
1327
0
  {
1328
0
    minval = fz_min(minval, samples[k]);
1329
0
    maxval = fz_max(maxval, samples[k]);
1330
0
  }
1331
1332
0
  if (minval - maxval == 0)
1333
0
  {
1334
0
    *minprct = *maxprct = minval;
1335
0
    return;
1336
0
  }
1337
1338
0
  size = fz_minz(65535, nsamples);
1339
0
  scale = (size - 1) / (maxval - minval);
1340
1341
0
  hist = fz_calloc(ctx, size, sizeof(int));
1342
1343
0
  *minprct = 0;
1344
0
  *maxprct = 0;
1345
1346
0
  for (k = 0; k < nsamples; k++)
1347
0
    hist[(uint16_t) (scale * (samples[k] - minval))]++;
1348
1349
0
  *minprct = calc_percentile(hist, 0.01f * nsamples, scale, minval, maxval);
1350
0
  *maxprct = calc_percentile(hist, 0.99f * nsamples, scale, minval, maxval);
1351
1352
0
  fz_free(ctx, hist);
1353
0
}
1354
1355
/* Tone mapping according to "Consistent Tone Reproduction" by Min H. Kim and Jan Kautz. */
1356
fz_pixmap *
1357
fz_new_pixmap_from_float_data(fz_context *ctx, fz_colorspace *cs, int w, int h, float *samples)
1358
0
{
1359
0
  fz_pixmap *pixmap = NULL;
1360
0
  unsigned char *dp;
1361
0
  float *sample;
1362
0
  float minsample, maxsample, mu;
1363
0
  float k1, d0, sigma, sigmasq2;
1364
0
  float minprct, maxprct, range;
1365
0
  size_t k, nsamples;
1366
0
  int y;
1367
0
#define KIMKAUTZC1 (3.0f)
1368
0
#define KIMKAUTZC2 (0.5f)
1369
0
#define MAXLD (logf(300.0f))
1370
0
#define MINLD (logf(0.3f))
1371
1372
0
  pixmap = fz_new_pixmap(ctx, cs, w, h, NULL, 0);
1373
0
  if (w > 0 && h > 0 && pixmap->n > 0)
1374
0
  {
1375
0
    fz_try(ctx)
1376
0
    {
1377
0
      nsamples = (size_t) w * h;
1378
0
      if ((size_t) pixmap->n > SIZE_MAX / nsamples)
1379
0
        fz_throw(ctx, FZ_ERROR_LIMIT, "too many floating point samples to convert to pixmap");
1380
0
      nsamples *= pixmap->n;
1381
1382
0
      mu = 0;
1383
0
      minsample = FLT_MAX;
1384
0
      maxsample = -FLT_MAX;
1385
1386
0
      for (k = 0; k < nsamples; k++)
1387
0
      {
1388
0
        float v = logf(samples[k] == 0 ? FLT_MIN : samples[k]);
1389
0
        mu += v;
1390
0
        minsample = fz_min(minsample, v);
1391
0
        maxsample = fz_max(maxsample, v);
1392
0
      }
1393
1394
0
      mu /= nsamples;
1395
0
      d0 = maxsample - minsample;
1396
0
      if (d0 == 0)
1397
0
        d0 = 1;
1398
0
      k1 = (MAXLD - MINLD) / d0;
1399
0
      sigma = d0 / KIMKAUTZC1;
1400
0
      sigmasq2 = sigma * sigma * 2;
1401
1402
0
      for (k = 0; k < nsamples; k++)
1403
0
      {
1404
0
        float samplemu = samples[k] - mu;
1405
0
        float samplemu2 = samplemu * samplemu;
1406
0
        float fw = expf(-samplemu2 / sigmasq2);
1407
0
        float k2 = (1 - k1) * fw + k1;
1408
0
        samples[k] = expf(KIMKAUTZC2 * k2 * (logf(samples[k] == 0 ? FLT_MIN : samples[k]) - mu) + mu);
1409
0
      }
1410
1411
0
      calc_percentiles(ctx, samples, nsamples, &minprct, &maxprct);
1412
0
      range = maxprct - minprct;
1413
1414
0
      dp = pixmap->samples + pixmap->stride * (h - 1);
1415
0
      sample = samples;
1416
1417
0
      for (y = 0; y < h; y++)
1418
0
      {
1419
0
        unsigned char *dpp = dp;
1420
1421
0
        for (k = 0; k < (size_t) w * pixmap->n; k++)
1422
0
          *dpp++ = 255.0f * (fz_clamp(*sample++, minprct, maxprct) - minprct) / range;
1423
1424
0
        dp -= pixmap->stride;
1425
0
      }
1426
0
    }
1427
0
    fz_catch(ctx)
1428
0
    {
1429
0
      fz_drop_pixmap(ctx, pixmap);
1430
0
      fz_rethrow(ctx);
1431
0
    }
1432
0
  }
1433
1434
0
  return pixmap;
1435
0
}
1436
1437
fz_pixmap *
1438
fz_new_pixmap_from_alpha_channel(fz_context *ctx, fz_pixmap *src)
1439
0
{
1440
0
  fz_pixmap *dst;
1441
0
  int w, h, n, x;
1442
0
  unsigned char *sp, *dp;
1443
1444
0
  if (!src->alpha)
1445
0
    return NULL;
1446
1447
0
  dst = fz_new_pixmap_with_bbox(ctx, NULL, fz_pixmap_bbox(ctx, src), NULL, 1);
1448
0
  w = src->w;
1449
0
  h = src->h;
1450
0
  n = src->n;
1451
0
  sp = src->samples + n - 1;
1452
0
  dp = dst->samples;
1453
1454
0
  while (h--)
1455
0
  {
1456
0
    unsigned char *s = sp;
1457
0
    unsigned char *d = dp;
1458
0
    for (x = 0; x < w; ++x)
1459
0
    {
1460
0
      *d++ = *s;
1461
0
      s += n;
1462
0
    }
1463
0
    sp += src->stride;
1464
0
    dp += dst->stride;
1465
0
  }
1466
1467
0
  return dst;
1468
0
}
1469
1470
fz_pixmap *
1471
fz_new_pixmap_from_color_and_mask(fz_context *ctx, fz_pixmap *color, fz_pixmap *mask)
1472
0
{
1473
0
  fz_pixmap *dst;
1474
0
  int w = color->w;
1475
0
  int h = color->h;
1476
0
  int n = color->n;
1477
0
  int x, y, k;
1478
1479
0
  if (color->alpha)
1480
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "color pixmap must not have an alpha channel");
1481
0
  if (mask->n != 1)
1482
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "mask pixmap must have exactly one channel");
1483
0
  if (mask->w != color->w || mask->h != color->h)
1484
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "color and mask pixmaps must be the same size");
1485
1486
0
  dst = fz_new_pixmap_with_bbox(ctx, color->colorspace, fz_pixmap_bbox(ctx, color), NULL, 1);
1487
1488
0
  for (y = 0; y < h; ++y)
1489
0
  {
1490
0
    unsigned char *cs = &color->samples[y * color->stride];
1491
0
    unsigned char *ms = &mask->samples[y * mask->stride];
1492
0
    unsigned char *ds = &dst->samples[y * dst->stride];
1493
0
    for (x = 0; x < w; ++x)
1494
0
    {
1495
0
      unsigned char a = *ms++;
1496
0
      for (k = 0; k < n; ++k)
1497
0
        *ds++ = fz_mul255(*cs++, a);
1498
0
      *ds++ = a;
1499
0
    }
1500
0
  }
1501
1502
0
  return dst;
1503
0
}
1504
1505
int
1506
fz_is_pixmap_monochrome(fz_context *ctx, fz_pixmap *pixmap)
1507
0
{
1508
0
  int n = pixmap->n;
1509
0
  int w = pixmap->w;
1510
0
  int h = pixmap->h;
1511
0
  unsigned char *s = pixmap->samples;
1512
0
  int x;
1513
1514
0
  if (n != 1)
1515
0
    return 0;
1516
1517
0
  while (h--)
1518
0
  {
1519
0
    for (x = 0; x < w; ++x)
1520
0
    {
1521
0
      unsigned char v = s[x];
1522
0
      if (v != 0 && v != 255)
1523
0
        return 0;
1524
0
    }
1525
0
    s += pixmap->stride;
1526
0
  }
1527
1528
0
  return 1;
1529
0
}
1530
1531
#ifdef ARCH_ARM
1532
static void
1533
fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1534
      int n, int fwd, int back, int back2, int fwd2,
1535
      int divX, int back4, int fwd4, int fwd3,
1536
      int divY, int back5, int divXY)
1537
__attribute__((naked));
1538
1539
static void
1540
fz_subsample_pixmap_ARM(unsigned char *ptr, int w, int h, int f, int factor,
1541
      int n, int fwd, int back, int back2, int fwd2,
1542
      int divX, int back4, int fwd4, int fwd3,
1543
      int divY, int back5, int divXY)
1544
{
1545
  asm volatile(
1546
  ENTER_ARM
1547
  "stmfd  r13!,{r1,r4-r11,r14}          \n"
1548
  "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1549
  "@ r0 = src = ptr           \n"
1550
  "@ r1 = w             \n"
1551
  "@ r2 = h             \n"
1552
  "@ r3 = f             \n"
1553
  "mov  r9, r0      @ r9 = dst = ptr    \n"
1554
  "ldr  r6, [r13,#4*12]   @ r6 = fwd      \n"
1555
  "ldr  r7, [r13,#4*13]   @ r7 = back     \n"
1556
  "subs r2, r2, r3    @ r2 = h -= f     \n"
1557
  "blt  12f     @ Skip if less than a full row  \n"
1558
  "1:       @ for (y = h; y > 0; y--) { \n"
1559
  "ldr  r1, [r13]   @ r1 = w      \n"
1560
  "subs r1, r1, r3    @ r1 = w -= f     \n"
1561
  "blt  6f      @ Skip if less than a full col  \n"
1562
  "ldr  r4, [r13,#4*10]   @ r4 = factor     \n"
1563
  "ldr  r8, [r13,#4*14]   @ r8 = back2      \n"
1564
  "ldr  r12,[r13,#4*15]   @ r12= fwd2     \n"
1565
  "2:       @ for (x = w; x > 0; x--) { \n"
1566
  "ldr  r5, [r13,#4*11]   @ for (nn = n; nn > 0; n--) { \n"
1567
  "3:       @       \n"
1568
  "mov  r14,#0      @ r14= v = 0      \n"
1569
  "sub  r5, r5, r3, LSL #8  @ for (xx = f; xx > 0; x--) { \n"
1570
  "4:       @       \n"
1571
  "add  r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n"
1572
  "5:       @       \n"
1573
  "ldrb r11,[r0], r6    @ r11= *src src += fwd  \n"
1574
  "subs r5, r5, #1<<16    @ xx--        \n"
1575
  "add  r14,r14,r11   @ v += r11      \n"
1576
  "bgt  5b      @ }       \n"
1577
  "sub  r0, r0, r7    @ src -= back     \n"
1578
  "adds r5, r5, #1<<8   @ yy--        \n"
1579
  "blt  4b      @ }       \n"
1580
  "mov  r14,r14,LSR r4    @ r14 = v >>= factor    \n"
1581
  "strb r14,[r9], #1    @ *d++ = r14      \n"
1582
  "sub  r0, r0, r8    @ s -= back2      \n"
1583
  "subs r5, r5, #1    @ n--       \n"
1584
  "bgt  3b      @ }       \n"
1585
  "add  r0, r0, r12   @ s += fwd2     \n"
1586
  "subs r1, r1, r3    @ x -= f      \n"
1587
  "bge  2b      @ }       \n"
1588
  "6:       @ Less than a full column left  \n"
1589
  "adds r1, r1, r3    @ x += f      \n"
1590
  "beq  11f     @ if (x == 0) next row    \n"
1591
  "@ r0 = src             \n"
1592
  "@ r1 = x             \n"
1593
  "@ r2 = y             \n"
1594
  "@ r3 = f             \n"
1595
  "@ r4 = factor              \n"
1596
  "@ r6 = fwd             \n"
1597
  "@ r7 = back              \n"
1598
  "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1599
  "ldr  r5, [r13,#4*11]   @ for (nn = n; nn > 0; n--) { \n"
1600
  "ldr  r4, [r13,#4*16]   @ r4 = divX     \n"
1601
  "ldr  r8, [r13,#4*17]   @ r8 = back4      \n"
1602
  "ldr  r12,[r13,#4*18]   @ r12= fwd4     \n"
1603
  "8:       @       \n"
1604
  "mov  r14,#0      @ r14= v = 0      \n"
1605
  "sub  r5, r5, r1, LSL #8  @ for (xx = x; xx > 0; x--) { \n"
1606
  "9:       @       \n"
1607
  "add  r5, r5, r3, LSL #16 @ for (yy = f; yy > 0; y--) { \n"
1608
  "10:        @       \n"
1609
  "ldrb r11,[r0], r6    @ r11= *src src += fwd  \n"
1610
  "subs r5, r5, #1<<16    @ xx--        \n"
1611
  "add  r14,r14,r11   @ v += r11      \n"
1612
  "bgt  10b     @ }       \n"
1613
  "sub  r0, r0, r7    @ src -= back     \n"
1614
  "adds r5, r5, #1<<8   @ yy--        \n"
1615
  "blt  9b      @ }       \n"
1616
  "mul  r14,r4, r14   @ r14= v *= divX    \n"
1617
  "mov  r14,r14,LSR #16   @ r14= v >>= 16     \n"
1618
  "strb r14,[r9], #1    @ *d++ = r14      \n"
1619
  "sub  r0, r0, r8    @ s -= back4      \n"
1620
  "subs r5, r5, #1    @ n--       \n"
1621
  "bgt  8b      @ }       \n"
1622
  "add  r0, r0, r12   @ s += fwd4     \n"
1623
  "11:        @       \n"
1624
  "ldr  r14,[r13,#4*19]   @ r14 = fwd3      \n"
1625
  "subs r2, r2, r3    @ h -= f      \n"
1626
  "add  r0, r0, r14   @ s += fwd3     \n"
1627
  "bge  1b      @ }       \n"
1628
  "12:                \n"
1629
  "adds r2, r2, r3    @ h += f      \n"
1630
  "beq  21f     @ if no stray row, end    \n"
1631
  "@ So doing one last (partial) row        \n"
1632
  "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1633
  "@ r0 = src = ptr           \n"
1634
  "@ r1 = w             \n"
1635
  "@ r2 = h             \n"
1636
  "@ r3 = f             \n"
1637
  "@ r4 = factor              \n"
1638
  "@ r5 = n             \n"
1639
  "@ r6 = fwd             \n"
1640
  "       @ for (y = h; y > 0; y--) { \n"
1641
  "ldr  r1, [r13]   @ r1 = w      \n"
1642
  "ldr  r7, [r13,#4*21]   @ r7 = back5      \n"
1643
  "ldr  r8, [r13,#4*14]   @ r8 = back2      \n"
1644
  "subs r1, r1, r3    @ r1 = w -= f     \n"
1645
  "blt  17f     @ Skip if less than a full col  \n"
1646
  "ldr  r4, [r13,#4*20]   @ r4 = divY     \n"
1647
  "ldr  r12,[r13,#4*15]   @ r12= fwd2     \n"
1648
  "13:        @ for (x = w; x > 0; x--) { \n"
1649
  "ldr  r5, [r13,#4*11]   @ for (nn = n; nn > 0; n--) { \n"
1650
  "14:        @       \n"
1651
  "mov  r14,#0      @ r14= v = 0      \n"
1652
  "sub  r5, r5, r3, LSL #8  @ for (xx = f; xx > 0; x--) { \n"
1653
  "15:        @       \n"
1654
  "add  r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n"
1655
  "16:        @       \n"
1656
  "ldrb r11,[r0], r6    @ r11= *src src += fwd  \n"
1657
  "subs r5, r5, #1<<16    @ xx--        \n"
1658
  "add  r14,r14,r11   @ v += r11      \n"
1659
  "bgt  16b     @ }       \n"
1660
  "sub  r0, r0, r7    @ src -= back5      \n"
1661
  "adds r5, r5, #1<<8   @ yy--        \n"
1662
  "blt  15b     @ }       \n"
1663
  "mul  r14,r4, r14   @ r14 = x *= divY   \n"
1664
  "mov  r14,r14,LSR #16   @ r14 = v >>= 16    \n"
1665
  "strb r14,[r9], #1    @ *d++ = r14      \n"
1666
  "sub  r0, r0, r8    @ s -= back2      \n"
1667
  "subs r5, r5, #1    @ n--       \n"
1668
  "bgt  14b     @ }       \n"
1669
  "add  r0, r0, r12   @ s += fwd2     \n"
1670
  "subs r1, r1, r3    @ x -= f      \n"
1671
  "bge  13b     @ }       \n"
1672
  "17:        @ Less than a full column left  \n"
1673
  "adds r1, r1, r3    @ x += f      \n"
1674
  "beq  21f     @ if (x == 0) end   \n"
1675
  "@ r0 = src             \n"
1676
  "@ r1 = x             \n"
1677
  "@ r2 = y             \n"
1678
  "@ r3 = f             \n"
1679
  "@ r4 = factor              \n"
1680
  "@ r6 = fwd             \n"
1681
  "@ r7 = back5             \n"
1682
  "@ r8 = back2             \n"
1683
  "@STACK:r1,<9>,factor,n,fwd,back,back2,fwd2,divX,back4,fwd4,fwd3,divY,back5,divXY\n"
1684
  "ldr  r4, [r13,#4*22]   @ r4 = divXY      \n"
1685
  "ldr  r5, [r13,#4*11]   @ for (nn = n; nn > 0; n--) { \n"
1686
  "ldr  r8, [r13,#4*17]   @ r8 = back4      \n"
1687
  "18:        @       \n"
1688
  "mov  r14,#0      @ r14= v = 0      \n"
1689
  "sub  r5, r5, r1, LSL #8  @ for (xx = x; xx > 0; x--) { \n"
1690
  "19:        @       \n"
1691
  "add  r5, r5, r2, LSL #16 @ for (yy = y; yy > 0; y--) { \n"
1692
  "20:        @       \n"
1693
  "ldrb r11,[r0],r6   @ r11= *src src += fwd  \n"
1694
  "subs r5, r5, #1<<16    @ xx--        \n"
1695
  "add  r14,r14,r11   @ v += r11      \n"
1696
  "bgt  20b     @ }       \n"
1697
  "sub  r0, r0, r7    @ src -= back5      \n"
1698
  "adds r5, r5, #1<<8   @ yy--        \n"
1699
  "blt  19b     @ }       \n"
1700
  "mul  r14,r4, r14   @ r14= v *= divX    \n"
1701
  "mov  r14,r14,LSR #16   @ r14= v >>= 16     \n"
1702
  "strb r14,[r9], #1    @ *d++ = r14      \n"
1703
  "sub  r0, r0, r8    @ s -= back4      \n"
1704
  "subs r5, r5, #1    @ n--       \n"
1705
  "bgt  18b     @ }       \n"
1706
  "21:        @       \n"
1707
  "ldmfd  r13!,{r1,r4-r11,PC} @ pop, return to thumb    \n"
1708
  ENTER_THUMB
1709
  );
1710
}
1711
1712
#endif
1713
1714
void
1715
fz_subsample_pixblock_bresenham(unsigned char *s2, int w, int h, int n, int factor, ptrdiff_t stride, int subx, int suby)
1716
0
{
1717
0
  int fwd, fwd2, back, back2;
1718
0
  unsigned char *d;
1719
0
  int x, y, xx, yy, nn;
1720
0
  int f = 1<<factor;
1721
1722
  /* In ((w+subx)/f) - 1 blocks, we want to repeat a line subx times. */
1723
0
  int bxd = ((w+subx)/f) - 1;
1724
0
  int bxf = (bxd+1)>>1; /* Round up here, because we invert below. */
1725
0
  int byd = ((h+suby)/f) - 1;
1726
0
  int byf = (byd+1)>>1; /* Round up here, because we invert below. */
1727
1728
0
  assert(0 <= bxf && bxf <= bxd);
1729
0
  assert(0 <= byf && byf <= byd);
1730
  /* And invert to make tests be against 0 */
1731
0
  bxf = bxd - bxf;
1732
0
  byf = byd - byf;
1733
1734
0
  d = s2;
1735
0
  fwd = stride;   /* Every pixel we step stride forwards */
1736
0
  back = f*fwd-n;   /* After f pixels we step back backwards (leaving us advanced by n) */
1737
0
  back2 = f*n-1;    /* After f columns we step back2 backwards (leaving us advanced by 1) */
1738
0
  fwd2 = (f-1)*n;   /* After n components we step fwd2 forwards (leaving us advanced by f*n) */
1739
0
  factor *= 2;
1740
0
  for (y = h; y > 0; y -= f)
1741
0
  {
1742
0
    int bxf2 = bxf;
1743
0
    unsigned char *s = s2;
1744
0
    for (x = w; x > 0; x -= f)
1745
0
    {
1746
0
      for (nn = n; nn > 0; nn--)
1747
0
      {
1748
0
        int v = 0;
1749
0
        for (xx = f; xx > 0; xx--)
1750
0
        {
1751
0
          for (yy = f; yy > 0; yy--)
1752
0
          {
1753
0
            v += *s;
1754
0
            s += fwd;
1755
0
          }
1756
0
          s -= back;
1757
0
        }
1758
0
        *d++ = v >> factor;
1759
0
        s -= back2;
1760
0
      }
1761
0
      s += fwd2;
1762
0
      bxf2 -= subx;
1763
0
      while (bxf2 < 0)
1764
0
      {
1765
0
        s -= n;
1766
0
        bxf2 += bxd;
1767
0
      }
1768
0
    }
1769
0
    s2 += stride * f;
1770
0
    byf -= suby;
1771
0
    while (byf < 0)
1772
0
    {
1773
0
      s2 -= stride;
1774
0
      byf += byd;
1775
0
    }
1776
0
  }
1777
0
}
1778
1779
void
1780
fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor)
1781
0
{
1782
0
  int f;
1783
0
  int subx, suby;
1784
1785
0
  if (!tile)
1786
0
    return;
1787
1788
0
  assert(tile->stride >= tile->w * tile->n);
1789
1790
0
  subx = (tile->w % (1<<factor));
1791
0
  suby = (tile->h % (1<<factor));
1792
0
  if ((subx != 0 || suby != 0) && tile->w >= (1<<factor) && tile->h >= (1<<factor))
1793
0
  {
1794
    /* Imagine that I've got a 61x61 image that we want to subsample
1795
     * by an l2factor of 2 (1<<2 == 4). Naively we'd treat it as a
1796
     * 64x64 image and shrink it to a 16x16 one. This would mean that
1797
     * the last column/row in the output came from a single pixel,
1798
     * and everything internally felt like it shifted up and left
1799
     * slightly.
1800
     *
1801
     * Naive:
1802
     *   INPUT:  0  1  2  3 ... 56 57 58 59 60 60 60 60
1803
     *   OUTPUT: <--  0 -->     <--  14 --> <--  15 -->
1804
     *
1805
     * Smarter:
1806
     *   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
1807
     *  OUTPUT:  <--  0 -->     <--  3  -->                       <--  8  -->     <--  11 -->
1808
     *                                   <--  4  -->     <--  7  -->                       <--  12 -->     <--  15 -->
1809
     *
1810
     * So 15, 33, and 48 are used twice.
1811
     */
1812
0
    subx = subx ? (1<<factor) - subx : 0;
1813
0
    suby = suby ? (1<<factor) - suby : 0;
1814
0
    fz_subsample_pixblock_bresenham(tile->samples, tile->w, tile->h, tile->n, factor, tile->stride, subx, suby);
1815
0
  }
1816
0
  else
1817
0
    fz_subsample_pixblock(tile->samples, tile->w, tile->h, tile->n, factor, tile->stride);
1818
1819
0
  f = 1<<factor;
1820
0
  tile->w = (tile->w + f-1)>>factor;
1821
0
  tile->h = (tile->h + f-1)>>factor;
1822
0
  tile->stride = tile->w * (size_t)tile->n;
1823
  /* Redundant test? We only ever make pixmaps smaller! */
1824
0
  if (tile->h > INT_MAX / (tile->w * tile->n))
1825
0
    fz_throw(ctx, FZ_ERROR_LIMIT, "pixmap too large");
1826
0
  tile->samples = fz_realloc(ctx, tile->samples, (size_t)tile->h * tile->w * tile->n);
1827
0
}
1828
1829
void
1830
fz_subsample_pixblock(unsigned char *s, int w, int h, int n, int factor, ptrdiff_t stride)
1831
217k
{
1832
217k
  int fwd, fwd2, fwd3, back, back2, f;
1833
217k
  unsigned char *d;
1834
217k
#ifndef ARCH_ARM
1835
217k
  int x, y, xx, yy, nn;
1836
217k
#endif
1837
1838
217k
  d = s;
1839
217k
  f = 1<<factor;
1840
217k
  fwd = stride;
1841
217k
  back = f*fwd-n;
1842
217k
  back2 = f*n-1;
1843
217k
  fwd2 = (f-1)*n;
1844
217k
  fwd3 = (f-1)*fwd + (int)stride - w * n;
1845
217k
  factor *= 2;
1846
#ifdef ARCH_ARM
1847
  {
1848
    int strayX = w%f;
1849
    int divX = (strayX ? 65536/(strayX*f) : 0);
1850
    int fwd4 = (strayX-1) * n;
1851
    int back4 = strayX*n-1;
1852
    int strayY = h%f;
1853
    int divY = (strayY ? 65536/(strayY*f) : 0);
1854
    int back5 = fwd * strayY - n;
1855
    int divXY = (strayY*strayX ? 65536/(strayX*strayY) : 0);
1856
    fz_subsample_pixmap_ARM(s, w, h, f, factor, n, fwd, back,
1857
          back2, fwd2, divX, back4, fwd4, fwd3,
1858
          divY, back5, divXY);
1859
  }
1860
#else
1861
432k
  for (y = h - f; y >= 0; y -= f)
1862
215k
  {
1863
7.38M
    for (x = w - f; x >= 0; x -= f)
1864
7.17M
    {
1865
21.1M
      for (nn = n; nn > 0; nn--)
1866
13.9M
      {
1867
13.9M
        int v = 0;
1868
42.0M
        for (xx = f; xx > 0; xx--)
1869
28.1M
        {
1870
85.5M
          for (yy = f; yy > 0; yy--)
1871
57.4M
          {
1872
57.4M
            v += *s;
1873
57.4M
            s += fwd;
1874
57.4M
          }
1875
28.1M
          s -= back;
1876
28.1M
        }
1877
13.9M
        *d++ = v >> factor;
1878
13.9M
        s -= back2;
1879
13.9M
      }
1880
7.17M
      s += fwd2;
1881
7.17M
    }
1882
    /* Do any strays */
1883
215k
    x += f;
1884
215k
    if (x > 0)
1885
208k
    {
1886
208k
      int div = x * f;
1887
208k
      int fwd4 = (x-1) * n;
1888
208k
      int back4 = x*n-1;
1889
631k
      for (nn = n; nn > 0; nn--)
1890
423k
      {
1891
423k
        int v = 0;
1892
847k
        for (xx = x; xx > 0; xx--)
1893
423k
        {
1894
1.27M
          for (yy = f; yy > 0; yy--)
1895
848k
          {
1896
848k
            v += *s;
1897
848k
            s += fwd;
1898
848k
          }
1899
423k
          s -= back;
1900
423k
        }
1901
423k
        *d++ = v / div;
1902
423k
        s -= back4;
1903
423k
      }
1904
208k
      s += fwd4;
1905
208k
    }
1906
215k
    s += fwd3;
1907
215k
  }
1908
  /* Do any stray line */
1909
217k
  y += f;
1910
217k
  if (y > 0)
1911
1.62k
  {
1912
1.62k
    int div = y * f;
1913
1.62k
    int back5 = fwd * y - n;
1914
51.4k
    for (x = w - f; x >= 0; x -= f)
1915
49.8k
    {
1916
149k
      for (nn = n; nn > 0; nn--)
1917
99.7k
      {
1918
99.7k
        int v = 0;
1919
299k
        for (xx = f; xx > 0; xx--)
1920
200k
        {
1921
400k
          for (yy = y; yy > 0; yy--)
1922
200k
          {
1923
200k
            v += *s;
1924
200k
            s += fwd;
1925
200k
          }
1926
200k
          s -= back5;
1927
200k
        }
1928
99.7k
        *d++ = v / div;
1929
99.7k
        s -= back2;
1930
99.7k
      }
1931
49.8k
      s += fwd2;
1932
49.8k
    }
1933
    /* Do any stray at the end of the stray line */
1934
1.62k
    x += f;
1935
1.62k
    if (x > 0)
1936
1.46k
    {
1937
1.46k
      int back4 = x * n - 1;
1938
1.46k
      div = x * y;
1939
4.42k
      for (nn = n; nn > 0; nn--)
1940
2.96k
      {
1941
2.96k
        int v = 0;
1942
5.93k
        for (xx = x; xx > 0; xx--)
1943
2.96k
        {
1944
5.93k
          for (yy = y; yy > 0; yy--)
1945
2.96k
          {
1946
2.96k
            v += *s;
1947
2.96k
            s += fwd;
1948
2.96k
          }
1949
2.96k
          s -= back5;
1950
2.96k
        }
1951
2.96k
        *d++ = v / div;
1952
2.96k
        s -= back4;
1953
2.96k
      }
1954
1.46k
    }
1955
1.62k
  }
1956
217k
#endif
1957
217k
}
1958
1959
void
1960
fz_set_pixmap_resolution(fz_context *ctx, fz_pixmap *pix, int xres, int yres)
1961
0
{
1962
0
  pix->xres = xres;
1963
0
  pix->yres = yres;
1964
0
}
1965
1966
/*
1967
  Return the md5 digest for a pixmap
1968
*/
1969
void
1970
fz_md5_pixmap(fz_context *ctx, fz_pixmap *pix, unsigned char digest[16])
1971
0
{
1972
0
  fz_md5 md5;
1973
1974
0
  fz_md5_init(&md5);
1975
0
  if (pix)
1976
0
  {
1977
0
    unsigned char *s = pix->samples;
1978
0
    int h = pix->h;
1979
0
    int ss = pix->stride;
1980
0
    int len = pix->w * pix->n;
1981
0
    while (h--)
1982
0
    {
1983
0
      fz_md5_update(&md5, s, len);
1984
0
      s += ss;
1985
0
    }
1986
0
  }
1987
0
  fz_md5_final(&md5, digest);
1988
0
}
1989
1990
#ifdef HAVE_VALGRIND
1991
int fz_valgrind_pixmap(const fz_pixmap *pix)
1992
{
1993
  int w, h, n, total;
1994
  int ww, hh, nn;
1995
  int stride;
1996
  const unsigned char *p = pix->samples;
1997
1998
  if (pix == NULL)
1999
    return 0;
2000
2001
  total = 0;
2002
  ww = pix->w;
2003
  hh = pix->h;
2004
  nn = pix->n;
2005
  stride = pix->stride - ww*nn;
2006
  for (h = 0; h < hh; h++)
2007
  {
2008
    for (w = 0; w < ww; w++)
2009
      for (n = 0; n < nn; n++)
2010
        if (*p++) total ++;
2011
    p += stride;
2012
  }
2013
  return total;
2014
}
2015
#endif /* HAVE_VALGRIND */
2016
2017
fz_pixmap *
2018
fz_convert_indexed_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
2019
0
{
2020
0
  fz_pixmap *dst;
2021
0
  fz_colorspace *base;
2022
0
  const unsigned char *s;
2023
0
  unsigned char *d;
2024
0
  int y, x, k, n, high;
2025
0
  unsigned char *lookup;
2026
0
  ptrdiff_t s_line_inc, d_line_inc;
2027
2028
0
  if (src->colorspace->type != FZ_COLORSPACE_INDEXED)
2029
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot convert non-indexed pixmap");
2030
0
  if (src->n != 1 + src->alpha)
2031
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot convert indexed pixmap mis-matching components");
2032
2033
0
  base = src->colorspace->u.indexed.base;
2034
0
  high = src->colorspace->u.indexed.high;
2035
0
  lookup = src->colorspace->u.indexed.lookup;
2036
0
  n = base->n;
2037
2038
0
  dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
2039
0
  s = src->samples;
2040
0
  d = dst->samples;
2041
0
  s_line_inc = src->stride - src->w * (ptrdiff_t)src->n;
2042
0
  d_line_inc = dst->stride - dst->w * (ptrdiff_t)dst->n;
2043
2044
0
  if (src->alpha)
2045
0
  {
2046
0
    for (y = 0; y < src->h; y++)
2047
0
    {
2048
0
      for (x = 0; x < src->w; x++)
2049
0
      {
2050
0
        int v = *s++;
2051
0
        int a = *s++;
2052
0
        int aa = a + (a>>7);
2053
0
        v = fz_mini(v, high);
2054
0
        for (k = 0; k < n; k++)
2055
0
          *d++ = (aa * lookup[v * n + k] + 128)>>8;
2056
0
        *d++ = a;
2057
0
      }
2058
0
      s += s_line_inc;
2059
0
      d += d_line_inc;
2060
0
    }
2061
0
  }
2062
0
  else
2063
0
  {
2064
0
    for (y = 0; y < src->h; y++)
2065
0
    {
2066
0
      for (x = 0; x < src->w; x++)
2067
0
      {
2068
0
        int v = *s++;
2069
0
        v = fz_mini(v, high);
2070
0
        for (k = 0; k < n; k++)
2071
0
          *d++ = lookup[v * n + k];
2072
0
      }
2073
0
      s += s_line_inc;
2074
0
      d += d_line_inc;
2075
0
    }
2076
0
  }
2077
2078
0
  if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
2079
0
    dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
2080
0
  else
2081
0
    dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
2082
2083
0
  return dst;
2084
0
}
2085
2086
fz_pixmap *
2087
fz_convert_separation_pixmap_to_base(fz_context *ctx, const fz_pixmap *src)
2088
0
{
2089
0
  fz_pixmap *dst;
2090
0
  fz_colorspace *ss, *base;
2091
0
  const unsigned char *s;
2092
0
  unsigned char *d;
2093
0
  int y, x, k, sn, bn, a;
2094
0
  float src_v[FZ_MAX_COLORS];
2095
0
  float base_v[FZ_MAX_COLORS];
2096
0
  ptrdiff_t s_line_inc, d_line_inc;
2097
2098
0
  ss = src->colorspace;
2099
2100
0
  if (ss->type != FZ_COLORSPACE_SEPARATION)
2101
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot expand non-separation pixmap");
2102
0
  if (src->n != ss->n + src->alpha)
2103
0
    fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot expand separation pixmap mis-matching alpha channel");
2104
2105
0
  base = ss->u.separation.base;
2106
0
  dst = fz_new_pixmap_with_bbox(ctx, base, fz_pixmap_bbox(ctx, src), src->seps, src->alpha);
2107
0
  fz_clear_pixmap(ctx, dst);
2108
0
  fz_try(ctx)
2109
0
  {
2110
0
    s = src->samples;
2111
0
    d = dst->samples;
2112
0
    s_line_inc = src->stride - src->w * (ptrdiff_t)src->n;
2113
0
    d_line_inc = dst->stride - dst->w * (ptrdiff_t)dst->n;
2114
0
    sn = ss->n;
2115
0
    bn = base->n;
2116
2117
0
    if (base->type == FZ_COLORSPACE_LAB)
2118
0
    {
2119
0
      if (src->alpha)
2120
0
      {
2121
0
        for (y = 0; y < src->h; y++)
2122
0
        {
2123
0
          for (x = 0; x < src->w; x++)
2124
0
          {
2125
0
            for (k = 0; k < sn; ++k)
2126
0
              src_v[k] = *s++ / 255.0f;
2127
0
            a = *s++;
2128
0
            ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
2129
0
            *d++ = (base_v[0] / 100) * 255.0f;
2130
0
            *d++ = base_v[1] + 128;
2131
0
            *d++ = base_v[2] + 128;
2132
0
            *d++ = a;
2133
0
          }
2134
0
          s += s_line_inc;
2135
0
          d += d_line_inc;
2136
0
        }
2137
0
      }
2138
0
      else
2139
0
      {
2140
0
        for (y = 0; y < src->h; y++)
2141
0
        {
2142
0
          for (x = 0; x < src->w; x++)
2143
0
          {
2144
0
            for (k = 0; k < sn; ++k)
2145
0
              src_v[k] = *s++ / 255.0f;
2146
0
            ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
2147
0
            *d++ = (base_v[0] / 100) * 255.0f;
2148
0
            *d++ = base_v[1] + 128;
2149
0
            *d++ = base_v[2] + 128;
2150
0
          }
2151
0
          s += s_line_inc;
2152
0
          d += d_line_inc;
2153
0
        }
2154
0
      }
2155
0
    }
2156
0
    else
2157
0
    {
2158
0
      if (src->alpha)
2159
0
      {
2160
0
        for (y = 0; y < src->h; y++)
2161
0
        {
2162
0
          for (x = 0; x < src->w; x++)
2163
0
          {
2164
0
            for (k = 0; k < sn; ++k)
2165
0
              src_v[k] = *s++ / 255.0f;
2166
0
            a = *s++;
2167
0
            ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
2168
0
            for (k = 0; k < bn; ++k)
2169
0
              *d++ = base_v[k] * 255.0f;
2170
0
            *d++ = a;
2171
0
          }
2172
0
          s += s_line_inc;
2173
0
          d += d_line_inc;
2174
0
        }
2175
0
      }
2176
0
      else
2177
0
      {
2178
0
        for (y = 0; y < src->h; y++)
2179
0
        {
2180
0
          for (x = 0; x < src->w; x++)
2181
0
          {
2182
0
            for (k = 0; k < sn; ++k)
2183
0
              src_v[k] = *s++ / 255.0f;
2184
0
            ss->u.separation.eval(ctx, ss->u.separation.tint, src_v, sn, base_v, bn);
2185
0
            for (k = 0; k < bn; ++k)
2186
0
              *d++ = base_v[k] * 255.0f;
2187
0
          }
2188
0
          s += s_line_inc;
2189
0
          d += d_line_inc;
2190
0
        }
2191
0
      }
2192
0
    }
2193
2194
0
    if (src->flags & FZ_PIXMAP_FLAG_INTERPOLATE)
2195
0
      dst->flags |= FZ_PIXMAP_FLAG_INTERPOLATE;
2196
0
    else
2197
0
      dst->flags &= ~FZ_PIXMAP_FLAG_INTERPOLATE;
2198
0
  }
2199
0
  fz_catch(ctx)
2200
0
  {
2201
0
    fz_drop_pixmap(ctx, dst);
2202
0
    fz_rethrow(ctx);
2203
0
  }
2204
2205
0
  return dst;
2206
0
}