• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

saitoha / libsixel / 19104006818

05 Nov 2025 01:09PM UTC coverage: 46.362% (+0.4%) from 45.985%
19104006818

push

github

saitoha
diffusion: drop diffusion methods lso1/lso3

7791 of 25105 branches covered (31.03%)

1 of 3 new or added lines in 1 file covered. (33.33%)

11126 of 23998 relevant lines covered (46.36%)

1682494.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

38.06
/src/quant.c
1
/*
2
 *
3
 * mediancut algorithm implementation is imported from pnmcolormap.c
4
 * in netpbm library.
5
 * http://netpbm.sourceforge.net/
6
 *
7
 * *******************************************************************************
8
 *                  original license block of pnmcolormap.c
9
 * *******************************************************************************
10
 *
11
 *   Derived from ppmquant, originally by Jef Poskanzer.
12
 *
13
 *   Copyright (C) 1989, 1991 by Jef Poskanzer.
14
 *   Copyright (C) 2001 by Bryan Henderson.
15
 *
16
 *   Permission to use, copy, modify, and distribute this software and its
17
 *   documentation for any purpose and without fee is hereby granted, provided
18
 *   that the above copyright notice appear in all copies and that both that
19
 *   copyright notice and this permission notice appear in supporting
20
 *   documentation.  This software is provided "as is" without express or
21
 *   implied warranty.
22
 *
23
 * ******************************************************************************
24
 *
25
 * Copyright (c) 2014-2018 Hayaki Saito
26
 *
27
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
28
 * this software and associated documentation files (the "Software"), to deal in
29
 * the Software without restriction, including without limitation the rights to
30
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
31
 * the Software, and to permit persons to whom the Software is furnished to do so,
32
 * subject to the following conditions:
33
 *
34
 * The above copyright notice and this permission notice shall be included in all
35
 * copies or substantial portions of the Software.
36
 *
37
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
39
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
40
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
41
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
42
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43
 *
44
 *
45
 */
46

47
#include "config.h"
48

49
/* STDC_HEADERS */
50
#include <stdlib.h>
51
#include <stdio.h>
52
#include <time.h>
53

54
#if HAVE_STRING_H
55
# include <string.h>
56
#endif  /* HAVE_STRING_H */
57
#if HAVE_MATH_H
58
#include <math.h>
59
#endif  /* HAVE_MATH_H */
60
#if HAVE_LIMITS_H
61
# include <limits.h>
62
#endif  /* HAVE_MATH_H */
63
#if HAVE_STDINT_H
64
# include <stdint.h>
65
#else
66
# if HAVE_INTTYPES_H
67
#  include <inttypes.h>
68
# endif
69
#endif  /* HAVE_STDINT_H */
70

71
#if defined(SIXEL_USE_SSE2)
72
# include <emmintrin.h>
73
# include <xmmintrin.h>
74
#elif defined(SIXEL_USE_NEON)
75
# include <arm_neon.h>
76
#endif
77

78
#include "quant.h"
79
#include "compat_stub.h"
80

81
static unsigned char const sixel_reversible_tones[101] = {
82
     0,  3,  5,  8, 10, 13, 15, 18, 20, 23,
83
    26, 28, 31, 33, 36, 38, 41, 43, 46, 48,
84
    51, 54, 56, 59, 61, 64, 66, 69, 71, 74,
85
    77, 79, 82, 84, 87, 89, 92, 94, 97, 99,
86
   102, 105, 107, 110, 112, 115, 117, 120, 122, 125,
87
   128, 130, 133, 135, 138, 140, 143, 145, 148, 150,
88
   153, 156, 158, 161, 163, 166, 168, 171, 173, 176,
89
   179, 181, 184, 186, 189, 191, 194, 196, 199, 201,
90
   204, 207, 209, 212, 214, 217, 219, 222, 224, 227,
91
   230, 232, 235, 237, 240, 242, 245, 247, 250, 252,
92
   255
93
};
94

95
static float mask_a(int x, int y, int c);
96
static float mask_x(int x, int y, int c);
97
static void diffuse_none(unsigned char *data, int width, int height,
98
                         int x, int y, int depth, int error, int direction);
99
static void diffuse_fs(unsigned char *data, int width, int height,
100
                       int x, int y, int depth, int error, int direction);
101
static void diffuse_atkinson(unsigned char *data, int width, int height,
102
                             int x, int y, int depth, int error,
103
                             int direction);
104
static void diffuse_jajuni(unsigned char *data, int width, int height,
105
                           int x, int y, int depth, int error,
106
                           int direction);
107
static void diffuse_stucki(unsigned char *data, int width, int height,
108
                           int x, int y, int depth, int error,
109
                           int direction);
110
static void diffuse_burkes(unsigned char *data, int width, int height,
111
                           int x, int y, int depth, int error,
112
                           int direction);
113
static void diffuse_sierra1(unsigned char *data, int width, int height,
114
                            int x, int y, int depth, int error,
115
                            int direction);
116
static void diffuse_sierra2(unsigned char *data, int width, int height,
117
                            int x, int y, int depth, int error,
118
                            int direction);
119
static void diffuse_sierra3(unsigned char *data, int width, int height,
120
                            int x, int y, int depth, int error,
121
                            int direction);
122
static void diffuse_none_carry(int32_t *carry_curr, int32_t *carry_next,
123
                               int32_t *carry_far, int width, int height,
124
                               int depth, int x, int y, int32_t error,
125
                               int direction, int channel);
126
static void diffuse_fs_carry(int32_t *carry_curr, int32_t *carry_next,
127
                             int32_t *carry_far, int width, int height,
128
                             int depth, int x, int y, int32_t error,
129
                             int direction, int channel);
130
static void diffuse_atkinson_carry(int32_t *carry_curr, int32_t *carry_next,
131
                                   int32_t *carry_far, int width,
132
                                   int height, int depth, int x, int y,
133
                                   int32_t error, int direction,
134
                                   int channel);
135
static void diffuse_jajuni_carry(int32_t *carry_curr, int32_t *carry_next,
136
                                 int32_t *carry_far, int width, int height,
137
                                 int depth, int x, int y, int32_t error,
138
                                 int direction, int channel);
139
static void diffuse_stucki_carry(int32_t *carry_curr, int32_t *carry_next,
140
                                 int32_t *carry_far, int width, int height,
141
                                 int depth, int x, int y, int32_t error,
142
                                 int direction, int channel);
143
static void diffuse_burkes_carry(int32_t *carry_curr, int32_t *carry_next,
144
                                 int32_t *carry_far, int width, int height,
145
                                 int depth, int x, int y, int32_t error,
146
                                 int direction, int channel);
147
static void diffuse_sierra1_carry(int32_t *carry_curr, int32_t *carry_next,
148
                                  int32_t *carry_far, int width, int height,
149
                                  int depth, int x, int y, int32_t error,
150
                                  int direction, int channel);
151
static void diffuse_sierra2_carry(int32_t *carry_curr, int32_t *carry_next,
152
                                  int32_t *carry_far, int width, int height,
153
                                  int depth, int x, int y, int32_t error,
154
                                  int direction, int channel);
155
static void diffuse_sierra3_carry(int32_t *carry_curr, int32_t *carry_next,
156
                                  int32_t *carry_far, int width, int height,
157
                                  int depth, int x, int y, int32_t error,
158
                                  int direction, int channel);
159

160
static const int (*
161
lso2_table(void))[7]
×
162
{
163
#include "lso2.h"
164
    return var_coefs;
165
}
166

167
#define VARERR_SCALE_SHIFT 12
168
#define VARERR_SCALE       (1 << VARERR_SCALE_SHIFT)
169
#define VARERR_ROUND       (1 << (VARERR_SCALE_SHIFT - 1))
170
#define VARERR_MAX_VALUE   (255 * VARERR_SCALE)
171

172
#if HAVE_DEBUG
173
#define quant_trace fprintf
174
#else
175
static inline void quant_trace(FILE *f, ...) { (void) f; }
176
#endif
177

178
/*****************************************************************************
179
 *
180
 * quantization
181
 *
182
 *****************************************************************************/
183

184
typedef struct box* boxVector;
185
struct box {
186
    unsigned int ind;
187
    unsigned int colors;
188
    unsigned int sum;
189
};
190

191
typedef unsigned long sample;
192
typedef sample * tuple;
193

194
static unsigned int
195
sixel_quant_reversible_index(unsigned int sample)
×
196
{
197
    unsigned int index;
198

199
    if (sample > 255U) {
×
200
        sample = 255U;
×
201
    }
202
    index = (sample * 100U + 127U) / 255U;
×
203
    if (index > 100U) {
×
204
        index = 100U;
×
205
    }
206

207
    return index;
×
208
}
209

210
static unsigned char
211
sixel_quant_reversible_value(unsigned int sample)
×
212
{
213
    unsigned int index;
214

215
    index = sixel_quant_reversible_index(sample);
×
216

217
    return sixel_reversible_tones[index];
×
218
}
219

220
static void
221
sixel_quant_reversible_pixel(unsigned char const *src,
×
222
                             unsigned int depth,
223
                             unsigned char *dst)
224
{
225
    unsigned int plane;
226

227
    for (plane = 0U; plane < depth; ++plane) {
×
228
        dst[plane] = sixel_quant_reversible_value(src[plane]);
×
229
    }
230
}
×
231

232
static void
233
sixel_quant_reversible_tuple(sample *tuple,
×
234
                             unsigned int depth)
235
{
236
    unsigned int plane;
237
    unsigned int sample_value;
238

239
    for (plane = 0U; plane < depth; ++plane) {
×
240
        sample_value = (unsigned int)tuple[plane];
×
241
        tuple[plane] =
×
242
            (sample)sixel_quant_reversible_value(sample_value);
×
243
    }
244
}
×
245

246
static void
247
sixel_quant_reversible_palette(unsigned char *palette,
×
248
                               unsigned int colors,
249
                               unsigned int depth)
250
{
251
    unsigned int index;
252
    unsigned int plane;
253
    unsigned int sample_value;
254
    size_t offset;
255

256
    for (index = 0U; index < colors; ++index) {
×
257
        for (plane = 0U; plane < depth; ++plane) {
×
258
            offset = (size_t)index * (size_t)depth + (size_t)plane;
×
259
            sample_value = (unsigned int)palette[offset];
×
260
            palette[offset] =
×
261
                sixel_quant_reversible_value(sample_value);
×
262
        }
263
    }
264
}
×
265

266
struct tupleint {
267
    /* An ordered pair of a tuple value and an integer, such as you
268
       would find in a tuple table or tuple hash.
269
       Note that this is a variable length structure.
270
    */
271
    unsigned int value;
272
    sample tuple[1];
273
    /* This is actually a variable size array -- its size is the
274
       depth of the tuple in question.  Some compilers do not let us
275
       declare a variable length array.
276
    */
277
};
278
typedef struct tupleint ** tupletable;
279

280
typedef struct {
281
    unsigned int size;
282
    tupletable table;
283
} tupletable2;
284

285
static unsigned int compareplanePlane;
286
static tupletable2 const *force_palette_source;
287
    /* This is a parameter to compareplane().  We use this global variable
288
       so that compareplane() can be called by qsort(), to compare two
289
       tuples.  qsort() doesn't pass any arguments except the two tuples.
290
    */
291
static int
292
compareplane(const void * const arg1,
11,191,943✔
293
             const void * const arg2)
294
{
295
    int lhs, rhs;
296

297
    typedef const struct tupleint * const * const sortarg;
298
    sortarg comparandPP  = (sortarg) arg1;
11,191,943✔
299
    sortarg comparatorPP = (sortarg) arg2;
11,191,943✔
300
    lhs = (int)(*comparandPP)->tuple[compareplanePlane];
11,191,943✔
301
    rhs = (int)(*comparatorPP)->tuple[compareplanePlane];
11,191,943✔
302

303
    return lhs - rhs;
11,191,943✔
304
}
305

306

307
static int
308
sumcompare(const void * const b1, const void * const b2)
8,300,637✔
309
{
310
    return (int)((boxVector)b2)->sum - (int)((boxVector)b1)->sum;
8,300,637✔
311
}
312

313

314
static SIXELSTATUS
315
alloctupletable(
520✔
316
    tupletable          /* out */ *result,
317
    unsigned int const  /* in */  depth,
318
    unsigned int const  /* in */  size,
319
    sixel_allocator_t   /* in */  *allocator)
320
{
321
    SIXELSTATUS status = SIXEL_FALSE;
520✔
322
    enum { message_buffer_size = 256 };
323
    char message[message_buffer_size];
324
    int nwrite;
325
    unsigned int mainTableSize;
326
    unsigned int tupleIntSize;
327
    unsigned int allocSize;
328
    void * pool;
329
    tupletable tbl;
330
    unsigned int i;
331

332
    if (UINT_MAX / sizeof(struct tupleint) < size) {
520!
333
        nwrite = sixel_compat_snprintf(
×
334
            message,
335
            sizeof(message),
336
            "size %u is too big for arithmetic",
337
            size);
338
        if (nwrite > 0) {
×
339
            sixel_helper_set_additional_message(message);
×
340
        }
341
        status = SIXEL_RUNTIME_ERROR;
×
342
        goto end;
×
343
    }
344

345
    mainTableSize = size * sizeof(struct tupleint *);
520✔
346
    tupleIntSize = sizeof(struct tupleint) - sizeof(sample)
520✔
347
        + depth * sizeof(sample);
236✔
348

349
    /* To save the enormous amount of time it could take to allocate
350
       each individual tuple, we do a trick here and allocate everything
351
       as a single malloc block and suballocate internally.
352
    */
353
    if ((UINT_MAX - mainTableSize) / tupleIntSize < size) {
520!
354
        nwrite = sixel_compat_snprintf(
×
355
            message,
356
            sizeof(message),
357
            "size %u is too big for arithmetic",
358
            size);
359
        if (nwrite > 0) {
×
360
            sixel_helper_set_additional_message(message);
×
361
        }
362
        status = SIXEL_RUNTIME_ERROR;
×
363
        goto end;
×
364
    }
365

366
    allocSize = mainTableSize + size * tupleIntSize;
520✔
367

368
    pool = sixel_allocator_malloc(allocator, allocSize);
520✔
369
    if (pool == NULL) {
520!
370
        sixel_compat_snprintf(
×
371
            message,
372
            sizeof(message),
373
            "unable to allocate %u bytes for a %u-entry tuple table",
374
            allocSize,
375
            size);
376
        sixel_helper_set_additional_message(message);
×
377
        status = SIXEL_BAD_ALLOCATION;
×
378
        goto end;
×
379
    }
380
    tbl = (tupletable) pool;
520✔
381

382
    for (i = 0; i < size; ++i)
311,397✔
383
        tbl[i] = (struct tupleint *)
310,877✔
384
            ((char*)pool + mainTableSize + i * tupleIntSize);
310,877✔
385

386
    *result = tbl;
520✔
387

388
    status = SIXEL_OK;
520✔
389

390
end:
284✔
391
    return status;
520✔
392
}
393

394

395
/*
396
** Here is the fun part, the median-cut colormap generator.  This is based
397
** on Paul Heckbert's paper "Color Image Quantization for Frame Buffer
398
** Display", SIGGRAPH '82 Proceedings, page 297.
399
*/
400

401
static tupletable2
402
newColorMap(unsigned int const newcolors, unsigned int const depth, sixel_allocator_t *allocator)
69✔
403
{
404
    SIXELSTATUS status = SIXEL_FALSE;
69✔
405
    tupletable2 colormap;
406
    unsigned int i;
407

408
    colormap.size = 0;
69✔
409
    status = alloctupletable(&colormap.table, depth, newcolors, allocator);
69✔
410
    if (SIXEL_FAILED(status)) {
69!
411
        goto end;
×
412
    }
413
    if (colormap.table) {
92!
414
        for (i = 0; i < newcolors; ++i) {
13,833✔
415
            unsigned int plane;
416
            for (plane = 0; plane < depth; ++plane)
55,056✔
417
                colormap.table[i]->tuple[plane] = 0;
41,292✔
418
        }
4,588✔
419
        colormap.size = newcolors;
69✔
420
    }
23✔
421

422
end:
423
    return colormap;
69✔
424
}
425

426

427
static boxVector
428
newBoxVector(
69✔
429
    unsigned int const  /* in */ colors,
430
    unsigned int const  /* in */ sum,
431
    unsigned int const  /* in */ newcolors,
432
    sixel_allocator_t   /* in */ *allocator)
433
{
434
    boxVector bv;
435

436
    bv = (boxVector)sixel_allocator_malloc(allocator,
92✔
437
                                           sizeof(struct box) * (size_t)newcolors);
69✔
438
    if (bv == NULL) {
69!
439
        quant_trace(stderr, "out of memory allocating box vector table\n");
×
440
        return NULL;
×
441
    }
442

443
    /* Set up the initial box. */
444
    bv[0].ind = 0;
69✔
445
    bv[0].colors = colors;
69✔
446
    bv[0].sum = sum;
69✔
447

448
    return bv;
69✔
449
}
23✔
450

451

452
static void
453
findBoxBoundaries(tupletable2  const colorfreqtable,
13,695✔
454
                  unsigned int const depth,
455
                  unsigned int const boxStart,
456
                  unsigned int const boxSize,
457
                  sample             minval[],
458
                  sample             maxval[])
459
{
460
/*----------------------------------------------------------------------------
461
  Go through the box finding the minimum and maximum of each
462
  component - the boundaries of the box.
463
-----------------------------------------------------------------------------*/
464
    unsigned int plane;
465
    unsigned int i;
466

467
    for (plane = 0; plane < depth; ++plane) {
54,780✔
468
        minval[plane] = colorfreqtable.table[boxStart]->tuple[plane];
41,085✔
469
        maxval[plane] = minval[plane];
41,085✔
470
    }
13,695✔
471

472
    for (i = 1; i < boxSize; ++i) {
1,958,613✔
473
        for (plane = 0; plane < depth; ++plane) {
7,779,672✔
474
            sample const v = colorfreqtable.table[boxStart + i]->tuple[plane];
5,834,754✔
475
            if (v < minval[plane]) minval[plane] = v;
5,834,754✔
476
            if (v > maxval[plane]) maxval[plane] = v;
5,834,754✔
477
        }
1,946,880✔
478
    }
648,960✔
479
}
13,695✔
480

481

482

483
static unsigned int
484
largestByNorm(sample minval[], sample maxval[], unsigned int const depth)
12,930✔
485
{
486

487
    unsigned int largestDimension;
488
    unsigned int plane;
489
    sample largestSpreadSoFar;
490

491
    largestSpreadSoFar = 0;
12,930✔
492
    largestDimension = 0;
12,930✔
493
    for (plane = 0; plane < depth; ++plane) {
51,720✔
494
        sample const spread = maxval[plane]-minval[plane];
38,790✔
495
        if (spread > largestSpreadSoFar) {
38,790✔
496
            largestDimension = plane;
22,629✔
497
            largestSpreadSoFar = spread;
22,629✔
498
        }
7,465✔
499
    }
12,930✔
500
    return largestDimension;
12,930✔
501
}
502

503

504

505
static unsigned int
506
largestByLuminosity(sample minval[], sample maxval[], unsigned int const depth)
765✔
507
{
508
/*----------------------------------------------------------------------------
509
   This subroutine presumes that the tuple type is either
510
   BLACKANDWHITE, GRAYSCALE, or RGB (which implies pamP->depth is 1 or 3).
511
   To save time, we don't actually check it.
512
-----------------------------------------------------------------------------*/
513
    unsigned int retval;
514

515
    double lumin_factor[3] = {0.2989, 0.5866, 0.1145};
765✔
516

517
    if (depth == 1) {
765!
518
        retval = 0;
×
519
    } else {
520
        /* An RGB tuple */
521
        unsigned int largestDimension;
522
        unsigned int plane;
523
        double largestSpreadSoFar;
524

525
        largestSpreadSoFar = 0.0;
765✔
526
        largestDimension = 0;
765✔
527

528
        for (plane = 0; plane < 3; ++plane) {
3,060✔
529
            double const spread =
2,295✔
530
                lumin_factor[plane] * (maxval[plane]-minval[plane]);
2,295✔
531
            if (spread > largestSpreadSoFar) {
2,295✔
532
                largestDimension = plane;
1,331✔
533
                largestSpreadSoFar = spread;
1,331✔
534
            }
451✔
535
        }
765✔
536
        retval = largestDimension;
765✔
537
    }
538
    return retval;
765✔
539
}
540

541

542

543
static void
544
centerBox(unsigned int const boxStart,
11,460✔
545
          unsigned int const boxSize,
546
          tupletable2  const colorfreqtable,
547
          unsigned int const depth,
548
          tuple        const newTuple)
549
{
550

551
    unsigned int plane;
552
    sample minval, maxval;
553
    unsigned int i;
554

555
    for (plane = 0; plane < depth; ++plane) {
45,840✔
556
        minval = maxval = colorfreqtable.table[boxStart]->tuple[plane];
34,380✔
557

558
        for (i = 1; i < boxSize; ++i) {
750,888✔
559
            sample v = colorfreqtable.table[boxStart + i]->tuple[plane];
716,508✔
560
            minval = minval < v ? minval: v;
716,508✔
561
            maxval = maxval > v ? maxval: v;
716,508✔
562
        }
238,518✔
563
        newTuple[plane] = (minval + maxval) / 2;
34,380✔
564
    }
11,460✔
565
}
11,460✔
566

567

568

569
static void
570
averageColors(unsigned int const boxStart,
768✔
571
              unsigned int const boxSize,
572
              tupletable2  const colorfreqtable,
573
              unsigned int const depth,
574
              tuple        const newTuple)
575
{
576
    unsigned int plane;
577
    sample sum;
578
    unsigned int i;
579

580
    for (plane = 0; plane < depth; ++plane) {
3,072✔
581
        sum = 0;
2,304✔
582

583
        for (i = 0; i < boxSize; ++i) {
43,962✔
584
            sum += colorfreqtable.table[boxStart + i]->tuple[plane];
41,658✔
585
        }
13,878✔
586

587
        newTuple[plane] = sum / boxSize;
2,304✔
588
    }
768✔
589
}
768✔
590

591

592

593
static void
594
averagePixels(unsigned int const boxStart,
1,536✔
595
              unsigned int const boxSize,
596
              tupletable2 const colorfreqtable,
597
              unsigned int const depth,
598
              tuple const newTuple)
599
{
600

601
    unsigned int n;
602
        /* Number of tuples represented by the box */
603
    unsigned int plane;
604
    unsigned int i;
605

606
    /* Count the tuples in question */
607
    n = 0;  /* initial value */
1,536✔
608
    for (i = 0; i < boxSize; ++i) {
28,453✔
609
        n += (unsigned int)colorfreqtable.table[boxStart + i]->value;
26,917✔
610
    }
8,937✔
611

612
    for (plane = 0; plane < depth; ++plane) {
6,144✔
613
        sample sum;
614

615
        sum = 0;
4,608✔
616

617
        for (i = 0; i < boxSize; ++i) {
85,359✔
618
            sum += colorfreqtable.table[boxStart + i]->tuple[plane]
107,562✔
619
                * (unsigned int)colorfreqtable.table[boxStart + i]->value;
80,751✔
620
        }
26,811✔
621

622
        newTuple[plane] = sum / n;
4,608✔
623
    }
1,536✔
624
}
1,536✔
625

626

627

628
static tupletable2
629
colormapFromBv(unsigned int const newcolors,
69✔
630
               boxVector const bv,
631
               unsigned int const boxes,
632
               tupletable2 const colorfreqtable,
633
               unsigned int const depth,
634
               int const methodForRep,
635
               int const use_reversible,
636
               sixel_allocator_t *allocator)
637
{
638
    /*
639
    ** Ok, we've got enough boxes.  Now choose a representative color for
640
    ** each box.  There are a number of possible ways to make this choice.
641
    ** One would be to choose the center of the box; this ignores any structure
642
    ** within the boxes.  Another method would be to average all the colors in
643
    ** the box - this is the method specified in Heckbert's paper.  A third
644
    ** method is to average all the pixels in the box.
645
    */
646
    tupletable2 colormap;
647
    unsigned int bi;
648

649
    colormap = newColorMap(newcolors, depth, allocator);
69✔
650
    if (!colormap.size) {
69!
651
        return colormap;
×
652
    }
653

654
    for (bi = 0; bi < boxes; ++bi) {
13,833✔
655
        switch (methodForRep) {
13,764!
656
        case SIXEL_REP_CENTER_BOX:
7,640✔
657
            centerBox(bv[bi].ind, bv[bi].colors,
15,280✔
658
                      colorfreqtable, depth,
3,820✔
659
                      colormap.table[bi]->tuple);
11,460✔
660
            break;
11,460✔
661
        case SIXEL_REP_AVERAGE_COLORS:
512✔
662
            averageColors(bv[bi].ind, bv[bi].colors,
1,024✔
663
                          colorfreqtable, depth,
256✔
664
                          colormap.table[bi]->tuple);
768✔
665
            break;
768✔
666
        case SIXEL_REP_AVERAGE_PIXELS:
1,024✔
667
            averagePixels(bv[bi].ind, bv[bi].colors,
2,048✔
668
                          colorfreqtable, depth,
512✔
669
                          colormap.table[bi]->tuple);
1,536✔
670
            break;
1,536✔
671
        default:
672
            quant_trace(stderr, "Internal error: "
×
673
                                "invalid value of methodForRep: %d\n",
674
                        methodForRep);
675
        }
676
        if (use_reversible) {
13,764!
677
            sixel_quant_reversible_tuple(colormap.table[bi]->tuple,
×
678
                                         depth);
679
        }
680
    }
4,588✔
681
    return colormap;
69✔
682
}
23✔
683

684

685
static int
686
force_palette_compare(const void *lhs, const void *rhs)
×
687
{
688
    unsigned int left;
689
    unsigned int right;
690
    unsigned int left_value;
691
    unsigned int right_value;
692

693
    left = *(const unsigned int *)lhs;
×
694
    right = *(const unsigned int *)rhs;
×
695
    left_value = force_palette_source->table[left]->value;
×
696
    right_value = force_palette_source->table[right]->value;
×
697
    if (left_value > right_value) {
×
698
        return -1;
×
699
    }
700
    if (left_value < right_value) {
×
701
        return 1;
×
702
    }
703
    if (left < right) {
×
704
        return -1;
×
705
    }
706
    if (left > right) {
×
707
        return 1;
×
708
    }
709
    return 0;
×
710
}
711

712

713
static SIXELSTATUS
714
force_palette_completion(tupletable2 *colormapP,
×
715
                         unsigned int depth,
716
                         unsigned int reqColors,
717
                         tupletable2 const colorfreqtable,
718
                         sixel_allocator_t *allocator)
719
{
720
    /*
721
     * We enqueue "losers" from the histogram so that we can revive them:
722
     *
723
     *   histogram --> sort by hit count --> append to palette tail
724
     *        ^                             |
725
     *        +-----------------------------+
726
     *
727
     * The ASCII loop shows how discarded colors walk back into the
728
     * palette when the user demands an exact size.
729
     */
730
    SIXELSTATUS status = SIXEL_FALSE;
×
731
    tupletable new_table = NULL;
×
732
    unsigned int *order = NULL;
×
733
    unsigned int current;
734
    unsigned int fill;
735
    unsigned int candidate;
736
    unsigned int plane;
737
    unsigned int source;
738

739
    current = colormapP->size;
×
740
    if (current >= reqColors) {
×
741
        return SIXEL_OK;
×
742
    }
743

744
    status = alloctupletable(&new_table, depth, reqColors, allocator);
×
745
    if (SIXEL_FAILED(status)) {
×
746
        goto end;
×
747
    }
748

749
    if (colorfreqtable.size > 0U) {
×
750
        order = (unsigned int *)sixel_allocator_malloc(
×
751
            allocator, colorfreqtable.size * sizeof(unsigned int));
×
752
        if (order == NULL) {
×
753
            status = SIXEL_BAD_ALLOCATION;
×
754
            goto end;
×
755
        }
756
        for (candidate = 0; candidate < colorfreqtable.size; ++candidate) {
×
757
            order[candidate] = candidate;
×
758
        }
759
        force_palette_source = &colorfreqtable;
×
760
        qsort(order, colorfreqtable.size, sizeof(unsigned int),
×
761
              force_palette_compare);
762
        force_palette_source = NULL;
×
763
    }
764

765
    for (fill = 0; fill < current; ++fill) {
×
766
        new_table[fill]->value = colormapP->table[fill]->value;
×
767
        for (plane = 0; plane < depth; ++plane) {
×
768
            new_table[fill]->tuple[plane] =
×
769
                colormapP->table[fill]->tuple[plane];
×
770
        }
771
    }
772

773
    candidate = 0U;
×
774
    fill = current;
×
775
    if (order != NULL) {
×
776
        while (fill < reqColors && candidate < colorfreqtable.size) {
×
777
            unsigned int index;
778

779
            index = order[candidate];
×
780
            new_table[fill]->value = colorfreqtable.table[index]->value;
×
781
            for (plane = 0; plane < depth; ++plane) {
×
782
                new_table[fill]->tuple[plane] =
×
783
                    colorfreqtable.table[index]->tuple[plane];
×
784
            }
785
            ++fill;
×
786
            ++candidate;
×
787
        }
788
    }
789

790
    if (fill < reqColors && fill == 0U) {
×
791
        new_table[fill]->value = 0U;
×
792
        for (plane = 0; plane < depth; ++plane) {
×
793
            new_table[fill]->tuple[plane] = 0U;
×
794
        }
795
        ++fill;
×
796
    }
797

798
    source = 0U;
×
799
    while (fill < reqColors) {
×
800
        new_table[fill]->value = new_table[source]->value;
×
801
        for (plane = 0; plane < depth; ++plane) {
×
802
            new_table[fill]->tuple[plane] = new_table[source]->tuple[plane];
×
803
        }
804
        ++fill;
×
805
        ++source;
×
806
        if (source >= fill) {
×
807
            source = 0U;
×
808
        }
809
    }
810

811
    sixel_allocator_free(allocator, colormapP->table);
×
812
    colormapP->table = new_table;
×
813
    colormapP->size = reqColors;
×
814
    status = SIXEL_OK;
×
815

816
end:
817
    if (status != SIXEL_OK && new_table != NULL) {
×
818
        sixel_allocator_free(allocator, new_table);
×
819
    }
820
    if (order != NULL) {
×
821
        sixel_allocator_free(allocator, order);
×
822
    }
823
    return status;
×
824
}
825

826

827
static SIXELSTATUS
828
splitBox(boxVector const bv,
13,695✔
829
         unsigned int *const boxesP,
830
         unsigned int const bi,
831
         tupletable2 const colorfreqtable,
832
         unsigned int const depth,
833
         int const methodForLargest)
834
{
835
/*----------------------------------------------------------------------------
836
   Split Box 'bi' in the box vector bv (so that bv contains one more box
837
   than it did as input).  Split it so that each new box represents about
838
   half of the pixels in the distribution given by 'colorfreqtable' for
839
   the colors in the original box, but with distinct colors in each of the
840
   two new boxes.
841

842
   Assume the box contains at least two colors.
843
-----------------------------------------------------------------------------*/
844
    SIXELSTATUS status = SIXEL_FALSE;
13,695✔
845
    unsigned int const boxStart = bv[bi].ind;
13,695✔
846
    unsigned int const boxSize  = bv[bi].colors;
13,695✔
847
    unsigned int const sm       = bv[bi].sum;
13,695✔
848

849
    enum { max_depth= 16 };
850
    sample minval[max_depth];
851
    sample maxval[max_depth];
852

853
    /* assert(max_depth >= depth); */
854

855
    unsigned int largestDimension;
856
    /* number of the plane with the largest spread */
857
    unsigned int medianIndex;
858
    unsigned int lowersum;
859

860
    /* Number of pixels whose value is "less than" the median */
861
    findBoxBoundaries(colorfreqtable, depth, boxStart, boxSize,
18,260✔
862
                      minval, maxval);
4,565✔
863

864
    /* Find the largest dimension, and sort by that component.  I have
865
       included two methods for determining the "largest" dimension;
866
       first by simply comparing the range in RGB space, and second by
867
       transforming into luminosities before the comparison.
868
    */
869
    switch (methodForLargest) {
13,695!
870
    case SIXEL_LARGE_NORM:
8,620✔
871
        largestDimension = largestByNorm(minval, maxval, depth);
12,930✔
872
        break;
12,930✔
873
    case SIXEL_LARGE_LUM:
510✔
874
        largestDimension = largestByLuminosity(minval, maxval, depth);
765✔
875
        break;
765✔
876
    default:
877
        sixel_helper_set_additional_message(
×
878
            "Internal error: invalid value of methodForLargest.");
879
        status = SIXEL_LOGIC_ERROR;
×
880
        goto end;
×
881
    }
882

883
    /* TODO: I think this sort should go after creating a box,
884
       not before splitting.  Because you need the sort to use
885
       the SIXEL_REP_CENTER_BOX method of choosing a color to
886
       represent the final boxes
887
    */
888

889
    /* Set the gross global variable 'compareplanePlane' as a
890
       parameter to compareplane(), which is called by qsort().
891
    */
892
    compareplanePlane = largestDimension;
13,695✔
893
    qsort((char*) &colorfreqtable.table[boxStart], boxSize,
13,695✔
894
          sizeof(colorfreqtable.table[boxStart]),
895
          compareplane);
896

897
    {
898
        /* Now find the median based on the counts, so that about half
899
           the pixels (not colors, pixels) are in each subdivision.  */
900

901
        unsigned int i;
902

903
        lowersum = colorfreqtable.table[boxStart]->value; /* initial value */
13,695✔
904
        for (i = 1; i < boxSize - 1 && lowersum < sm / 2; ++i) {
898,806✔
905
            lowersum += colorfreqtable.table[boxStart + i]->value;
885,111✔
906
        }
294,643✔
907
        medianIndex = i;
13,695✔
908
    }
909
    /* Split the box, and sort to bring the biggest boxes to the top.  */
910

911
    bv[bi].colors = medianIndex;
13,695✔
912
    bv[bi].sum = lowersum;
13,695✔
913
    bv[*boxesP].ind = boxStart + medianIndex;
13,695✔
914
    bv[*boxesP].colors = boxSize - medianIndex;
13,695✔
915
    bv[*boxesP].sum = sm - lowersum;
13,695✔
916
    ++(*boxesP);
13,695✔
917
    qsort((char*) bv, *boxesP, sizeof(struct box), sumcompare);
13,695✔
918

919
    status = SIXEL_OK;
13,695✔
920

921
end:
9,130✔
922
    return status;
13,695✔
923
}
924

925

926

927
static SIXELSTATUS
928
mediancut(tupletable2 const colorfreqtable,
69✔
929
          unsigned int const depth,
930
          unsigned int const newcolors,
931
          int const methodForLargest,
932
          int const methodForRep,
933
          int const use_reversible,
934
          tupletable2 *const colormapP,
935
          sixel_allocator_t *allocator)
936
{
937
/*----------------------------------------------------------------------------
938
   Compute a set of only 'newcolors' colors that best represent an
939
   image whose pixels are summarized by the histogram
940
   'colorfreqtable'.  Each tuple in that table has depth 'depth'.
941
   colorfreqtable.table[i] tells the number of pixels in the subject image
942
   have a particular color.
943

944
   As a side effect, sort 'colorfreqtable'.
945
-----------------------------------------------------------------------------*/
946
    boxVector bv;
947
    unsigned int bi;
948
    unsigned int boxes;
949
    int multicolorBoxesExist;
950
    unsigned int i;
951
    unsigned int sum;
952
    SIXELSTATUS status = SIXEL_FALSE;
69✔
953

954
    sum = 0;
69✔
955

956
    for (i = 0; i < colorfreqtable.size; ++i) {
291,168✔
957
        sum += colorfreqtable.table[i]->value;
291,099✔
958
    }
96,889✔
959

960
    /* There is at least one box that contains at least 2 colors; ergo,
961
       there is more splitting we can do.  */
962
    bv = newBoxVector(colorfreqtable.size, sum, newcolors, allocator);
69✔
963
    if (bv == NULL) {
69!
964
        goto end;
×
965
    }
966
    boxes = 1;
69✔
967
    multicolorBoxesExist = (colorfreqtable.size > 1);
69✔
968

969
    /* Main loop: split boxes until we have enough. */
970
    while (boxes < newcolors && multicolorBoxesExist) {
13,764!
971
        /* Find the first splittable box. */
972
        for (bi = 0; bi < boxes && bv[bi].colors < 2; ++bi)
65,987!
973
            ;
974
        if (bi >= boxes) {
13,695!
975
            multicolorBoxesExist = 0;
×
976
        } else {
977
            status = splitBox(bv, &boxes, bi,
18,260✔
978
                              colorfreqtable, depth,
4,565✔
979
                              methodForLargest);
4,565✔
980
            if (SIXEL_FAILED(status)) {
13,695!
981
                goto end;
×
982
            }
983
        }
984
    }
985
    *colormapP = colormapFromBv(newcolors, bv, boxes,
92✔
986
                                colorfreqtable, depth,
23✔
987
                                methodForRep, use_reversible,
23✔
988
                                allocator);
23✔
989

990
    sixel_allocator_free(allocator, bv);
69✔
991

992
    status = SIXEL_OK;
69✔
993

994
end:
46✔
995
    return status;
69✔
996
}
997

998

999
static int histogram_lut_policy = SIXEL_LUT_POLICY_AUTO;
1000

1001
void
1002
sixel_quant_set_lut_policy(int lut_policy)
545✔
1003
{
1004
    int normalized;
1005

1006
    normalized = SIXEL_LUT_POLICY_AUTO;
545✔
1007
    if (lut_policy == SIXEL_LUT_POLICY_5BIT
778!
1008
        || lut_policy == SIXEL_LUT_POLICY_6BIT
545!
1009
        || lut_policy == SIXEL_LUT_POLICY_ROBINHOOD
545!
1010
        || lut_policy == SIXEL_LUT_POLICY_HOPSCOTCH) {
545!
1011
        normalized = lut_policy;
×
1012
    }
1013

1014
    histogram_lut_policy = normalized;
545✔
1015
}
545✔
1016

1017
struct histogram_control {
1018
    unsigned int channel_shift;
1019
    unsigned int channel_bits;
1020
    unsigned int channel_mask;
1021
    int reversible_rounding;         /* nonzero biases quantization upward */
1022
};
1023

1024
static struct histogram_control
1025
histogram_control_make(unsigned int depth);
1026
static struct histogram_control
1027
histogram_control_make_for_policy(unsigned int depth, int lut_policy);
1028
static size_t histogram_dense_size(unsigned int depth,
1029
                                   struct histogram_control const
1030
                                       *control);
1031
static unsigned int histogram_reconstruct(unsigned int quantized,
1032
                                          struct histogram_control const
1033
                                              *control);
1034

1035
static size_t
1036
histogram_dense_size(unsigned int depth,
527✔
1037
                     struct histogram_control const *control)
1038
{
1039
    size_t size;
1040
    unsigned int exponent;
1041
    unsigned int i;
1042

1043
    size = 1U;
527✔
1044
    exponent = depth * control->channel_bits;
527✔
1045
    for (i = 0U; i < exponent; ++i) {
10,013✔
1046
        if (size > SIZE_MAX / 2U) {
9,486!
1047
            size = SIZE_MAX;
×
1048
            break;
×
1049
        }
1050
        size <<= 1U;
9,486✔
1051
    }
4,086✔
1052

1053
    return size;
527✔
1054
}
1055

1056
static struct histogram_control
1057
histogram_control_make_for_policy(unsigned int depth, int lut_policy)
40,078,485✔
1058
{
1059
    struct histogram_control control;
1060

1061
    control.reversible_rounding = 0;
40,078,485✔
1062
    /*
1063
     * The ASCII ladder below shows how each policy selects bucket width.
1064
     *
1065
     *   auto / 6bit RGB : |--6--|
1066
     *   forced 5bit     : |---5---|
1067
     *   robinhood       : |------8------|
1068
     *   alpha fallback  : |---5---|  (avoids 2^(6*4) buckets)
1069
     */
1070
    control.channel_shift = 2U;
40,078,485✔
1071
    if (depth > 3U) {
40,078,485!
1072
        control.channel_shift = 3U;
×
1073
    }
1074
    if (lut_policy == SIXEL_LUT_POLICY_5BIT) {
40,078,485!
1075
        control.channel_shift = 3U;
×
1076
    } else if (lut_policy == SIXEL_LUT_POLICY_6BIT) {
40,078,485✔
1077
        control.channel_shift = 2U;
267✔
1078
        if (depth > 3U) {
267!
1079
            control.channel_shift = 3U;
×
1080
        }
1081
    } else if (lut_policy == SIXEL_LUT_POLICY_ROBINHOOD
40,078,327!
1082
               || lut_policy == SIXEL_LUT_POLICY_HOPSCOTCH) {
40,078,218!
1083
        control.channel_shift = 0U;
×
1084
    }
1085
    control.channel_bits = 8U - control.channel_shift;
40,078,485✔
1086
    control.channel_mask = (1U << control.channel_bits) - 1U;
40,078,485✔
1087

1088
    return control;
40,078,485✔
1089
}
1090

1091
static unsigned int
1092
histogram_reconstruct(unsigned int quantized,
882,318✔
1093
                      struct histogram_control const *control)
1094
{
1095
    unsigned int value;
1096

1097
    value = quantized << control->channel_shift;
882,318✔
1098
    if (quantized == control->channel_mask) {
882,318✔
1099
        value = 255U;
1,195✔
1100
    } else {
509✔
1101
        if (control->channel_shift > 0U) {
881,123!
1102
            value |= (1U << (control->channel_shift - 1U));
881,123✔
1103
        }
294,361✔
1104
    }
1105
    if (value > 255U) {
882,318!
1106
        value = 255U;
×
1107
    }
1108

1109
    return value;
882,318✔
1110
}
1111

1112
static unsigned int
1113
histogram_quantize(unsigned int sample8,
130,951,272✔
1114
                   struct histogram_control const *control)
1115
{
1116
    unsigned int quantized;
1117
    unsigned int shift;
1118
    unsigned int mask;
1119
    unsigned int rounding;
1120

1121
    /*
1122
     * In reversible mode we already rounded once when snapping to
1123
     * sixel_reversible_tones[].  If we rounded to the nearest midpoint
1124
     * again, the second pass would fall back to the lower bucket and break
1125
     * the round-trip.  Biasing towards the upper edge keeps the bucket
1126
     * stable after decoding and encoding again.  Non-reversible runs keep
1127
     * symmetric midpoints to avoid nudging colors upwards.
1128
     *
1129
     *        midpoint bias        upper-edge bias
1130
     *   |----*----|----*----|    |----|----*----|
1131
     *   0         8        16    0    8        16
1132
     *
1133
     * The asterisk marks the midpoint captured by a bucket.  Moving that
1134
     * midpoint to the upper edge keeps reversible tones from drifting.
1135
     */
1136
    shift = control->channel_shift;
130,951,272✔
1137
    mask = control->channel_mask;
130,951,272✔
1138
    if (shift == 0U) {
130,951,272!
1139
        quantized = sample8;
×
1140
    } else {
1141
        if (control->reversible_rounding) {
130,951,272!
1142
            rounding = 1U << shift;
×
1143
        } else {
1144
            rounding = 1U << (shift - 1U);
130,951,272✔
1145
        }
1146
        quantized = (sample8 + rounding) >> shift;
130,951,272✔
1147
        if (quantized > mask) {
130,951,272✔
1148
            quantized = mask;
3,173,826✔
1149
        }
1,408,976✔
1150
    }
1151

1152
    return quantized;
130,951,272✔
1153
}
1154

1155
static uint32_t
1156
histogram_pack_color(unsigned char const *data,
43,650,424✔
1157
                     unsigned int const depth,
1158
                     struct histogram_control const *control)
1159
{
1160
    uint32_t packed;
1161
    unsigned int n;
1162
    unsigned int sample8;
1163
    unsigned int bits;
1164

1165
    packed = 0U;
43,650,424✔
1166
    bits = control->channel_bits;
43,650,424✔
1167
    if (control->channel_shift == 0U) {
43,650,424!
1168
        /*
1169
         * The channel shift being zero means each component keeps eight
1170
         * bits.  We therefore pack pixels in RGB order, as illustrated
1171
         * below:
1172
         *
1173
         *      R   G   B
1174
         *     [ ]-[ ]-[ ]
1175
         *      |   |   |
1176
         *      v   v   v
1177
         *     0xRRGGBB
1178
         */
1179
        for (n = 0U; n < depth; ++n) {
×
1180
            packed |= (uint32_t)data[depth - 1U - n] << (n * bits);
×
1181
        }
1182
        return packed;
×
1183
    }
1184

1185
    for (n = 0U; n < depth; ++n) {
174,601,696✔
1186
        sample8 = (unsigned int)data[depth - 1U - n];
130,951,272✔
1187
        packed |= histogram_quantize(sample8, control) << (n * bits);
130,951,272✔
1188
    }
62,349,072✔
1189

1190
    return packed;
43,650,424✔
1191
}
20,783,024✔
1192

1193
static uint32_t
1194
histogram_hash_mix(uint32_t key)
40,077,958✔
1195
{
1196
    uint32_t hash;
1197

1198
    /*
1199
     * Multiplicative mixing with two avalanching rounds keeps nearby
1200
     * colors far apart in the hash domain.  The final tweak avoids the
1201
     * 0xffffffff sentinel used by hopscotch slots.
1202
     */
1203
    hash = key * 0x9e3779b9U;
40,077,958✔
1204
    hash ^= hash >> 16;
40,077,958✔
1205
    hash *= 0x7feb352dU;
40,077,958✔
1206
    hash ^= hash >> 15;
40,077,958✔
1207
    hash *= 0x846ca68bU;
40,077,958✔
1208
    hash ^= hash >> 16;
40,077,958✔
1209
    if (hash == 0xffffffffU) {
40,077,958!
1210
        hash ^= 0x632be59bU;
×
1211
    }
1212

1213
    return hash;
40,077,958✔
1214
}
1215

1216
static unsigned int
1217
computeHash(unsigned char const *data,
40,077,958✔
1218
            unsigned int const depth,
1219
            struct histogram_control const *control)
1220
{
1221
    uint32_t packed;
1222

1223
    packed = histogram_pack_color(data, depth, control);
40,077,958✔
1224

1225
    return histogram_hash_mix(packed);
40,077,958✔
1226
}
1227

1228
#define CUCKOO_BUCKET_SIZE 4U
1229
#define CUCKOO_MAX_KICKS 128U
1230
#define CUCKOO_STASH_SIZE 32U
1231
#define CUCKOO_EMPTY_KEY 0xffffffffU
1232

1233
struct cuckoo_bucket32 {
1234
    uint32_t key[CUCKOO_BUCKET_SIZE];
1235
    uint32_t value[CUCKOO_BUCKET_SIZE];
1236
};
1237

1238
struct cuckoo_table32 {
1239
    struct cuckoo_bucket32 *buckets;
1240
    uint32_t stash_key[CUCKOO_STASH_SIZE];
1241
    uint32_t stash_value[CUCKOO_STASH_SIZE];
1242
    size_t bucket_count;
1243
    size_t bucket_mask;
1244
    size_t stash_count;
1245
    size_t entry_count;
1246
    sixel_allocator_t *allocator;
1247
};
1248

1249
static size_t cuckoo_round_buckets(size_t hint);
1250
static size_t cuckoo_hash_primary(uint32_t key, size_t mask);
1251
static size_t cuckoo_hash_secondary(uint32_t key, size_t mask);
1252
static size_t cuckoo_hash_alternate(uint32_t key,
1253
                                    size_t bucket,
1254
                                    size_t mask);
1255
static uint32_t *cuckoo_bucket_find(struct cuckoo_bucket32 *bucket,
1256
                                    uint32_t key);
1257
static int cuckoo_bucket_insert_direct(struct cuckoo_bucket32 *bucket,
1258
                                       uint32_t key,
1259
                                       uint32_t value);
1260
static SIXELSTATUS cuckoo_table32_init(struct cuckoo_table32 *table,
1261
                                       size_t expected,
1262
                                       sixel_allocator_t *allocator);
1263
static void cuckoo_table32_clear(struct cuckoo_table32 *table);
1264
static void cuckoo_table32_fini(struct cuckoo_table32 *table);
1265
static uint32_t *cuckoo_table32_lookup(struct cuckoo_table32 *table,
1266
                                       uint32_t key);
1267
static SIXELSTATUS cuckoo_table32_insert(struct cuckoo_table32 *table,
1268
                                         uint32_t key,
1269
                                         uint32_t value);
1270
static SIXELSTATUS cuckoo_table32_grow(struct cuckoo_table32 *table);
1271

1272
struct robinhood_slot32 {
1273
    uint32_t key;
1274
    uint32_t color;
1275
    uint32_t value;
1276
    uint16_t distance;
1277
    uint16_t pad;
1278
};
1279

1280
struct robinhood_table32 {
1281
    struct robinhood_slot32 *slots;
1282
    size_t capacity;
1283
    size_t count;
1284
    sixel_allocator_t *allocator;
1285
};
1286

1287
static size_t robinhood_round_capacity(size_t hint);
1288
static SIXELSTATUS robinhood_table32_init(struct robinhood_table32 *table,
1289
                                         size_t expected,
1290
                                         sixel_allocator_t *allocator);
1291
static void robinhood_table32_fini(struct robinhood_table32 *table);
1292
static struct robinhood_slot32 *
1293
robinhood_table32_lookup(struct robinhood_table32 *table,
1294
                         uint32_t key,
1295
                         uint32_t color);
1296
static SIXELSTATUS robinhood_table32_insert(struct robinhood_table32 *table,
1297
                                           uint32_t key,
1298
                                           uint32_t color,
1299
                                           uint32_t value);
1300
static SIXELSTATUS robinhood_table32_grow(struct robinhood_table32 *table);
1301
static struct robinhood_slot32 *
1302
robinhood_table32_place(struct robinhood_table32 *table,
1303
                        struct robinhood_slot32 entry);
1304

1305
#define HOPSCOTCH_EMPTY_KEY 0xffffffffU
1306
#define HOPSCOTCH_DEFAULT_NEIGHBORHOOD 32U
1307
#define HOPSCOTCH_INSERT_RANGE 256U
1308

1309
struct hopscotch_slot32 {
1310
    uint32_t key;
1311
    uint32_t color;
1312
    uint32_t value;
1313
};
1314

1315
struct hopscotch_table32 {
1316
    struct hopscotch_slot32 *slots;
1317
    uint32_t *hopinfo;
1318
    size_t capacity;
1319
    size_t count;
1320
    size_t neighborhood;
1321
    sixel_allocator_t *allocator;
1322
};
1323

1324
static SIXELSTATUS hopscotch_table32_init(struct hopscotch_table32 *table,
1325
                                          size_t expected,
1326
                                          sixel_allocator_t *allocator);
1327
static void hopscotch_table32_fini(struct hopscotch_table32 *table);
1328
static struct hopscotch_slot32 *
1329
hopscotch_table32_lookup(struct hopscotch_table32 *table,
1330
                         uint32_t key,
1331
                         uint32_t color);
1332
static SIXELSTATUS hopscotch_table32_insert(struct hopscotch_table32 *table,
1333
                                            uint32_t key,
1334
                                            uint32_t color,
1335
                                            uint32_t value);
1336
static SIXELSTATUS hopscotch_table32_grow(struct hopscotch_table32 *table);
1337

1338
static struct histogram_control
1339
histogram_control_make(unsigned int depth)
40,078,218✔
1340
{
1341
    struct histogram_control control;
1342

1343
    control = histogram_control_make_for_policy(depth,
59,084,154✔
1344
                                                histogram_lut_policy);
19,005,936✔
1345

1346
    return control;
40,078,218✔
1347
}
1348

1349
static size_t
1350
robinhood_round_capacity(size_t hint)
×
1351
{
1352
    size_t capacity;
1353

1354
    capacity = 16U;
×
1355
    if (hint < capacity) {
×
1356
        return capacity;
×
1357
    }
1358

1359
    capacity = hint - 1U;
×
1360
    capacity |= capacity >> 1;
×
1361
    capacity |= capacity >> 2;
×
1362
    capacity |= capacity >> 4;
×
1363
    capacity |= capacity >> 8;
×
1364
    capacity |= capacity >> 16;
×
1365
#if SIZE_MAX > UINT32_MAX
1366
    capacity |= capacity >> 32;
×
1367
#endif
1368
    if (capacity == SIZE_MAX) {
×
1369
        return SIZE_MAX;
×
1370
    }
1371
    capacity++;
×
1372
    if (capacity < 16U) {
×
1373
        capacity = 16U;
×
1374
    }
1375

1376
    return capacity;
×
1377
}
1378

1379
static SIXELSTATUS
1380
robinhood_table32_init(struct robinhood_table32 *table,
×
1381
                       size_t expected,
1382
                       sixel_allocator_t *allocator)
1383
{
1384
    size_t hint;
1385
    size_t capacity;
1386

1387
    table->slots = NULL;
×
1388
    table->capacity = 0U;
×
1389
    table->count = 0U;
×
1390
    table->allocator = allocator;
×
1391

1392
    if (expected < 16U) {
×
1393
        expected = 16U;
×
1394
    }
1395
    if (expected > SIZE_MAX / 2U) {
×
1396
        hint = SIZE_MAX / 2U;
×
1397
    } else {
1398
        hint = expected * 2U;
×
1399
    }
1400
    capacity = robinhood_round_capacity(hint);
×
1401
    if (capacity == SIZE_MAX && hint != SIZE_MAX) {
×
1402
        return SIXEL_BAD_ALLOCATION;
×
1403
    }
1404

1405
    table->slots = (struct robinhood_slot32 *)
×
1406
        sixel_allocator_calloc(allocator,
×
1407
                               capacity,
1408
                               sizeof(struct robinhood_slot32));
1409
    if (table->slots == NULL) {
×
1410
        table->capacity = 0U;
×
1411
        table->count = 0U;
×
1412
        return SIXEL_BAD_ALLOCATION;
×
1413
    }
1414
    table->capacity = capacity;
×
1415
    table->count = 0U;
×
1416

1417
    return SIXEL_OK;
×
1418
}
1419

1420
static void
1421
robinhood_table32_fini(struct robinhood_table32 *table)
×
1422
{
1423
    if (table->slots != NULL) {
×
1424
        sixel_allocator_free(table->allocator, table->slots);
×
1425
        table->slots = NULL;
×
1426
    }
1427
    table->capacity = 0U;
×
1428
    table->count = 0U;
×
1429
    table->allocator = NULL;
×
1430
}
×
1431

1432
static struct robinhood_slot32 *
1433
robinhood_table32_lookup(struct robinhood_table32 *table,
×
1434
                         uint32_t key,
1435
                         uint32_t color)
1436
{
1437
    size_t mask;
1438
    size_t index;
1439
    uint16_t distance;
1440
    struct robinhood_slot32 *slot;
1441

1442
    if (table->capacity == 0U || table->slots == NULL) {
×
1443
        return NULL;
×
1444
    }
1445

1446
    mask = table->capacity - 1U;
×
1447
    index = (size_t)(key & mask);
×
1448
    distance = 0U;
×
1449

1450
    for (;;) {
1451
        slot = &table->slots[index];
×
1452
        if (slot->value == 0U) {
×
1453
            return NULL;
×
1454
        }
1455
        if (slot->key == key && slot->color == color) {
×
1456
            return slot;
×
1457
        }
1458
        if (slot->distance < distance) {
×
1459
            return NULL;
×
1460
        }
1461
        index = (index + 1U) & mask;
×
1462
        distance++;
×
1463
    }
1464
}
1465

1466
static struct robinhood_slot32 *
1467
robinhood_table32_place(struct robinhood_table32 *table,
×
1468
                        struct robinhood_slot32 entry)
1469
{
1470
    size_t mask;
1471
    size_t index;
1472
    struct robinhood_slot32 *slot;
1473
    struct robinhood_slot32 tmp;
1474

1475
    mask = table->capacity - 1U;
×
1476
    index = (size_t)(entry.key & mask);
×
1477

1478
    for (;;) {
1479
        slot = &table->slots[index];
×
1480
        if (slot->value == 0U) {
×
1481
            *slot = entry;
×
1482
            table->count++;
×
1483
            return slot;
×
1484
        }
1485
        if (slot->key == entry.key && slot->color == entry.color) {
×
1486
            slot->value = entry.value;
×
1487
            return slot;
×
1488
        }
1489
        if (slot->distance < entry.distance) {
×
1490
            tmp = *slot;
×
1491
            *slot = entry;
×
1492
            entry = tmp;
×
1493
        }
1494
        index = (index + 1U) & mask;
×
1495
        entry.distance++;
×
1496
    }
1497
}
1498

1499
static SIXELSTATUS
1500
robinhood_table32_grow(struct robinhood_table32 *table)
×
1501
{
1502
    struct robinhood_slot32 *old_slots;
1503
    size_t old_capacity;
1504
    size_t new_capacity;
1505
    size_t i;
1506

1507
    if (table->allocator == NULL) {
×
1508
        return SIXEL_BAD_ALLOCATION;
×
1509
    }
1510
    if (table->capacity == 0U) {
×
1511
        new_capacity = 16U;
×
1512
    } else {
1513
        if (table->capacity > SIZE_MAX / 2U) {
×
1514
            return SIXEL_BAD_ALLOCATION;
×
1515
        }
1516
        new_capacity = table->capacity << 1U;
×
1517
    }
1518
    new_capacity = robinhood_round_capacity(new_capacity);
×
1519
    if (new_capacity <= table->capacity) {
×
1520
        return SIXEL_BAD_ALLOCATION;
×
1521
    }
1522

1523
    old_slots = table->slots;
×
1524
    old_capacity = table->capacity;
×
1525
    table->slots = (struct robinhood_slot32 *)
×
1526
        sixel_allocator_calloc(table->allocator,
×
1527
                               new_capacity,
1528
                               sizeof(struct robinhood_slot32));
1529
    if (table->slots == NULL) {
×
1530
        table->slots = old_slots;
×
1531
        table->capacity = old_capacity;
×
1532
        return SIXEL_BAD_ALLOCATION;
×
1533
    }
1534
    table->capacity = new_capacity;
×
1535
    table->count = 0U;
×
1536

1537
    for (i = 0U; i < old_capacity; ++i) {
×
1538
        struct robinhood_slot32 entry;
1539

1540
        if (old_slots[i].value == 0U) {
×
1541
            continue;
×
1542
        }
1543
        entry.key = old_slots[i].key;
×
1544
        entry.color = old_slots[i].color;
×
1545
        entry.value = old_slots[i].value;
×
1546
        entry.distance = 0U;
×
1547
        entry.pad = 0U;  /* ensure padding bytes are initialized */
×
1548
        (void)robinhood_table32_place(table, entry);
×
1549
    }
1550

1551
    sixel_allocator_free(table->allocator, old_slots);
×
1552

1553
    return SIXEL_OK;
×
1554
}
1555

1556
static SIXELSTATUS
1557
robinhood_table32_insert(struct robinhood_table32 *table,
×
1558
                         uint32_t key,
1559
                         uint32_t color,
1560
                         uint32_t value)
1561
{
1562
    SIXELSTATUS status;
1563
    struct robinhood_slot32 entry;
1564

1565
    if (table->slots == NULL || table->capacity == 0U) {
×
1566
        return SIXEL_BAD_ARGUMENT;
×
1567
    }
1568
    if (table->count * 2U >= table->capacity) {
×
1569
        status = robinhood_table32_grow(table);
×
1570
        if (SIXEL_FAILED(status)) {
×
1571
            return status;
×
1572
        }
1573
    }
1574

1575
    entry.key = key;
×
1576
    entry.color = color;
×
1577
    entry.value = value;
×
1578
    entry.distance = 0U;
×
1579
    entry.pad = 0U;  /* ensure padding bytes are initialized */
×
1580
    (void)robinhood_table32_place(table, entry);
×
1581

1582
    return SIXEL_OK;
×
1583
}
1584

1585
static SIXELSTATUS
1586
hopscotch_table32_init(struct hopscotch_table32 *table,
×
1587
                       size_t expected,
1588
                       sixel_allocator_t *allocator)
1589
{
1590
    size_t hint;
1591
    size_t capacity;
1592
    size_t i;
1593

1594
    if (table == NULL) {
×
1595
        return SIXEL_BAD_ARGUMENT;
×
1596
    }
1597

1598
    table->slots = NULL;
×
1599
    table->hopinfo = NULL;
×
1600
    table->capacity = 0U;
×
1601
    table->count = 0U;
×
1602
    table->neighborhood = HOPSCOTCH_DEFAULT_NEIGHBORHOOD;
×
1603
    table->allocator = allocator;
×
1604

1605
    if (expected < 16U) {
×
1606
        expected = 16U;
×
1607
    }
1608
    if (expected > SIZE_MAX / 2U) {
×
1609
        hint = SIZE_MAX / 2U;
×
1610
    } else {
1611
        hint = expected * 2U;
×
1612
    }
1613
    capacity = robinhood_round_capacity(hint);
×
1614
    if (capacity == SIZE_MAX && hint != SIZE_MAX) {
×
1615
        return SIXEL_BAD_ALLOCATION;
×
1616
    }
1617
    if (capacity < table->neighborhood) {
×
1618
        capacity = table->neighborhood;
×
1619
    }
1620

1621
    table->slots = (struct hopscotch_slot32 *)
×
1622
        sixel_allocator_malloc(allocator,
×
1623
                               capacity * sizeof(struct hopscotch_slot32));
1624
    if (table->slots == NULL) {
×
1625
        return SIXEL_BAD_ALLOCATION;
×
1626
    }
1627
    table->hopinfo = (uint32_t *)
×
1628
        sixel_allocator_calloc(allocator,
×
1629
                               capacity,
1630
                               sizeof(uint32_t));
1631
    if (table->hopinfo == NULL) {
×
1632
        sixel_allocator_free(allocator, table->slots);
×
1633
        table->slots = NULL;
×
1634
        return SIXEL_BAD_ALLOCATION;
×
1635
    }
1636

1637
    for (i = 0U; i < capacity; ++i) {
×
1638
        table->slots[i].key = HOPSCOTCH_EMPTY_KEY;
×
1639
        table->slots[i].color = 0U;
×
1640
        table->slots[i].value = 0U;
×
1641
    }
1642
    table->capacity = capacity;
×
1643
    table->count = 0U;
×
1644
    if (table->neighborhood > 32U) {
×
1645
        table->neighborhood = 32U;
×
1646
    }
1647
    if (table->neighborhood > table->capacity) {
×
1648
        table->neighborhood = table->capacity;
×
1649
    }
1650

1651
    return SIXEL_OK;
×
1652
}
1653

1654
static void
1655
hopscotch_table32_fini(struct hopscotch_table32 *table)
×
1656
{
1657
    sixel_allocator_t *allocator;
1658

1659
    if (table == NULL) {
×
1660
        return;
×
1661
    }
1662

1663
    allocator = table->allocator;
×
1664
    if (allocator != NULL) {
×
1665
        if (table->slots != NULL) {
×
1666
            sixel_allocator_free(allocator, table->slots);
×
1667
        }
1668
        if (table->hopinfo != NULL) {
×
1669
            sixel_allocator_free(allocator, table->hopinfo);
×
1670
        }
1671
    }
1672
    table->slots = NULL;
×
1673
    table->hopinfo = NULL;
×
1674
    table->capacity = 0U;
×
1675
    table->count = 0U;
×
1676
}
1677

1678
static struct hopscotch_slot32 *
1679
hopscotch_table32_lookup(struct hopscotch_table32 *table,
×
1680
                         uint32_t key,
1681
                         uint32_t color)
1682
{
1683
    size_t index;
1684
    size_t bit;
1685
    size_t candidate;
1686
    uint32_t hop;
1687
    size_t mask;
1688
    size_t neighborhood;
1689

1690
    if (table == NULL || table->slots == NULL || table->hopinfo == NULL) {
×
1691
        return NULL;
×
1692
    }
1693
    if (table->capacity == 0U) {
×
1694
        return NULL;
×
1695
    }
1696

1697
    mask = table->capacity - 1U;
×
1698
    index = (size_t)key & mask;
×
1699
    hop = table->hopinfo[index];
×
1700
    neighborhood = table->neighborhood;
×
1701
    for (bit = 0U; bit < neighborhood; ++bit) {
×
1702
        if ((hop & (1U << bit)) == 0U) {
×
1703
            continue;
×
1704
        }
1705
        candidate = (index + bit) & mask;
×
1706
        if (table->slots[candidate].key == key
×
1707
            && table->slots[candidate].color == color) {
×
1708
            return &table->slots[candidate];
×
1709
        }
1710
    }
1711

1712
    return NULL;
×
1713
}
1714

1715
static SIXELSTATUS
1716
hopscotch_table32_grow(struct hopscotch_table32 *table)
×
1717
{
1718
    SIXELSTATUS status;
1719
    struct hopscotch_table32 tmp;
1720
    size_t i;
1721
    struct hopscotch_slot32 *slot;
1722

1723
    tmp.slots = NULL;
×
1724
    tmp.hopinfo = NULL;
×
1725
    tmp.capacity = 0U;
×
1726
    tmp.count = 0U;
×
1727
    tmp.neighborhood = table->neighborhood;
×
1728
    tmp.allocator = table->allocator;
×
1729

1730
    status = hopscotch_table32_init(&tmp,
×
1731
                                    table->capacity * 2U,
×
1732
                                    table->allocator);
1733
    if (SIXEL_FAILED(status)) {
×
1734
        return status;
×
1735
    }
1736
    if (tmp.neighborhood > table->neighborhood) {
×
1737
        tmp.neighborhood = table->neighborhood;
×
1738
    }
1739

1740
    for (i = 0U; i < table->capacity; ++i) {
×
1741
        slot = &table->slots[i];
×
1742
        if (slot->key == HOPSCOTCH_EMPTY_KEY) {
×
1743
            continue;
×
1744
        }
1745
        status = hopscotch_table32_insert(&tmp,
×
1746
                                          slot->key,
1747
                                          slot->color,
1748
                                          slot->value);
1749
        if (SIXEL_FAILED(status)) {
×
1750
            hopscotch_table32_fini(&tmp);
×
1751
            return status;
×
1752
        }
1753
    }
1754

1755
    hopscotch_table32_fini(table);
×
1756

1757
    table->slots = tmp.slots;
×
1758
    table->hopinfo = tmp.hopinfo;
×
1759
    table->capacity = tmp.capacity;
×
1760
    table->count = tmp.count;
×
1761
    table->neighborhood = tmp.neighborhood;
×
1762
    table->allocator = tmp.allocator;
×
1763

1764
    return SIXEL_OK;
×
1765
}
1766

1767
static SIXELSTATUS
1768
hopscotch_table32_insert(struct hopscotch_table32 *table,
×
1769
                         uint32_t key,
1770
                         uint32_t color,
1771
                         uint32_t value)
1772
{
1773
    SIXELSTATUS status;
1774
    struct hopscotch_slot32 *slot;
1775
    size_t index;
1776
    size_t mask;
1777
    size_t distance;
1778
    size_t attempts;
1779
    size_t free_index;
1780
    size_t neighborhood;
1781
    int relocated;
1782
    size_t offset;
1783
    uint32_t hop;
1784
    size_t bit;
1785
    size_t move_index;
1786
    struct hopscotch_slot32 tmp_slot;
1787

1788
    if (table == NULL || table->slots == NULL || table->hopinfo == NULL) {
×
1789
        return SIXEL_BAD_ARGUMENT;
×
1790
    }
1791
    if (table->capacity == 0U) {
×
1792
        return SIXEL_BAD_ARGUMENT;
×
1793
    }
1794

1795
    slot = hopscotch_table32_lookup(table, key, color);
×
1796
    if (slot != NULL) {
×
1797
        slot->value = value;
×
1798
        return SIXEL_OK;
×
1799
    }
1800

1801
    if (table->count * 2U >= table->capacity) {
×
1802
        status = hopscotch_table32_grow(table);
×
1803
        if (SIXEL_FAILED(status)) {
×
1804
            return status;
×
1805
        }
1806
        return hopscotch_table32_insert(table, key, color, value);
×
1807
    }
1808

1809
    mask = table->capacity - 1U;
×
1810
    neighborhood = table->neighborhood;
×
1811
    index = (size_t)key & mask;
×
1812
    slot = NULL;
×
1813
    free_index = index;
×
1814
    distance = 0U;
×
1815
    for (attempts = 0U; attempts < HOPSCOTCH_INSERT_RANGE; ++attempts) {
×
1816
        free_index = (index + attempts) & mask;
×
1817
        slot = &table->slots[free_index];
×
1818
        if (slot->key == HOPSCOTCH_EMPTY_KEY) {
×
1819
            distance = attempts;
×
1820
            break;
×
1821
        }
1822
    }
1823
    if (slot == NULL || slot->key != HOPSCOTCH_EMPTY_KEY) {
×
1824
        status = hopscotch_table32_grow(table);
×
1825
        if (SIXEL_FAILED(status)) {
×
1826
            return status;
×
1827
        }
1828
        return hopscotch_table32_insert(table, key, color, value);
×
1829
    }
1830

1831
    /*
1832
     * Relocation diagram:
1833
     *
1834
     *   free slot <--- hop window <--- [base bucket]
1835
     *      ^ move resident outward until distance < neighborhood
1836
     */
1837
    while (distance >= neighborhood) {
×
1838
        relocated = 0;
×
1839
        for (offset = neighborhood - 1U; offset > 0U; --offset) {
×
1840
            size_t base;
1841

1842
            base = (free_index + table->capacity - offset) & mask;
×
1843
            hop = table->hopinfo[base];
×
1844
            if (hop == 0U) {
×
1845
                continue;
×
1846
            }
1847
            for (bit = 0U; bit < offset; ++bit) {
×
1848
                if ((hop & (1U << bit)) == 0U) {
×
1849
                    continue;
×
1850
                }
1851
                move_index = (base + bit) & mask;
×
1852
                tmp_slot = table->slots[move_index];
×
1853
                table->slots[free_index] = tmp_slot;
×
1854
                table->slots[move_index].key = HOPSCOTCH_EMPTY_KEY;
×
1855
                table->slots[move_index].color = 0U;
×
1856
                table->slots[move_index].value = 0U;
×
1857
                table->hopinfo[base] &= (uint32_t)~(1U << bit);
×
1858
                table->hopinfo[base] |= (uint32_t)(1U << offset);
×
1859
                free_index = move_index;
×
1860
                if (free_index >= index) {
×
1861
                    distance = free_index - index;
×
1862
                } else {
1863
                    distance = free_index + table->capacity - index;
×
1864
                }
1865
                relocated = 1;
×
1866
                break;
×
1867
            }
1868
            if (relocated) {
×
1869
                break;
×
1870
            }
1871
        }
1872
        if (!relocated) {
×
1873
            status = hopscotch_table32_grow(table);
×
1874
            if (SIXEL_FAILED(status)) {
×
1875
                return status;
×
1876
            }
1877
            return hopscotch_table32_insert(table, key, color, value);
×
1878
        }
1879
    }
1880

1881
    if (distance >= 32U) {
×
1882
        status = hopscotch_table32_grow(table);
×
1883
        if (SIXEL_FAILED(status)) {
×
1884
            return status;
×
1885
        }
1886
        return hopscotch_table32_insert(table, key, color, value);
×
1887
    }
1888

1889
    table->slots[free_index].key = key;
×
1890
    table->slots[free_index].color = color;
×
1891
    table->slots[free_index].value = value;
×
1892
    table->hopinfo[index] |= (uint32_t)(1U << distance);
×
1893
    table->count++;
×
1894

1895
    return SIXEL_OK;
×
1896
}
1897

1898
/*
1899
 * The cuckoo hash backend stores entries in fixed-width buckets.
1900
 *
1901
 *   [bucket 0] -> key0 key1 key2 key3
1902
 *                 val0 val1 val2 val3
1903
 *   [bucket 1] -> ...
1904
 *
1905
 * Each key is compared against the 128-bit lane using SIMD instructions.
1906
 * Two hash functions map a key to its primary and secondary buckets.  When
1907
 * both are full, the eviction loop "kicks" an entry toward its alternate
1908
 * bucket, as illustrated below:
1909
 *
1910
 *   bucket A --kick--> bucket B --kick--> bucket A ...
1911
 *
1912
 * A tiny stash buffers entries when the table momentarily fills up.  This
1913
 * keeps lookups fast while letting us grow the table lazily.
1914
 */
1915
static size_t
1916
cuckoo_round_buckets(size_t hint)
267✔
1917
{
1918
    size_t desired;
1919
    size_t buckets;
1920
    size_t prev;
1921

1922
    if (hint < CUCKOO_BUCKET_SIZE) {
267!
1923
        hint = CUCKOO_BUCKET_SIZE;
×
1924
    }
1925
    if (hint > SIZE_MAX / 2U) {
267!
1926
        hint = SIZE_MAX / 2U;
×
1927
    }
1928
    desired = (hint * 2U + CUCKOO_BUCKET_SIZE - 1U) / CUCKOO_BUCKET_SIZE;
267✔
1929
    if (desired == 0U) {
267!
1930
        desired = 1U;
×
1931
    }
1932

1933
    buckets = 1U;
267✔
1934
    while (buckets < desired) {
4,806✔
1935
        prev = buckets;
4,539✔
1936
        if (buckets > SIZE_MAX / 2U) {
4,539!
1937
            buckets = prev;
×
1938
            break;
×
1939
        }
1940
        buckets <<= 1U;
4,539✔
1941
        if (buckets < prev) {
4,539!
1942
            buckets = prev;
×
1943
            break;
×
1944
        }
1945
    }
1946
    if (buckets == 0U) {
267!
1947
        buckets = 1U;
×
1948
    }
1949

1950
    return buckets;
267✔
1951
}
1952

1953
static size_t
1954
cuckoo_hash_primary(uint32_t key, size_t mask)
43,408,352✔
1955
{
1956
    uint32_t mix;
1957

1958
    mix = key * 0x9e3779b1U;
43,408,352✔
1959
    return (size_t)(mix & (uint32_t)mask);
43,408,352✔
1960
}
1961

1962
static size_t
1963
cuckoo_hash_secondary(uint32_t key, size_t mask)
3,330,618✔
1964
{
1965
    uint32_t mix;
1966

1967
    mix = key ^ 0x85ebca6bU;
3,330,618✔
1968
    mix ^= mix >> 13;
3,330,618✔
1969
    mix *= 0xc2b2ae35U;
3,330,618✔
1970
    return (size_t)(mix & (uint32_t)mask);
3,330,618✔
1971
}
1972

1973
static size_t
1974
cuckoo_hash_alternate(uint32_t key, size_t bucket, size_t mask)
16✔
1975
{
1976
    size_t primary;
1977
    size_t secondary;
1978

1979
    primary = cuckoo_hash_primary(key, mask);
16✔
1980
    secondary = cuckoo_hash_secondary(key, mask);
16✔
1981
    if (primary == bucket) {
16!
1982
        if (secondary == primary) {
16!
1983
            secondary = (secondary + 1U) & mask;
×
1984
        }
1985
        return secondary;
16✔
1986
    }
1987

1988
    return primary;
×
1989
}
2✔
1990

1991
static uint32_t *
1992
cuckoo_bucket_find(struct cuckoo_bucket32 *bucket, uint32_t key)
45,073,749✔
1993
{
1994
    size_t i;
1995

1996
#if defined(SIXEL_USE_SSE2)
1997
    __m128i needle;
1998
    __m128i keys;
1999
    __m128i cmp;
2000
    int mask;
2001

2002
    needle = _mm_set1_epi32((int)key);
2003
    keys = _mm_loadu_si128((const __m128i *)bucket->key);
2004
    cmp = _mm_cmpeq_epi32(needle, keys);
2005
    mask = _mm_movemask_ps(_mm_castsi128_ps(cmp));
2006
    if ((mask & 1) != 0 && bucket->value[0] != 0U) {
2007
        return &bucket->value[0];
2008
    }
2009
    if ((mask & 2) != 0 && bucket->value[1] != 0U) {
2010
        return &bucket->value[1];
2011
    }
2012
    if ((mask & 4) != 0 && bucket->value[2] != 0U) {
2013
        return &bucket->value[2];
2014
    }
2015
    if ((mask & 8) != 0 && bucket->value[3] != 0U) {
2016
        return &bucket->value[3];
2017
    }
2018
#elif defined(SIXEL_USE_NEON)
2019
    uint32x4_t needle;
2020
    uint32x4_t keys;
2021
    uint32x4_t cmp;
2022

2023
    needle = vdupq_n_u32(key);
2024
    keys = vld1q_u32(bucket->key);
2025
    cmp = vceqq_u32(needle, keys);
2026
    if (vgetq_lane_u32(cmp, 0) != 0U && bucket->value[0] != 0U) {
2027
        return &bucket->value[0];
2028
    }
2029
    if (vgetq_lane_u32(cmp, 1) != 0U && bucket->value[1] != 0U) {
2030
        return &bucket->value[1];
2031
    }
2032
    if (vgetq_lane_u32(cmp, 2) != 0U && bucket->value[2] != 0U) {
2033
        return &bucket->value[2];
2034
    }
2035
    if (vgetq_lane_u32(cmp, 3) != 0U && bucket->value[3] != 0U) {
2036
        return &bucket->value[3];
2037
    }
2038
#else
2039
    for (i = 0U; i < CUCKOO_BUCKET_SIZE; ++i) {
72,901,179✔
2040
        if (bucket->value[i] != 0U && bucket->key[i] == key) {
66,240,199✔
2041
            return &bucket->value[i];
38,412,769✔
2042
        }
2043
    }
9,010,468✔
2044
#endif
2045

2046
    return NULL;
6,660,980✔
2047
}
20,620,459✔
2048

2049
static int
2050
cuckoo_bucket_insert_direct(struct cuckoo_bucket32 *bucket,
1,665,205✔
2051
                            uint32_t key,
2052
                            uint32_t value)
2053
{
2054
    size_t i;
2055

2056
    for (i = 0U; i < CUCKOO_BUCKET_SIZE; ++i) {
1,806,371✔
2057
        if (bucket->value[i] == 0U) {
1,806,355✔
2058
            bucket->key[i] = key;
1,665,189✔
2059
            bucket->value[i] = value;
1,665,189✔
2060
            return 1;
1,665,189✔
2061
        }
2062
    }
43,238✔
2063

2064
    return 0;
16✔
2065
}
538,193✔
2066

2067
static SIXELSTATUS
2068
cuckoo_table32_init(struct cuckoo_table32 *table,
264✔
2069
                    size_t expected,
2070
                    sixel_allocator_t *allocator)
2071
{
2072
    size_t buckets;
2073
    size_t i;
2074
    size_t j;
2075

2076
    if (table == NULL || allocator == NULL) {
264!
2077
        return SIXEL_BAD_ARGUMENT;
×
2078
    }
2079

2080
    buckets = cuckoo_round_buckets(expected);
264✔
2081
    if (buckets == 0U
264!
2082
        || buckets > SIZE_MAX / sizeof(struct cuckoo_bucket32)) {
264!
2083
        sixel_helper_set_additional_message(
×
2084
            "unable to size cuckoo bucket array.");
2085
        return SIXEL_BAD_ALLOCATION;
×
2086
    }
2087

2088
    table->buckets = (struct cuckoo_bucket32 *)sixel_allocator_malloc(
264✔
2089
        allocator, buckets * sizeof(struct cuckoo_bucket32));
108✔
2090
    if (table->buckets == NULL) {
264!
2091
        sixel_helper_set_additional_message(
×
2092
            "unable to allocate cuckoo buckets.");
2093
        return SIXEL_BAD_ALLOCATION;
×
2094
    }
2095

2096
    table->bucket_count = buckets;
264✔
2097
    table->bucket_mask = buckets - 1U;
264✔
2098
    table->stash_count = 0U;
264✔
2099
    table->entry_count = 0U;
264✔
2100
    table->allocator = allocator;
264✔
2101
    for (i = 0U; i < buckets; ++i) {
34,603,272✔
2102
        for (j = 0U; j < CUCKOO_BUCKET_SIZE; ++j) {
173,015,040✔
2103
            table->buckets[i].key[j] = CUCKOO_EMPTY_KEY;
138,412,032✔
2104
            table->buckets[i].value[j] = 0U;
138,412,032✔
2105
        }
56,623,104✔
2106
    }
14,155,776✔
2107
    for (i = 0U; i < CUCKOO_STASH_SIZE; ++i) {
8,712✔
2108
        table->stash_key[i] = CUCKOO_EMPTY_KEY;
8,448✔
2109
        table->stash_value[i] = 0U;
8,448✔
2110
    }
3,456✔
2111

2112
    return SIXEL_OK;
264✔
2113
}
108✔
2114

2115
static void
2116
cuckoo_table32_clear(struct cuckoo_table32 *table)
267✔
2117
{
2118
    size_t i;
2119
    size_t j;
2120

2121
    if (table == NULL || table->buckets == NULL) {
267!
2122
        return;
×
2123
    }
2124

2125
    table->stash_count = 0U;
267✔
2126
    table->entry_count = 0U;
267✔
2127
    for (i = 0U; i < table->bucket_count; ++i) {
34,996,491✔
2128
        for (j = 0U; j < CUCKOO_BUCKET_SIZE; ++j) {
174,981,120✔
2129
            table->buckets[i].key[j] = CUCKOO_EMPTY_KEY;
139,984,896✔
2130
            table->buckets[i].value[j] = 0U;
139,984,896✔
2131
        }
57,147,392✔
2132
    }
14,286,848✔
2133
    for (i = 0U; i < CUCKOO_STASH_SIZE; ++i) {
8,811✔
2134
        table->stash_key[i] = CUCKOO_EMPTY_KEY;
8,544✔
2135
        table->stash_value[i] = 0U;
8,544✔
2136
    }
3,488✔
2137
}
109✔
2138

2139
static void
2140
cuckoo_table32_fini(struct cuckoo_table32 *table)
264✔
2141
{
2142
    if (table == NULL || table->allocator == NULL) {
264!
2143
        return;
×
2144
    }
2145
    if (table->buckets != NULL) {
264!
2146
        sixel_allocator_free(table->allocator, table->buckets);
264✔
2147
        table->buckets = NULL;
264✔
2148
    }
108✔
2149
    table->bucket_count = 0U;
264✔
2150
    table->bucket_mask = 0U;
264✔
2151
    table->stash_count = 0U;
264✔
2152
    table->entry_count = 0U;
264✔
2153
}
108✔
2154

2155
static uint32_t *
2156
cuckoo_table32_lookup(struct cuckoo_table32 *table, uint32_t key)
41,743,147✔
2157
{
2158
    size_t index;
2159
    size_t i;
2160
    uint32_t *slot;
2161

2162
    if (table == NULL || table->buckets == NULL) {
41,743,147!
2163
        return NULL;
×
2164
    }
2165

2166
    index = cuckoo_hash_primary(key, table->bucket_mask);
41,743,147✔
2167
    slot = cuckoo_bucket_find(&table->buckets[index], key);
41,743,147✔
2168
    if (slot != NULL) {
41,743,147✔
2169
        return slot;
38,412,545✔
2170
    }
2171

2172
    index = cuckoo_hash_secondary(key, table->bucket_mask);
3,330,602✔
2173
    slot = cuckoo_bucket_find(&table->buckets[index], key);
3,330,602✔
2174
    if (slot != NULL) {
3,330,602✔
2175
        return slot;
224✔
2176
    }
2177

2178
    for (i = 0U; i < table->stash_count; ++i) {
3,330,378!
2179
        if (table->stash_value[i] != 0U && table->stash_key[i] == key) {
×
2180
            return &table->stash_value[i];
×
2181
        }
2182
    }
2183

2184
    return NULL;
3,330,378✔
2185
}
19,544,009✔
2186

2187
static SIXELSTATUS
2188
cuckoo_table32_grow(struct cuckoo_table32 *table)
×
2189
{
2190
    struct cuckoo_table32 tmp;
2191
    struct cuckoo_bucket32 *old_buckets;
2192
    size_t old_count;
2193
    size_t i;
2194
    size_t j;
2195
    SIXELSTATUS status;
2196

2197
    if (table == NULL || table->allocator == NULL) {
×
2198
        return SIXEL_BAD_ARGUMENT;
×
2199
    }
2200

2201
    tmp.buckets = NULL;
×
2202
    tmp.bucket_count = 0U;
×
2203
    tmp.bucket_mask = 0U;
×
2204
    tmp.stash_count = 0U;
×
2205
    tmp.entry_count = 0U;
×
2206
    tmp.allocator = table->allocator;
×
2207
    for (i = 0U; i < CUCKOO_STASH_SIZE; ++i) {
×
2208
        tmp.stash_key[i] = CUCKOO_EMPTY_KEY;
×
2209
        tmp.stash_value[i] = 0U;
×
2210
    }
2211

2212
    status = cuckoo_table32_init(&tmp,
×
2213
                                 (table->entry_count + 1U) * 2U,
×
2214
                                 table->allocator);
2215
    if (SIXEL_FAILED(status)) {
×
2216
        return status;
×
2217
    }
2218

2219
    old_buckets = table->buckets;
×
2220
    old_count = table->bucket_count;
×
2221
    for (i = 0U; i < old_count; ++i) {
×
2222
        for (j = 0U; j < CUCKOO_BUCKET_SIZE; ++j) {
×
2223
            if (old_buckets[i].value[j] != 0U) {
×
2224
                status = cuckoo_table32_insert(&tmp,
×
2225
                                               old_buckets[i].key[j],
×
2226
                                               old_buckets[i].value[j]);
×
2227
                if (SIXEL_FAILED(status)) {
×
2228
                    cuckoo_table32_fini(&tmp);
×
2229
                    return status;
×
2230
                }
2231
            }
2232
        }
2233
    }
2234
    for (i = 0U; i < table->stash_count; ++i) {
×
2235
        if (table->stash_value[i] != 0U) {
×
2236
            status = cuckoo_table32_insert(&tmp,
×
2237
                                           table->stash_key[i],
2238
                                           table->stash_value[i]);
2239
            if (SIXEL_FAILED(status)) {
×
2240
                cuckoo_table32_fini(&tmp);
×
2241
                return status;
×
2242
            }
2243
        }
2244
    }
2245

2246
    sixel_allocator_free(table->allocator, old_buckets);
×
2247
    *table = tmp;
×
2248

2249
    return SIXEL_OK;
×
2250
}
2251

2252
static SIXELSTATUS
2253
cuckoo_table32_insert(struct cuckoo_table32 *table,
1,665,189✔
2254
                      uint32_t key,
2255
                      uint32_t value)
2256
{
2257
    uint32_t *slot;
2258
    uint32_t cur_key;
2259
    uint32_t cur_value;
2260
    uint32_t victim_key;
2261
    uint32_t victim_value;
2262
    size_t bucket_index;
2263
    size_t kicks;
2264
    size_t victim_slot;
2265
    struct cuckoo_bucket32 *bucket;
2266
    SIXELSTATUS status;
2267

2268
    if (table == NULL || table->buckets == NULL) {
1,665,189!
2269
        return SIXEL_BAD_ARGUMENT;
×
2270
    }
2271

2272
    slot = cuckoo_table32_lookup(table, key);
1,665,189✔
2273
    if (slot != NULL) {
1,665,189!
2274
        *slot = value;
×
2275
        return SIXEL_OK;
×
2276
    }
2277

2278
    cur_key = key;
1,665,189✔
2279
    cur_value = value;
1,665,189✔
2280
    bucket_index = cuckoo_hash_primary(cur_key, table->bucket_mask);
1,665,189✔
2281
    for (kicks = 0U; kicks < CUCKOO_MAX_KICKS; ++kicks) {
1,665,205!
2282
        bucket = &table->buckets[bucket_index];
1,665,205✔
2283
        if (cuckoo_bucket_insert_direct(bucket, cur_key, cur_value)) {
1,665,205✔
2284
            table->entry_count++;
1,665,189✔
2285
            return SIXEL_OK;
1,665,189✔
2286
        }
2287
        victim_slot = (size_t)((cur_key + kicks) &
16✔
2288
                               (CUCKOO_BUCKET_SIZE - 1U));
2289
        victim_key = bucket->key[victim_slot];
16✔
2290
        victim_value = bucket->value[victim_slot];
16✔
2291
        bucket->key[victim_slot] = cur_key;
16✔
2292
        bucket->value[victim_slot] = cur_value;
16✔
2293
        cur_key = victim_key;
16✔
2294
        cur_value = victim_value;
16✔
2295
        bucket_index = cuckoo_hash_alternate(cur_key,
18✔
2296
                                             bucket_index,
2✔
2297
                                             table->bucket_mask);
2✔
2298
    }
2✔
2299

2300
    if (table->stash_count < CUCKOO_STASH_SIZE) {
×
2301
        table->stash_key[table->stash_count] = cur_key;
×
2302
        table->stash_value[table->stash_count] = cur_value;
×
2303
        table->stash_count++;
×
2304
        table->entry_count++;
×
2305
        return SIXEL_OK;
×
2306
    }
2307

2308
    status = cuckoo_table32_grow(table);
×
2309
    if (SIXEL_FAILED(status)) {
×
2310
        return status;
×
2311
    }
2312

2313
    return cuckoo_table32_insert(table, cur_key, cur_value);
×
2314
}
538,191✔
2315

2316
static SIXELSTATUS
2317
computeHistogram_robinhood(unsigned char const *data,
2318
                           unsigned int length,
2319
                           unsigned long depth,
2320
                           unsigned int step,
2321
                           unsigned int max_sample,
2322
                           tupletable2 * const colorfreqtableP,
2323
                           struct histogram_control const *control,
2324
                           int use_reversible,
2325
                           sixel_allocator_t *allocator);
2326

2327
static SIXELSTATUS
2328
computeHistogram_hopscotch(unsigned char const *data,
2329
                           unsigned int length,
2330
                           unsigned long depth,
2331
                           unsigned int step,
2332
                           unsigned int max_sample,
2333
                           tupletable2 * const colorfreqtableP,
2334
                           struct histogram_control const *control,
2335
                           int use_reversible,
2336
                           sixel_allocator_t *allocator);
2337

2338
static SIXELSTATUS
2339
computeHistogram(unsigned char const    /* in */  *data,
260✔
2340
                 unsigned int           /* in */  length,
2341
                 unsigned long const    /* in */  depth,
2342
                 tupletable2 * const    /* out */ colorfreqtableP,
2343
                 int const              /* in */  qualityMode,
2344
                 int const              /* in */  use_reversible,
2345
                 sixel_allocator_t      /* in */  *allocator)
2346
{
2347
    SIXELSTATUS status = SIXEL_FALSE;
260✔
2348
    typedef uint32_t unit_t;
2349
    unsigned int i, n;
2350
    unit_t *histogram = NULL;
260✔
2351
    unit_t *refmap = NULL;
260✔
2352
    unit_t *ref;
2353
    unsigned int bucket_index;
2354
    unsigned int step;
2355
    unsigned int max_sample;
2356
    size_t hist_size;
2357
    unit_t bucket_value;
2358
    unsigned int component;
2359
    unsigned int reconstructed;
2360
    struct histogram_control control;
2361
    unsigned int depth_u;
2362
    unsigned char reversible_pixel[4];
2363

2364
    switch (qualityMode) {
260!
2365
    case SIXEL_QUALITY_LOW:
120✔
2366
        max_sample = 18383;
227✔
2367
        break;
227✔
2368
    case SIXEL_QUALITY_HIGH:
20✔
2369
        max_sample = 1118383;
30✔
2370
        break;
30✔
2371
    case SIXEL_QUALITY_FULL:
3✔
2372
    default:
2373
        max_sample = 4003079;
3✔
2374
        break;
3✔
2375
    }
2376

2377
    step = length / depth / max_sample * depth;
260✔
2378
    if (step <= 0) {
260✔
2379
        step = depth;
156✔
2380
    }
52✔
2381

2382
    quant_trace(stderr, "making histogram...\n");
260✔
2383

2384
    depth_u = (unsigned int)depth;
260✔
2385
    control = histogram_control_make(depth_u);
260✔
2386
    if (use_reversible) {
260!
2387
        control.reversible_rounding = 1;
×
2388
    }
2389
    if (histogram_lut_policy == SIXEL_LUT_POLICY_ROBINHOOD
260!
2390
        || histogram_lut_policy == SIXEL_LUT_POLICY_HOPSCOTCH) {
260!
2391
        if (histogram_lut_policy == SIXEL_LUT_POLICY_ROBINHOOD) {
×
2392
            status = computeHistogram_robinhood(data,
×
2393
                                                length,
2394
                                                depth,
2395
                                                step,
2396
                                                max_sample,
2397
                                                colorfreqtableP,
2398
                                                &control,
2399
                                                use_reversible,
2400
                                                allocator);
2401
        } else {
2402
            status = computeHistogram_hopscotch(data,
×
2403
                                                length,
2404
                                                depth,
2405
                                                step,
2406
                                                max_sample,
2407
                                                colorfreqtableP,
2408
                                                &control,
2409
                                                use_reversible,
2410
                                                allocator);
2411
        }
2412
        goto end;
×
2413
    }
2414

2415
    hist_size = histogram_dense_size((unsigned int)depth, &control);
260✔
2416
    histogram = (unit_t *)sixel_allocator_calloc(allocator,
378✔
2417
                                                 hist_size,
118✔
2418
                                                 sizeof(unit_t));
2419
    if (histogram == NULL) {
260!
2420
        sixel_helper_set_additional_message(
×
2421
            "unable to allocate memory for histogram.");
2422
        status = SIXEL_BAD_ALLOCATION;
×
2423
        goto end;
×
2424
    }
2425
    ref = refmap = (unit_t *)sixel_allocator_malloc(allocator,
378✔
2426
                                                    hist_size *
118✔
2427
                                                    sizeof(unit_t));
2428
    if (refmap == NULL) {
260!
2429
        sixel_helper_set_additional_message(
×
2430
            "unable to allocate memory for lookup table.");
2431
        status = SIXEL_BAD_ALLOCATION;
×
2432
        goto end;
×
2433
    }
2434

2435
    for (i = 0; i < length; i += step) {
3,572,726✔
2436
        if (use_reversible) {
3,572,466!
2437
            sixel_quant_reversible_pixel(data + i,
×
2438
                                         depth_u,
2439
                                         reversible_pixel);
2440
            bucket_index = histogram_pack_color(reversible_pixel,
×
2441
                                                depth_u,
2442
                                                &control);
2443
        } else {
2444
            bucket_index = histogram_pack_color(data + i,
5,349,672✔
2445
                                                depth_u,
1,777,206✔
2446
                                                &control);
2447
        }
2448
        if (histogram[bucket_index] == 0) {
3,572,466✔
2449
            *ref++ = bucket_index;
294,106✔
2450
        }
98,290✔
2451
        if (histogram[bucket_index] < UINT32_MAX) {
3,572,466!
2452
            histogram[bucket_index]++;
3,572,466✔
2453
        }
1,777,206✔
2454
    }
1,777,206✔
2455

2456
    colorfreqtableP->size = (unsigned int)(ref - refmap);
260✔
2457

2458
    status = alloctupletable(&colorfreqtableP->table,
378✔
2459
                             depth,
118✔
2460
                             (unsigned int)(ref - refmap),
260✔
2461
                             allocator);
118✔
2462
    if (SIXEL_FAILED(status)) {
260!
2463
        goto end;
×
2464
    }
2465
    for (i = 0; i < colorfreqtableP->size; ++i) {
294,366✔
2466
        bucket_value = refmap[i];
294,106✔
2467
        if (histogram[bucket_value] > 0) {
294,106!
2468
            colorfreqtableP->table[i]->value = histogram[bucket_value];
294,106✔
2469
            for (n = 0; n < depth; n++) {
1,176,424✔
2470
                component = (unsigned int)
882,318✔
2471
                    ((bucket_value >> (n * control.channel_bits)) &
1,177,188✔
2472
                     control.channel_mask);
882,318✔
2473
                reconstructed = histogram_reconstruct(component,
882,318✔
2474
                                                      &control);
2475
                if (use_reversible) {
882,318!
2476
                    reconstructed =
×
2477
                        (unsigned int)sixel_quant_reversible_value(
×
2478
                            reconstructed);
2479
                }
2480
                colorfreqtableP->table[i]->tuple[depth - 1 - n]
882,318✔
2481
                    = (sample)reconstructed;
1,177,188✔
2482
            }
294,870✔
2483
        }
98,290✔
2484
    }
98,290✔
2485

2486
    quant_trace(stderr, "%u colors found\n", colorfreqtableP->size);
260✔
2487

2488
    status = SIXEL_OK;
260✔
2489

2490
end:
142✔
2491
    sixel_allocator_free(allocator, refmap);
260✔
2492
    sixel_allocator_free(allocator, histogram);
260✔
2493

2494
    return status;
260✔
2495
}
2496

2497
static SIXELSTATUS
2498
computeHistogram_robinhood(unsigned char const *data,
×
2499
                           unsigned int length,
2500
                           unsigned long depth,
2501
                           unsigned int step,
2502
                           unsigned int max_sample,
2503
                           tupletable2 * const colorfreqtableP,
2504
                           struct histogram_control const *control,
2505
                           int use_reversible,
2506
                           sixel_allocator_t *allocator)
2507
{
2508
    SIXELSTATUS status = SIXEL_FALSE;
×
2509
    struct robinhood_table32 table;
2510
    size_t expected;
2511
    size_t cap_limit;
2512
    size_t index;
2513
    unsigned int depth_u;
2514
    unsigned int i;
2515
    unsigned int n;
2516
    uint32_t bucket_color;
2517
    uint32_t bucket_hash;
2518
    uint32_t entry_color;
2519
    struct robinhood_slot32 *slot;
2520
    unsigned int component;
2521
    unsigned int reconstructed;
2522
    unsigned char reversible_pixel[4];
2523

2524
    /*
2525
     * The ASCII sketch below shows how the sparse table stores samples:
2526
     *
2527
     *   [hash]->(key,value,distance)  Robin Hood probing keeps dense tails.
2528
     */
2529
    table.slots = NULL;
×
2530
    table.capacity = 0U;
×
2531
    table.count = 0U;
×
2532
    table.allocator = allocator;
×
2533
    cap_limit = (size_t)1U << 20;
×
2534
    expected = max_sample;
×
2535
    if (expected < 256U) {
×
2536
        expected = 256U;
×
2537
    }
2538
    if (expected > cap_limit) {
×
2539
        expected = cap_limit;
×
2540
    }
2541

2542
    status = robinhood_table32_init(&table, expected, allocator);
×
2543
    if (SIXEL_FAILED(status)) {
×
2544
        sixel_helper_set_additional_message(
×
2545
            "unable to allocate robinhood histogram.");
2546
        goto end;
×
2547
    }
2548

2549
    depth_u = (unsigned int)depth;
×
2550
    for (i = 0U; i < length; i += step) {
×
2551
        if (use_reversible) {
×
2552
            sixel_quant_reversible_pixel(data + i, depth_u,
×
2553
                                         reversible_pixel);
2554
            bucket_color = histogram_pack_color(reversible_pixel,
×
2555
                                                depth_u, control);
2556
        } else {
2557
            bucket_color = histogram_pack_color(data + i,
×
2558
                                                depth_u, control);
2559
        }
2560
        bucket_hash = histogram_hash_mix(bucket_color);
×
2561
        /*
2562
         * Hash probing uses the mixed key while the slot stores the
2563
         * original quantized RGB value:
2564
         *
2565
         *   hash --> [slot]
2566
         *             |color|count|
2567
         */
2568
        slot = robinhood_table32_lookup(&table,
×
2569
                                        bucket_hash,
2570
                                        bucket_color);
2571
        if (slot == NULL) {
×
2572
            status = robinhood_table32_insert(&table,
×
2573
                                              bucket_hash,
2574
                                              bucket_color,
2575
                                              1U);
2576
            if (SIXEL_FAILED(status)) {
×
2577
                sixel_helper_set_additional_message(
×
2578
                    "unable to grow robinhood histogram.");
2579
                goto end;
×
2580
            }
2581
        } else if (slot->value < UINT32_MAX) {
×
2582
            slot->value++;
×
2583
        }
2584
    }
2585

2586
    if (table.count > UINT_MAX) {
×
2587
        sixel_helper_set_additional_message(
×
2588
            "too many unique colors for histogram.");
2589
        status = SIXEL_BAD_ARGUMENT;
×
2590
        goto end;
×
2591
    }
2592

2593
    colorfreqtableP->size = (unsigned int)table.count;
×
2594
    status = alloctupletable(&colorfreqtableP->table,
×
2595
                             depth_u,
2596
                             (unsigned int)table.count,
×
2597
                             allocator);
2598
    if (SIXEL_FAILED(status)) {
×
2599
        goto end;
×
2600
    }
2601

2602
    index = 0U;
×
2603
    /*
2604
     * Stream slots in the hash traversal order to avoid qsort overhead.
2605
     * This favors throughput over identical palette ordering.
2606
     */
2607
    for (i = 0U; i < table.capacity; ++i) {
×
2608
        slot = &table.slots[i];
×
2609
        if (slot->value == 0U) {
×
2610
            continue;
×
2611
        }
2612
        if (index >= colorfreqtableP->size) {
×
2613
            break;
×
2614
        }
2615
        entry_color = slot->color;
×
2616
        colorfreqtableP->table[index]->value = slot->value;
×
2617
        for (n = 0U; n < depth_u; ++n) {
×
2618
            component = (unsigned int)
×
2619
                ((entry_color >> (n * control->channel_bits))
×
2620
                 & control->channel_mask);
×
2621
            reconstructed = histogram_reconstruct(component, control);
×
2622
            if (use_reversible) {
×
2623
                reconstructed =
×
2624
                    (unsigned int)sixel_quant_reversible_value(
×
2625
                        reconstructed);
2626
            }
2627
            colorfreqtableP->table[index]->tuple[depth_u - 1U - n]
×
2628
                = (sample)reconstructed;
×
2629
        }
2630
        index++;
×
2631
    }
2632

2633
    status = SIXEL_OK;
×
2634

2635
end:
2636
    robinhood_table32_fini(&table);
×
2637

2638
    return status;
×
2639
}
2640

2641
static SIXELSTATUS
2642
computeHistogram_hopscotch(unsigned char const *data,
×
2643
                           unsigned int length,
2644
                           unsigned long depth,
2645
                           unsigned int step,
2646
                           unsigned int max_sample,
2647
                           tupletable2 * const colorfreqtableP,
2648
                           struct histogram_control const *control,
2649
                           int use_reversible,
2650
                           sixel_allocator_t *allocator)
2651
{
2652
    SIXELSTATUS status = SIXEL_FALSE;
×
2653
    struct hopscotch_table32 table;
2654
    size_t expected;
2655
    size_t cap_limit;
2656
    size_t index;
2657
    unsigned int depth_u;
2658
    unsigned int i;
2659
    unsigned int n;
2660
    uint32_t bucket_color;
2661
    uint32_t bucket_hash;
2662
    uint32_t entry_color;
2663
    struct hopscotch_slot32 *slot;
2664
    unsigned int component;
2665
    unsigned int reconstructed;
2666
    unsigned char reversible_pixel[4];
2667

2668
    /*
2669
     * Hopscotch hashing stores the local neighbourhood using the map below:
2670
     *
2671
     *   [home] hopinfo bits ---> |slot+0|slot+1|slot+2| ...
2672
     *                              ^ entries hop within this window.
2673
     */
2674
    table.slots = NULL;
×
2675
    table.hopinfo = NULL;
×
2676
    table.capacity = 0U;
×
2677
    table.count = 0U;
×
2678
    table.neighborhood = HOPSCOTCH_DEFAULT_NEIGHBORHOOD;
×
2679
    table.allocator = allocator;
×
2680
    cap_limit = (size_t)1U << 20;
×
2681
    expected = max_sample;
×
2682
    if (expected < 256U) {
×
2683
        expected = 256U;
×
2684
    }
2685
    if (expected > cap_limit) {
×
2686
        expected = cap_limit;
×
2687
    }
2688

2689
    status = hopscotch_table32_init(&table, expected, allocator);
×
2690
    if (SIXEL_FAILED(status)) {
×
2691
        sixel_helper_set_additional_message(
×
2692
            "unable to allocate hopscotch histogram.");
2693
        goto end;
×
2694
    }
2695

2696
    depth_u = (unsigned int)depth;
×
2697
    for (i = 0U; i < length; i += step) {
×
2698
        if (use_reversible) {
×
2699
            sixel_quant_reversible_pixel(data + i, depth_u,
×
2700
                                         reversible_pixel);
2701
            bucket_color = histogram_pack_color(reversible_pixel,
×
2702
                                                depth_u, control);
2703
        } else {
2704
            bucket_color = histogram_pack_color(data + i,
×
2705
                                                depth_u, control);
2706
        }
2707
        bucket_hash = histogram_hash_mix(bucket_color);
×
2708
        /*
2709
         * Hopscotch buckets mirror the robinhood layout, keeping the
2710
         * quantized color next to the count so we never derive it from
2711
         * the scrambled hash key.
2712
         */
2713
        slot = hopscotch_table32_lookup(&table,
×
2714
                                        bucket_hash,
2715
                                        bucket_color);
2716
        if (slot == NULL) {
×
2717
            status = hopscotch_table32_insert(&table,
×
2718
                                              bucket_hash,
2719
                                              bucket_color,
2720
                                              1U);
2721
            if (SIXEL_FAILED(status)) {
×
2722
                sixel_helper_set_additional_message(
×
2723
                    "unable to grow hopscotch histogram.");
2724
                goto end;
×
2725
            }
2726
        } else if (slot->value < UINT32_MAX) {
×
2727
            slot->value++;
×
2728
        }
2729
    }
2730

2731
    if (table.count > UINT_MAX) {
×
2732
        sixel_helper_set_additional_message(
×
2733
            "too many unique colors for histogram.");
2734
        status = SIXEL_BAD_ARGUMENT;
×
2735
        goto end;
×
2736
    }
2737

2738
    colorfreqtableP->size = (unsigned int)table.count;
×
2739
    status = alloctupletable(&colorfreqtableP->table,
×
2740
                             depth_u,
2741
                             (unsigned int)table.count,
×
2742
                             allocator);
2743
    if (SIXEL_FAILED(status)) {
×
2744
        goto end;
×
2745
    }
2746

2747
    index = 0U;
×
2748
    /*
2749
     * Stream slots in the hash traversal order to avoid qsort overhead.
2750
     * This favors throughput over identical palette ordering.
2751
     */
2752
    for (i = 0U; i < table.capacity; ++i) {
×
2753
        slot = &table.slots[i];
×
2754
        if (slot->key == HOPSCOTCH_EMPTY_KEY || slot->value == 0U) {
×
2755
            continue;
×
2756
        }
2757
        if (index >= colorfreqtableP->size) {
×
2758
            break;
×
2759
        }
2760
        entry_color = slot->color;
×
2761
        colorfreqtableP->table[index]->value = slot->value;
×
2762
        for (n = 0U; n < depth_u; ++n) {
×
2763
            component = (unsigned int)
×
2764
                ((entry_color >> (n * control->channel_bits))
×
2765
                 & control->channel_mask);
×
2766
            reconstructed = histogram_reconstruct(component, control);
×
2767
            if (use_reversible) {
×
2768
                reconstructed =
×
2769
                    (unsigned int)sixel_quant_reversible_value(
×
2770
                        reconstructed);
2771
            }
2772
            colorfreqtableP->table[index]->tuple[depth_u - 1U - n]
×
2773
                = (sample)reconstructed;
×
2774
        }
2775
        index++;
×
2776
    }
2777

2778
    status = SIXEL_OK;
×
2779

2780
end:
2781
    hopscotch_table32_fini(&table);
×
2782

2783
    return status;
×
2784
}
2785

2786
SIXELSTATUS
2787
sixel_quant_cache_prepare(unsigned short **cachetable,
267✔
2788
                          size_t *cachetable_size,
2789
                          int lut_policy,
2790
                          int reqcolor,
2791
                          sixel_allocator_t *allocator)
2792
{
2793
    SIXELSTATUS status;
2794
    struct histogram_control control;
2795
    struct cuckoo_table32 *table;
2796
    size_t expected;
2797
    size_t buckets;
2798
    size_t cap_limit;
2799
    int normalized;
2800

2801
    if (cachetable == NULL || allocator == NULL) {
267!
2802
        return SIXEL_BAD_ARGUMENT;
×
2803
    }
2804

2805
    /*
2806
     * The cache pointer always references the same ladder:
2807
     *
2808
     *   cache -> cuckoo_table32 -> buckets
2809
     *                           -> stash
2810
     */
2811
    normalized = lut_policy;
267✔
2812
    if (normalized == SIXEL_LUT_POLICY_AUTO) {
267!
2813
        normalized = histogram_lut_policy;
267✔
2814
    }
109✔
2815
    if (normalized == SIXEL_LUT_POLICY_AUTO) {
267!
2816
        normalized = SIXEL_LUT_POLICY_6BIT;
267✔
2817
    }
109✔
2818

2819
    control = histogram_control_make_for_policy(3U, normalized);
267✔
2820
    if (control.channel_shift == 0U) {
267!
2821
        expected = (size_t)reqcolor * 64U;
×
2822
        cap_limit = (size_t)1U << 20;
×
2823
        if (expected < 512U) {
×
2824
            expected = 512U;
×
2825
        }
2826
        if (expected > cap_limit) {
×
2827
            expected = cap_limit;
×
2828
        }
2829
    } else {
2830
        expected = histogram_dense_size(3U, &control);
267✔
2831
        if (expected == 0U) {
267!
2832
            expected = CUCKOO_BUCKET_SIZE;
×
2833
        }
2834
    }
2835

2836
    table = (struct cuckoo_table32 *)*cachetable;
267✔
2837
    if (table != NULL) {
267✔
2838
        buckets = cuckoo_round_buckets(expected);
3✔
2839
        if (table->bucket_count < buckets) {
3!
2840
            cuckoo_table32_fini(table);
×
2841
            sixel_allocator_free(allocator, table);
×
2842
            table = NULL;
×
2843
            *cachetable = NULL;
×
2844
        } else {
2845
            cuckoo_table32_clear(table);
3✔
2846
        }
2847
    }
1✔
2848
    if (table == NULL) {
267✔
2849
        table = (struct cuckoo_table32 *)sixel_allocator_malloc(
264✔
2850
            allocator, sizeof(struct cuckoo_table32));
108✔
2851
        if (table == NULL) {
264!
2852
            sixel_helper_set_additional_message(
×
2853
                "unable to allocate cuckoo cache state.");
2854
            return SIXEL_BAD_ALLOCATION;
×
2855
        }
2856
        memset(table, 0, sizeof(struct cuckoo_table32));
264✔
2857
        status = cuckoo_table32_init(table, expected, allocator);
264✔
2858
        if (SIXEL_FAILED(status)) {
264!
2859
            sixel_allocator_free(allocator, table);
×
2860
            sixel_helper_set_additional_message(
×
2861
                "unable to initialize cuckoo cache.");
2862
            return status;
×
2863
        }
2864
        *cachetable = (unsigned short *)table;
264✔
2865
    }
108✔
2866

2867
    if (cachetable_size != NULL) {
267!
2868
        *cachetable_size = table->bucket_count * CUCKOO_BUCKET_SIZE;
267✔
2869
    }
109✔
2870

2871
    return SIXEL_OK;
267✔
2872
}
109✔
2873

2874
void
2875
sixel_quant_cache_clear(unsigned short *cachetable,
264✔
2876
                        int lut_policy)
2877
{
2878
    struct cuckoo_table32 *table;
2879

2880
    (void)lut_policy;
108✔
2881
    if (cachetable == NULL) {
264!
2882
        return;
×
2883
    }
2884

2885
    table = (struct cuckoo_table32 *)cachetable;
264✔
2886
    cuckoo_table32_clear(table);
264✔
2887
}
108✔
2888

2889
void
2890
sixel_quant_cache_release(unsigned short *cachetable,
529✔
2891
                          int lut_policy,
2892
                          sixel_allocator_t *allocator)
2893
{
2894
    struct cuckoo_table32 *table;
2895

2896
    (void)lut_policy;
183✔
2897
    if (cachetable == NULL || allocator == NULL) {
529!
2898
        return;
265✔
2899
    }
2900

2901
    table = (struct cuckoo_table32 *)cachetable;
264✔
2902
    cuckoo_table32_fini(table);
264✔
2903
    sixel_allocator_free(allocator, table);
264✔
2904
}
183✔
2905

2906

2907
static int
2908
computeColorMapFromInput(unsigned char const *data,
260✔
2909
                         unsigned int const length,
2910
                         unsigned int const depth,
2911
                         unsigned int const reqColors,
2912
                         int const methodForLargest,
2913
                         int const methodForRep,
2914
                         int const qualityMode,
2915
                         int const force_palette,
2916
                         int const use_reversible,
2917
                         tupletable2 * const colormapP,
2918
                         unsigned int *origcolors,
2919
                         sixel_allocator_t *allocator)
2920
{
2921
/*----------------------------------------------------------------------------
2922
   Produce a colormap containing the best colors to represent the
2923
   image stream in file 'ifP'.  Figure it out using the median cut
2924
   technique.
2925

2926
   The colormap will have 'reqcolors' or fewer colors in it, unless
2927
   'allcolors' is true, in which case it will have all the colors that
2928
   are in the input.
2929

2930
   The colormap has the same maxval as the input.
2931

2932
   Put the colormap in newly allocated storage as a tupletable2
2933
   and return its address as *colormapP.  Return the number of colors in
2934
   it as *colorsP and its maxval as *colormapMaxvalP.
2935

2936
   Return the characteristics of the input file as
2937
   *formatP and *freqPamP.  (This information is not really
2938
   relevant to our colormap mission; just a fringe benefit).
2939
-----------------------------------------------------------------------------*/
2940
    SIXELSTATUS status = SIXEL_FALSE;
260✔
2941
    tupletable2 colorfreqtable = {0, NULL};
260✔
2942
    unsigned int i;
2943
    unsigned int n;
2944

2945
    status = computeHistogram(data, length, depth,
378✔
2946
                              &colorfreqtable, qualityMode,
118✔
2947
                              use_reversible, allocator);
118✔
2948
    if (SIXEL_FAILED(status)) {
260!
2949
        goto end;
×
2950
    }
2951
    if (origcolors) {
260!
2952
        *origcolors = colorfreqtable.size;
260✔
2953
    }
118✔
2954

2955
    if (colorfreqtable.size <= reqColors) {
260✔
2956
        quant_trace(stderr,
286✔
2957
                    "Image already has few enough colors (<=%d).  "
2958
                    "Keeping same colors.\n", reqColors);
95✔
2959
        /* *colormapP = colorfreqtable; */
2960
        colormapP->size = colorfreqtable.size;
191✔
2961
        status = alloctupletable(&colormapP->table, depth, colorfreqtable.size, allocator);
191✔
2962
        if (SIXEL_FAILED(status)) {
191!
2963
            goto end;
×
2964
        }
2965
        for (i = 0; i < colorfreqtable.size; ++i) {
3,198✔
2966
            colormapP->table[i]->value = colorfreqtable.table[i]->value;
3,007✔
2967
            for (n = 0; n < depth; ++n) {
12,028✔
2968
                colormapP->table[i]->tuple[n] = colorfreqtable.table[i]->tuple[n];
9,021✔
2969
            }
4,203✔
2970
            if (use_reversible) {
3,007!
2971
                sixel_quant_reversible_tuple(colormapP->table[i]->tuple,
×
2972
                                             depth);
2973
            }
2974
        }
1,401✔
2975
    } else {
95✔
2976
        quant_trace(stderr, "choosing %d colors...\n", reqColors);
69✔
2977
        status = mediancut(colorfreqtable, depth, reqColors,
92✔
2978
                           methodForLargest, methodForRep,
23✔
2979
                           use_reversible, colormapP, allocator);
23✔
2980
        if (SIXEL_FAILED(status)) {
69!
2981
            goto end;
×
2982
        }
2983
        quant_trace(stderr, "%d colors are choosed.\n", colorfreqtable.size);
69✔
2984
    }
2985

2986
    if (force_palette) {
260!
2987
        status = force_palette_completion(colormapP, depth, reqColors,
×
2988
                                          colorfreqtable, allocator);
2989
        if (SIXEL_FAILED(status)) {
×
2990
            goto end;
×
2991
        }
2992
    }
2993

2994
    status = SIXEL_OK;
260✔
2995

2996
end:
142✔
2997
    sixel_allocator_free(allocator, colorfreqtable.table);
260✔
2998
    return status;
260✔
2999
}
3000

3001

3002
/* diffuse error energy to surround pixels (normal strategy) */
3003
static void
3004
error_diffuse_normal(
281,667,771✔
3005
    unsigned char /* in */    *data,      /* base address of pixel buffer */
3006
    int           /* in */    pos,        /* address of the destination pixel */
3007
    int           /* in */    depth,      /* color depth in bytes */
3008
    int           /* in */    error,      /* error energy */
3009
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
3010
    int           /* in */    denominator /* denominator of diffusion coefficient */)
3011
{
3012
    int c;
3013

3014
    data += pos * depth;
281,667,771✔
3015

3016
    c = *data + (error * numerator * 2 / denominator + 1) / 2;
281,667,771✔
3017
    if (c < 0) {
281,667,771✔
3018
        c = 0;
2,655,543✔
3019
    }
885,917✔
3020
    if (c >= 1 << 8) {
281,667,771✔
3021
        c = (1 << 8) - 1;
1,434,889✔
3022
    }
436,601✔
3023
    *data = (unsigned char)c;
281,667,771✔
3024
}
281,667,771✔
3025

3026
/* error diffusion with fast strategy */
3027
static void
3028
error_diffuse_fast(
169,469,067✔
3029
    unsigned char /* in */    *data,      /* base address of pixel buffer */
3030
    int           /* in */    pos,        /* address of the destination pixel */
3031
    int           /* in */    depth,      /* color depth in bytes */
3032
    int           /* in */    error,      /* error energy */
3033
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
3034
    int           /* in */    denominator /* denominator of diffusion coefficient */)
3035
{
3036
    int c;
3037

3038
    data += pos * depth;
169,469,067✔
3039

3040
    c = *data + error * numerator / denominator;
169,469,067✔
3041
    if (c < 0) {
169,469,067✔
3042
        c = 0;
7,485,418✔
3043
    }
2,822,832✔
3044
    if (c >= 1 << 8) {
169,469,067✔
3045
        c = (1 << 8) - 1;
455,515✔
3046
    }
148,827✔
3047
    *data = (unsigned char)c;
169,469,067✔
3048
}
169,469,067✔
3049

3050

3051
/* error diffusion with precise strategy */
3052
static void
3053
error_diffuse_precise(
6,111,369✔
3054
    unsigned char /* in */    *data,      /* base address of pixel buffer */
3055
    int           /* in */    pos,        /* address of the destination pixel */
3056
    int           /* in */    depth,      /* color depth in bytes */
3057
    int           /* in */    error,      /* error energy */
3058
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
3059
    int           /* in */    denominator /* denominator of diffusion coefficient */)
3060
{
3061
    int c;
3062

3063
    data += pos * depth;
6,111,369✔
3064

3065
    c = (int)(*data + error * numerator / (double)denominator + 0.5);
6,111,369✔
3066
    if (c < 0) {
6,111,369✔
3067
        c = 0;
70,495✔
3068
    }
25,489✔
3069
    if (c >= 1 << 8) {
6,111,369!
3070
        c = (1 << 8) - 1;
×
3071
    }
3072
    *data = (unsigned char)c;
6,111,369✔
3073
}
6,111,369✔
3074

3075

3076
typedef void (*diffuse_fixed_carry_mode)(int32_t *carry_curr,
3077
                                         int32_t *carry_next,
3078
                                         int32_t *carry_far,
3079
                                         int width,
3080
                                         int height,
3081
                                         int depth,
3082
                                         int x,
3083
                                         int y,
3084
                                         int32_t error,
3085
                                         int direction,
3086
                                         int channel);
3087

3088

3089
typedef void (*diffuse_varerr_mode)(unsigned char *data,
3090
                                    int width,
3091
                                    int height,
3092
                                    int x,
3093
                                    int y,
3094
                                    int depth,
3095
                                    int32_t error,
3096
                                    int index,
3097
                                    int direction);
3098

3099
typedef void (*diffuse_varerr_carry_mode)(int32_t *carry_curr,
3100
                                          int32_t *carry_next,
3101
                                          int32_t *carry_far,
3102
                                          int width,
3103
                                          int height,
3104
                                          int depth,
3105
                                          int x,
3106
                                          int y,
3107
                                          int32_t error,
3108
                                          int index,
3109
                                          int direction,
3110
                                          int channel);
3111

3112

3113
static int32_t
3114
diffuse_varerr_term(int32_t error, int weight, int denom)
×
3115
{
3116
    int64_t delta;
3117

3118
    delta = (int64_t)error * (int64_t)weight;
×
3119
    if (delta >= 0) {
×
3120
        delta = (delta + denom / 2) / denom;
×
3121
    } else {
3122
        delta = (delta - denom / 2) / denom;
×
3123
    }
3124

3125
    return (int32_t)delta;
×
3126
}
3127

3128

3129
static int32_t
3130
diffuse_fixed_term(int32_t error, int numerator, int denominator)
×
3131
{
3132
    int64_t delta;
3133

3134
    delta = (int64_t)error * (int64_t)numerator;
×
3135
    if (delta >= 0) {
×
3136
        delta = (delta + denominator / 2) / denominator;
×
3137
    } else {
3138
        delta = (delta - denominator / 2) / denominator;
×
3139
    }
3140

3141
    return (int32_t)delta;
×
3142
}
3143

3144

3145
static void
3146
diffuse_varerr_apply_direct(unsigned char *target, int depth, size_t offset,
×
3147
                            int32_t delta)
3148
{
3149
    int64_t value;
3150
    int result;
3151

3152
    value = (int64_t)target[offset * depth] << VARERR_SCALE_SHIFT;
×
3153
    value += delta;
×
3154
    if (value < 0) {
×
3155
        value = 0;
×
3156
    } else {
3157
        int64_t max_value;
3158

3159
        max_value = VARERR_MAX_VALUE;
×
3160
        if (value > max_value) {
×
3161
            value = max_value;
×
3162
        }
3163
    }
3164

3165
    result = (int)((value + VARERR_ROUND) >> VARERR_SCALE_SHIFT);
×
3166
    if (result < 0) {
×
3167
        result = 0;
×
3168
    }
3169
    if (result > 255) {
×
3170
        result = 255;
×
3171
    }
3172
    target[offset * depth] = (unsigned char)result;
×
3173
}
×
3174

3175

3176
static void
3177
diffuse_lso2(unsigned char *data, int width, int height,
×
3178
             int x, int y, int depth, int32_t error,
3179
             int index, int direction)
3180
{
3181
    const int (*table)[7];
3182
    const int *entry;
3183
    int denom;
3184
    int32_t term_r = 0;
×
3185
    int32_t term_r2 = 0;
×
3186
    int32_t term_dl = 0;
×
3187
    int32_t term_d = 0;
×
3188
    int32_t term_dr = 0;
×
3189
    int32_t term_d2 = 0;
×
3190
    size_t offset;
3191

3192
    if (error == 0) {
×
3193
        return;
×
3194
    }
3195
    if (index < 0) {
×
3196
        index = 0;
×
3197
    }
3198
    if (index > 255) {
×
3199
        index = 255;
×
3200
    }
3201

3202
    table = lso2_table();
×
3203
    entry = table[index];
×
3204
    denom = entry[6];
×
3205
    if (denom == 0) {
×
3206
        return;
×
3207
    }
3208

3209
    term_r = diffuse_varerr_term(error, entry[0], denom);
×
3210
    term_r2 = diffuse_varerr_term(error, entry[1], denom);
×
3211
    term_dl = diffuse_varerr_term(error, entry[2], denom);
×
3212
    term_d = diffuse_varerr_term(error, entry[3], denom);
×
3213
    term_dr = diffuse_varerr_term(error, entry[4], denom);
×
3214
    term_d2 = diffuse_varerr_term(error, entry[5], denom);
×
3215

3216

3217
    if (direction >= 0) {
×
3218
        if (x + 1 < width) {
×
3219
            offset = (size_t)y * (size_t)width + (size_t)(x + 1);
×
3220
            diffuse_varerr_apply_direct(data, depth, offset, term_r);
×
3221
        }
3222
        if (x + 2 < width) {
×
3223
            offset = (size_t)y * (size_t)width + (size_t)(x + 2);
×
3224
            diffuse_varerr_apply_direct(data, depth, offset, term_r2);
×
3225
        }
3226
        if (y + 1 < height && x - 1 >= 0) {
×
3227
            offset = (size_t)(y + 1) * (size_t)width;
×
3228
            offset += (size_t)(x - 1);
×
3229
            diffuse_varerr_apply_direct(data, depth, offset, term_dl);
×
3230
        }
3231
        if (y + 1 < height) {
×
3232
            offset = (size_t)(y + 1) * (size_t)width + (size_t)x;
×
3233
            diffuse_varerr_apply_direct(data, depth, offset, term_d);
×
3234
        }
3235
        if (y + 1 < height && x + 1 < width) {
×
3236
            offset = (size_t)(y + 1) * (size_t)width;
×
3237
            offset += (size_t)(x + 1);
×
3238
            diffuse_varerr_apply_direct(data, depth, offset, term_dr);
×
3239
        }
3240
        if (y + 2 < height) {
×
3241
            offset = (size_t)(y + 2) * (size_t)width + (size_t)x;
×
3242
            diffuse_varerr_apply_direct(data, depth, offset, term_d2);
×
3243
        }
3244
    } else {
3245
        if (x - 1 >= 0) {
×
3246
            offset = (size_t)y * (size_t)width + (size_t)(x - 1);
×
3247
            diffuse_varerr_apply_direct(data, depth, offset, term_r);
×
3248
        }
3249
        if (x - 2 >= 0) {
×
3250
            offset = (size_t)y * (size_t)width + (size_t)(x - 2);
×
3251
            diffuse_varerr_apply_direct(data, depth, offset, term_r2);
×
3252
        }
3253
        if (y + 1 < height && x + 1 < width) {
×
3254
            offset = (size_t)(y + 1) * (size_t)width;
×
3255
            offset += (size_t)(x + 1);
×
3256
            diffuse_varerr_apply_direct(data, depth, offset, term_dl);
×
3257
        }
3258
        if (y + 1 < height) {
×
3259
            offset = (size_t)(y + 1) * (size_t)width + (size_t)x;
×
3260
            diffuse_varerr_apply_direct(data, depth, offset, term_d);
×
3261
        }
3262
        if (y + 1 < height && x - 1 >= 0) {
×
3263
            offset = (size_t)(y + 1) * (size_t)width;
×
3264
            offset += (size_t)(x - 1);
×
3265
            diffuse_varerr_apply_direct(data, depth, offset, term_dr);
×
3266
        }
3267
        if (y + 2 < height) {
×
3268
            offset = (size_t)(y + 2) * (size_t)width + (size_t)x;
×
3269
            diffuse_varerr_apply_direct(data, depth, offset, term_d2);
×
3270
        }
3271
    }
3272
}
3273

3274

3275
static void
3276
diffuse_lso2_carry(int32_t *carry_curr, int32_t *carry_next, int32_t *carry_far,
×
3277
                   int width, int height, int depth,
3278
                   int x, int y, int32_t error,
3279
                   int index, int direction, int channel)
3280
{
3281
    const int (*table)[7];
3282
    const int *entry;
3283
    int denom;
3284
    int32_t term_r = 0;
×
3285
    int32_t term_r2 = 0;
×
3286
    int32_t term_dl = 0;
×
3287
    int32_t term_d = 0;
×
3288
    int32_t term_dr = 0;
×
3289
    int32_t term_d2 = 0;
×
3290
    size_t base;
3291

3292
    if (error == 0) {
×
3293
        return;
×
3294
    }
3295
    if (index < 0) {
×
3296
        index = 0;
×
3297
    }
3298
    if (index > 255) {
×
3299
        index = 255;
×
3300
    }
3301

3302
    table = lso2_table();
×
3303
    entry = table[index];
×
3304
    denom = entry[6];
×
3305
    if (denom == 0) {
×
3306
        return;
×
3307
    }
3308

3309
    term_r = diffuse_varerr_term(error, entry[0], denom);
×
3310
    term_r2 = diffuse_varerr_term(error, entry[1], denom);
×
3311
    term_dl = diffuse_varerr_term(error, entry[2], denom);
×
3312
    term_d = diffuse_varerr_term(error, entry[3], denom);
×
3313
    term_dr = diffuse_varerr_term(error, entry[4], denom);
×
3314
    term_d2 = error - term_r - term_r2 - term_dl - term_d - term_dr;
×
3315

3316
    if (direction >= 0) {
×
3317
        if (x + 1 < width) {
×
3318
            base = ((size_t)(x + 1) * (size_t)depth) + (size_t)channel;
×
3319
            carry_curr[base] += term_r;
×
3320
        }
3321
        if (x + 2 < width) {
×
3322
            base = ((size_t)(x + 2) * (size_t)depth) + (size_t)channel;
×
3323
            carry_curr[base] += term_r2;
×
3324
        }
3325
        if (y + 1 < height && x - 1 >= 0) {
×
3326
            base = ((size_t)(x - 1) * (size_t)depth) + (size_t)channel;
×
3327
            carry_next[base] += term_dl;
×
3328
        }
3329
        if (y + 1 < height) {
×
3330
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
3331
            carry_next[base] += term_d;
×
3332
        }
3333
        if (y + 1 < height && x + 1 < width) {
×
3334
            base = ((size_t)(x + 1) * (size_t)depth) + (size_t)channel;
×
3335
            carry_next[base] += term_dr;
×
3336
        }
3337
        if (y + 2 < height) {
×
3338
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
3339
            carry_far[base] += term_d2;
×
3340
        }
3341
    } else {
3342
        if (x - 1 >= 0) {
×
3343
            base = ((size_t)(x - 1) * (size_t)depth) + (size_t)channel;
×
3344
            carry_curr[base] += term_r;
×
3345
        }
3346
        if (x - 2 >= 0) {
×
3347
            base = ((size_t)(x - 2) * (size_t)depth) + (size_t)channel;
×
3348
            carry_curr[base] += term_r;
×
3349
        }
3350
        if (y + 1 < height && x + 1 < width) {
×
3351
            base = ((size_t)(x + 1) * (size_t)depth) + (size_t)channel;
×
3352
            carry_next[base] += term_dl;
×
3353
        }
3354
        if (y + 1 < height) {
×
3355
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
3356
            carry_next[base] += term_d;
×
3357
        }
3358
        if (y + 1 < height && x - 1 >= 0) {
×
3359
            base = ((size_t)(x - 1) * (size_t)depth) + (size_t)channel;
×
3360
            carry_next[base] += term_dr;
×
3361
        }
3362
        if (y + 2 < height) {
×
3363
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
3364
            carry_far[base] += term_d2;
×
3365
        }
3366
    }
3367
}
3368

3369

3370
static void
3371
scanline_params(int serpentine, int index, int limit,
59,650✔
3372
                int *start, int *end, int *step, int *direction)
3373
{
3374
    if (serpentine && (index & 1)) {
59,650✔
3375
        *start = limit - 1;
675✔
3376
        *end = -1;
675✔
3377
        *step = -1;
675✔
3378
        *direction = -1;
675✔
3379
    } else {
225✔
3380
        *start = 0;
58,975✔
3381
        *end = limit;
58,975✔
3382
        *step = 1;
58,975✔
3383
        *direction = 1;
58,975✔
3384
    }
3385
}
59,650✔
3386

3387

3388
static SIXELSTATUS
3389
apply_palette_positional(
×
3390
    sixel_index_t *result,
3391
    unsigned char *data,
3392
    int width,
3393
    int height,
3394
    int depth,
3395
    unsigned char *palette,
3396
    int reqcolor,
3397
    int methodForDiffuse,
3398
    int methodForScan,
3399
    int foptimize_palette,
3400
    int (*f_lookup)(const unsigned char *pixel,
3401
                    int depth,
3402
                    const unsigned char *palette,
3403
                    int reqcolor,
3404
                    unsigned short *cachetable,
3405
                    int complexion),
3406
    unsigned short *indextable,
3407
    int complexion,
3408
    unsigned char copy[],
3409
    unsigned char new_palette[],
3410
    unsigned short migration_map[],
3411
    int *ncolors)
3412
{
3413
    int serpentine;
3414
    int y;
3415
    float (*f_mask)(int x, int y, int c);
3416

3417
    switch (methodForDiffuse) {
×
3418
    case SIXEL_DIFFUSE_A_DITHER:
3419
        f_mask = mask_a;
×
3420
        break;
×
3421
    case SIXEL_DIFFUSE_X_DITHER:
×
3422
    default:
3423
        f_mask = mask_x;
×
3424
        break;
×
3425
    }
3426

3427
    serpentine = (methodForScan == SIXEL_SCAN_SERPENTINE);
×
3428

3429
    if (foptimize_palette) {
×
3430
        int x;
3431

3432
        *ncolors = 0;
×
3433
        memset(new_palette, 0x00,
×
3434
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
3435
        memset(migration_map, 0x00,
×
3436
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
3437
        for (y = 0; y < height; ++y) {
×
3438
            int start;
3439
            int end;
3440
            int step;
3441
            int direction;
3442

3443
            scanline_params(serpentine, y, width,
×
3444
                            &start, &end, &step, &direction);
3445
            (void)direction;
3446
            for (x = start; x != end; x += step) {
×
3447
                int pos;
3448
                int d;
3449
                int color_index;
3450

3451
                pos = y * width + x;
×
3452
                for (d = 0; d < depth; ++d) {
×
3453
                    int val;
3454

3455
                    val = data[pos * depth + d]
×
3456
                        + f_mask(x, y, d) * 32;
×
3457
                    copy[d] = val < 0 ? 0
×
3458
                               : val > 255 ? 255 : val;
×
3459
                }
3460
                color_index = f_lookup(copy, depth, palette,
×
3461
                                       reqcolor, indextable,
3462
                                       complexion);
3463
                if (migration_map[color_index] == 0) {
×
3464
                    result[pos] = *ncolors;
×
3465
                    for (d = 0; d < depth; ++d) {
×
3466
                        new_palette[*ncolors * depth + d]
×
3467
                            = palette[color_index * depth + d];
×
3468
                    }
3469
                    ++*ncolors;
×
3470
                    migration_map[color_index] = *ncolors;
×
3471
                } else {
3472
                    result[pos] = migration_map[color_index] - 1;
×
3473
                }
3474
            }
3475
        }
3476
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
×
3477
    } else {
3478
        int x;
3479

3480
        for (y = 0; y < height; ++y) {
×
3481
            int start;
3482
            int end;
3483
            int step;
3484
            int direction;
3485

3486
            scanline_params(serpentine, y, width,
×
3487
                            &start, &end, &step, &direction);
3488
            (void)direction;
3489
            for (x = start; x != end; x += step) {
×
3490
                int pos;
3491
                int d;
3492

3493
                pos = y * width + x;
×
3494
                for (d = 0; d < depth; ++d) {
×
3495
                    int val;
3496

3497
                    val = data[pos * depth + d]
×
3498
                        + f_mask(x, y, d) * 32;
×
3499
                    copy[d] = val < 0 ? 0
×
3500
                               : val > 255 ? 255 : val;
×
3501
                }
3502
                result[pos] = f_lookup(copy, depth, palette,
×
3503
                                       reqcolor, indextable,
3504
                                       complexion);
3505
            }
3506
        }
3507
        *ncolors = reqcolor;
×
3508
    }
3509

3510
    return SIXEL_OK;
×
3511
}
3512

3513

3514
static SIXELSTATUS
3515
apply_palette_variable(
×
3516
    sixel_index_t *result,
3517
    unsigned char *data,
3518
    int width,
3519
    int height,
3520
    int depth,
3521
    unsigned char *palette,
3522
    int reqcolor,
3523
    int methodForScan,
3524
    int foptimize_palette,
3525
    int (*f_lookup)(const unsigned char *pixel,
3526
                    int depth,
3527
                    const unsigned char *palette,
3528
                    int reqcolor,
3529
                    unsigned short *cachetable,
3530
                    int complexion),
3531
    unsigned short *indextable,
3532
    int complexion,
3533
    unsigned char new_palette[],
3534
    unsigned short migration_map[],
3535
    int *ncolors,
3536
    int methodForDiffuse,
3537
    int methodForCarry)
3538
{
3539
    SIXELSTATUS status = SIXEL_FALSE;
×
3540
#if _MSC_VER
3541
    enum { max_channels = 4 };
3542
#else
3543
    const int max_channels = 4;
×
3544
#endif
3545
    int serpentine;
3546
    int y;
3547
    diffuse_varerr_mode varerr_diffuse;
3548
    diffuse_varerr_carry_mode varerr_diffuse_carry;
3549
    int use_carry;
3550
    size_t carry_len;
3551
    int32_t *carry_curr = NULL;
×
3552
    int32_t *carry_next = NULL;
×
3553
    int32_t *carry_far = NULL;
×
3554
    unsigned char corrected[max_channels];
3555
    int32_t sample_scaled[max_channels];
3556
    int32_t accum_scaled[max_channels];
3557
    int start;
3558
    int end;
3559
    int step;
3560
    int direction;
3561
    int x;
3562
    int pos;
3563
    size_t base;
3564
    size_t carry_base;
3565
    const unsigned char *source_pixel;
3566
    int color_index;
3567
    int output_index;
3568
    int n;
3569
    int palette_value;
3570
    int diff;
3571
    int table_index;
3572
    int64_t accum;
3573
    int64_t clamped;
3574
    int32_t target_scaled;
3575
    int32_t error_scaled;
3576
    int32_t *tmp;
3577

3578
    if (depth > max_channels) {
×
3579
        status = SIXEL_BAD_ARGUMENT;
×
3580
        goto end;
×
3581
    }
3582

3583
    use_carry = (methodForCarry == SIXEL_CARRY_ENABLE);
×
3584
    carry_len = 0;
×
3585

3586
    switch (methodForDiffuse) {
×
3587
    case SIXEL_DIFFUSE_LSO2:
3588
        varerr_diffuse = diffuse_lso2;
×
3589
        varerr_diffuse_carry = diffuse_lso2_carry;
×
3590
        break;
×
3591
    default:
3592
        varerr_diffuse = diffuse_lso2;
×
3593
        varerr_diffuse_carry = diffuse_lso2_carry;
×
3594
        break;
×
3595
    }
3596

3597
    if (use_carry) {
×
3598
        carry_len = (size_t)width * (size_t)depth;
×
3599
        carry_curr = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
3600
        if (carry_curr == NULL) {
×
3601
            status = SIXEL_BAD_ALLOCATION;
×
3602
            goto end;
×
3603
        }
3604
        carry_next = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
3605
        if (carry_next == NULL) {
×
3606
            status = SIXEL_BAD_ALLOCATION;
×
3607
            goto end;
×
3608
        }
3609
        carry_far = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
3610
        if (carry_far == NULL) {
×
3611
            status = SIXEL_BAD_ALLOCATION;
×
3612
            goto end;
×
3613
        }
3614
    }
3615

3616
    serpentine = (methodForScan == SIXEL_SCAN_SERPENTINE);
×
3617

3618
    if (foptimize_palette) {
×
3619
        *ncolors = 0;
×
3620
        memset(new_palette, 0x00,
×
3621
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
3622
        memset(migration_map, 0x00,
×
3623
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
3624
    }
3625

3626
    for (y = 0; y < height; ++y) {
×
3627
        scanline_params(serpentine, y, width,
×
3628
                        &start, &end, &step, &direction);
3629
        for (x = start; x != end; x += step) {
×
3630
            pos = y * width + x;
×
3631
            base = (size_t)pos * (size_t)depth;
×
3632
            carry_base = (size_t)x * (size_t)depth;
×
3633
            if (use_carry) {
×
3634
                for (n = 0; n < depth; ++n) {
×
3635
                    accum = ((int64_t)data[base + n]
×
3636
                             << VARERR_SCALE_SHIFT)
×
3637
                          + carry_curr[carry_base + (size_t)n];
×
3638
                    if (accum < INT32_MIN) {
×
3639
                        accum = INT32_MIN;
×
3640
                    } else if (accum > INT32_MAX) {
×
3641
                        accum = INT32_MAX;
×
3642
                    }
3643
                    carry_curr[carry_base + (size_t)n] = 0;
×
3644
                    clamped = accum;
×
3645
                    if (clamped < 0) {
×
3646
                        clamped = 0;
×
3647
                    } else if (clamped > VARERR_MAX_VALUE) {
×
3648
                        clamped = VARERR_MAX_VALUE;
×
3649
                    }
3650
                    accum_scaled[n] = (int32_t)clamped;
×
3651
                    corrected[n]
3652
                        = (unsigned char)((clamped + VARERR_ROUND)
×
3653
                                          >> VARERR_SCALE_SHIFT);
×
3654
                }
3655
                source_pixel = corrected;
×
3656
            } else {
3657
                for (n = 0; n < depth; ++n) {
×
3658
                    sample_scaled[n]
3659
                        = (int32_t)data[base + n]
×
3660
                        << VARERR_SCALE_SHIFT;
×
3661
                    corrected[n] = data[base + n];
×
3662
                }
3663
                source_pixel = data + base;
×
3664
            }
3665

3666
            color_index = f_lookup(source_pixel, depth, palette,
×
3667
                                   reqcolor, indextable,
3668
                                   complexion);
3669

3670
            if (foptimize_palette) {
×
3671
                if (migration_map[color_index] == 0) {
×
3672
                    output_index = *ncolors;
×
3673
                    for (n = 0; n < depth; ++n) {
×
3674
                        new_palette[output_index * depth + n]
×
3675
                            = palette[color_index * depth + n];
×
3676
                    }
3677
                    ++*ncolors;
×
3678
                    migration_map[color_index] = *ncolors;
×
3679
                } else {
3680
                    output_index = migration_map[color_index] - 1;
×
3681
                }
3682
                result[pos] = output_index;
×
3683
            } else {
3684
                output_index = color_index;
×
3685
                result[pos] = output_index;
×
3686
            }
3687

3688
            for (n = 0; n < depth; ++n) {
×
3689
                if (foptimize_palette) {
×
3690
                    palette_value = new_palette[output_index * depth + n];
×
3691
                } else {
3692
                    palette_value = palette[color_index * depth + n];
×
3693
                }
3694
                diff = (int)source_pixel[n] - palette_value;
×
3695
                if (diff < 0) {
×
3696
                    diff = -diff;
×
3697
                }
3698
                if (diff > 255) {
×
3699
                    diff = 255;
×
3700
                }
3701
                table_index = diff;
×
3702
                if (use_carry) {
×
3703
                    target_scaled = (int32_t)palette_value
×
3704
                                  << VARERR_SCALE_SHIFT;
3705
                    error_scaled = accum_scaled[n] - target_scaled;
×
3706
                    varerr_diffuse_carry(carry_curr, carry_next, carry_far,
×
3707
                                         width, height, depth,
3708
                                         x, y, error_scaled,
3709
                                         table_index,
3710
                                         direction, n);
3711
                } else {
3712
                    target_scaled = (int32_t)palette_value
×
3713
                                  << VARERR_SCALE_SHIFT;
3714
                    error_scaled = sample_scaled[n] - target_scaled;
×
3715
                    varerr_diffuse(data + n, width, height,
×
3716
                                   x, y, depth, error_scaled,
3717
                                   table_index,
3718
                                   direction);
3719
                }
3720
            }
3721
        }
3722
        if (use_carry) {
×
3723
            tmp = carry_curr;
×
3724
            carry_curr = carry_next;
×
3725
            carry_next = carry_far;
×
3726
            carry_far = tmp;
×
3727
            if (carry_len > 0) {
×
3728
                memset(carry_far, 0x00, carry_len * sizeof(int32_t));
×
3729
            }
3730
        }
3731
    }
3732

3733
    if (foptimize_palette) {
×
3734
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
×
3735
    } else {
3736
        *ncolors = reqcolor;
×
3737
    }
3738

3739
    status = SIXEL_OK;
×
3740

3741
end:
3742
    free(carry_next);
×
3743
    free(carry_curr);
×
3744
    free(carry_far);
×
3745
    return status;
×
3746
}
3747

3748

3749
static SIXELSTATUS
3750
apply_palette_fixed(
285✔
3751
    sixel_index_t *result,
3752
    unsigned char *data,
3753
    int width,
3754
    int height,
3755
    int depth,
3756
    unsigned char *palette,
3757
    int reqcolor,
3758
    int methodForScan,
3759
    int foptimize_palette,
3760
    int (*f_lookup)(const unsigned char *pixel,
3761
                    int depth,
3762
                    const unsigned char *palette,
3763
                    int reqcolor,
3764
                    unsigned short *cachetable,
3765
                    int complexion),
3766
    unsigned short *indextable,
3767
    int complexion,
3768
    unsigned char new_palette[],
3769
    unsigned short migration_map[],
3770
    int *ncolors,
3771
    int methodForDiffuse,
3772
    int methodForCarry)
3773
{
170✔
3774
#if _MSC_VER
3775
    enum { max_channels = 4 };
3776
#else
3777
    const int max_channels = 4;
285✔
3778
#endif
3779
    SIXELSTATUS status = SIXEL_FALSE;
285✔
3780
    int serpentine;
3781
    int y;
3782
    void (*f_diffuse)(unsigned char *data,
3783
                      int width,
3784
                      int height,
3785
                      int x,
3786
                      int y,
3787
                      int depth,
3788
                      int offset,
3789
                      int direction);
3790
    diffuse_fixed_carry_mode f_diffuse_carry;
3791
    int use_carry;
3792
    size_t carry_len;
3793
    int32_t *carry_curr = NULL;
285✔
3794
    int32_t *carry_next = NULL;
285✔
3795
    int32_t *carry_far = NULL;
285✔
3796
    unsigned char corrected[max_channels];
170✔
3797
    int32_t accum_scaled[max_channels];
170✔
3798
    int start;
3799
    int end;
3800
    int step;
3801
    int direction;
3802
    int x;
3803
    int pos;
3804
    size_t base;
3805
    size_t carry_base;
3806
    const unsigned char *source_pixel;
3807
    int color_index;
3808
    int output_index;
3809
    int n;
3810
    int palette_value;
3811
    int64_t accum;
3812
    int64_t clamped;
3813
    int32_t target_scaled;
3814
    int32_t error_scaled;
3815
    int offset;
3816
    int32_t *tmp;
3817

3818
    if (depth > max_channels) {
285!
3819
        status = SIXEL_BAD_ARGUMENT;
×
3820
        goto end;
×
3821
    }
3822

3823
    use_carry = (methodForCarry == SIXEL_CARRY_ENABLE);
285✔
3824
    carry_len = 0;
285✔
3825

3826
    if (depth != 3) {
285!
3827
        f_diffuse = diffuse_none;
×
3828
        f_diffuse_carry = diffuse_none_carry;
×
3829
        use_carry = 0;
×
3830
    } else {
3831
        switch (methodForDiffuse) {
285!
3832
        case SIXEL_DIFFUSE_NONE:
86✔
3833
            f_diffuse = diffuse_none;
158✔
3834
            f_diffuse_carry = diffuse_none_carry;
158✔
3835
            break;
158✔
3836
        case SIXEL_DIFFUSE_ATKINSON:
44✔
3837
            f_diffuse = diffuse_atkinson;
67✔
3838
            f_diffuse_carry = diffuse_atkinson_carry;
67✔
3839
            break;
67✔
3840
        case SIXEL_DIFFUSE_FS:
34✔
3841
            f_diffuse = diffuse_fs;
51✔
3842
            f_diffuse_carry = diffuse_fs_carry;
51✔
3843
            break;
51✔
3844
        case SIXEL_DIFFUSE_JAJUNI:
2✔
3845
            f_diffuse = diffuse_jajuni;
3✔
3846
            f_diffuse_carry = diffuse_jajuni_carry;
3✔
3847
            break;
3✔
3848
        case SIXEL_DIFFUSE_STUCKI:
2✔
3849
            f_diffuse = diffuse_stucki;
3✔
3850
            f_diffuse_carry = diffuse_stucki_carry;
3✔
3851
            break;
3✔
3852
        case SIXEL_DIFFUSE_BURKES:
2✔
3853
            f_diffuse = diffuse_burkes;
3✔
3854
            f_diffuse_carry = diffuse_burkes_carry;
3✔
3855
            break;
3✔
3856
        case SIXEL_DIFFUSE_SIERRA1:
3857
            f_diffuse = diffuse_sierra1;
×
3858
            f_diffuse_carry = diffuse_sierra1_carry;
×
3859
            break;
×
3860
        case SIXEL_DIFFUSE_SIERRA2:
3861
            f_diffuse = diffuse_sierra2;
×
3862
            f_diffuse_carry = diffuse_sierra2_carry;
×
3863
            break;
×
3864
        case SIXEL_DIFFUSE_SIERRA3:
3865
            f_diffuse = diffuse_sierra3;
×
3866
            f_diffuse_carry = diffuse_sierra3_carry;
×
3867
            break;
×
3868
        default:
3869
            quant_trace(stderr,
×
3870
                        "Internal error: invalid methodForDiffuse: %d\n",
3871
                        methodForDiffuse);
3872
            f_diffuse = diffuse_none;
×
3873
            f_diffuse_carry = diffuse_none_carry;
×
3874
            break;
×
3875
        }
3876
    }
3877

3878
    if (use_carry) {
285!
3879
        carry_len = (size_t)width * (size_t)depth;
×
3880
        if (carry_len > 0) {
×
3881
            carry_curr = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
3882
            if (carry_curr == NULL) {
×
3883
                status = SIXEL_BAD_ALLOCATION;
×
3884
                goto end;
×
3885
            }
3886
            carry_next = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
3887
            if (carry_next == NULL) {
×
3888
                status = SIXEL_BAD_ALLOCATION;
×
3889
                goto end;
×
3890
            }
3891
            carry_far = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
3892
            if (carry_far == NULL) {
×
3893
                status = SIXEL_BAD_ALLOCATION;
×
3894
                goto end;
×
3895
            }
3896
        } else {
3897
            use_carry = 0;
×
3898
        }
3899
    }
3900

3901
    serpentine = (methodForScan == SIXEL_SCAN_SERPENTINE);
285✔
3902

3903
    if (foptimize_palette) {
285✔
3904
        *ncolors = 0;
206✔
3905
        memset(new_palette, 0x00,
206✔
3906
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
130✔
3907
        memset(migration_map, 0x00,
206✔
3908
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
3909
    } else {
76✔
3910
        *ncolors = reqcolor;
79✔
3911
    }
3912

3913
    for (y = 0; y < height; ++y) {
59,935✔
3914
        scanline_params(serpentine, y, width,
59,650✔
3915
                        &start, &end, &step, &direction);
3916
        for (x = start; x != end; x += step) {
43,528,028✔
3917
            pos = y * width + x;
43,468,378✔
3918
            base = (size_t)pos * (size_t)depth;
43,468,378✔
3919
            carry_base = (size_t)x * (size_t)depth;
43,468,378✔
3920
            if (use_carry) {
43,468,378!
3921
                for (n = 0; n < depth; ++n) {
×
3922
                    accum = ((int64_t)data[base + n]
×
3923
                             << VARERR_SCALE_SHIFT)
×
3924
                           + carry_curr[carry_base + (size_t)n];
×
3925
                    if (accum < INT32_MIN) {
×
3926
                        accum = INT32_MIN;
×
3927
                    } else if (accum > INT32_MAX) {
×
3928
                        accum = INT32_MAX;
×
3929
                    }
3930
                    clamped = accum;
×
3931
                    if (clamped < 0) {
×
3932
                        clamped = 0;
×
3933
                    } else if (clamped > VARERR_MAX_VALUE) {
×
3934
                        clamped = VARERR_MAX_VALUE;
×
3935
                    }
3936
                    accum_scaled[n] = (int32_t)clamped;
×
3937
                    corrected[n]
3938
                        = (unsigned char)((clamped + VARERR_ROUND)
×
3939
                                          >> VARERR_SCALE_SHIFT);
×
3940
                    data[base + n] = corrected[n];
×
3941
                    carry_curr[carry_base + (size_t)n] = 0;
×
3942
                }
3943
                source_pixel = corrected;
×
3944
            } else {
3945
                source_pixel = data + base;
43,468,378✔
3946
            }
3947

3948
            color_index = f_lookup(source_pixel, depth, palette,
63,604,336✔
3949
                                   reqcolor, indextable,
20,135,958✔
3950
                                   complexion);
20,135,958✔
3951

3952
            if (foptimize_palette) {
43,468,378✔
3953
                if (migration_map[color_index] == 0) {
31,366,878✔
3954
                    output_index = *ncolors;
16,578✔
3955
                    for (n = 0; n < depth; ++n) {
66,312✔
3956
                        new_palette[output_index * depth + n]
49,734✔
3957
                            = palette[color_index * depth + n];
66,756✔
3958
                    }
17,022✔
3959
                    ++*ncolors;
16,578✔
3960
                    migration_map[color_index] = *ncolors;
16,578✔
3961
                } else {
5,674✔
3962
                    output_index = migration_map[color_index] - 1;
31,350,300✔
3963
                }
3964
                result[pos] = output_index;
31,366,878✔
3965
            } else {
14,296,138✔
3966
                output_index = color_index;
12,101,500✔
3967
                result[pos] = output_index;
12,101,500✔
3968
            }
3969

3970
            for (n = 0; n < depth; ++n) {
173,873,512✔
3971
                if (foptimize_palette) {
130,405,134✔
3972
                    palette_value = new_palette[output_index * depth + n];
94,100,634✔
3973
                } else {
42,888,414✔
3974
                    palette_value = palette[color_index * depth + n];
36,304,500✔
3975
                }
3976
                if (use_carry) {
130,405,134!
3977
                    target_scaled = (int32_t)palette_value
×
3978
                                  << VARERR_SCALE_SHIFT;
3979
                    error_scaled = accum_scaled[n] - target_scaled;
×
3980
                    f_diffuse_carry(carry_curr, carry_next, carry_far,
×
3981
                                    width, height, depth,
3982
                                    x, y, error_scaled, direction, n);
3983
                } else {
3984
                    offset = (int)source_pixel[n] - palette_value;
130,405,134✔
3985
                    f_diffuse(data + n, width, height, x, y,
190,813,008✔
3986
                              depth, offset, direction);
60,407,874✔
3987
                }
3988
            }
60,407,874✔
3989
        }
20,135,958✔
3990
        if (use_carry) {
59,650!
3991
            tmp = carry_curr;
×
3992
            carry_curr = carry_next;
×
3993
            carry_next = carry_far;
×
3994
            carry_far = tmp;
×
3995
            if (carry_len > 0) {
×
3996
                memset(carry_far, 0x00, carry_len * sizeof(int32_t));
×
3997
            }
3998
        }
3999
    }
26,750✔
4000

4001
    if (foptimize_palette) {
285✔
4002
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
206✔
4003
    }
76✔
4004

4005
    status = SIXEL_OK;
285✔
4006

4007
end:
170✔
4008
    free(carry_far);
285✔
4009
    free(carry_next);
285✔
4010
    free(carry_curr);
285✔
4011
    return status;
285✔
4012
}
4013

4014

4015
static void
4016
diffuse_none(unsigned char *data, int width, int height,
31,038,318✔
4017
             int x, int y, int depth, int error, int direction)
4018
{
4019
    /* unused */ (void) data;
27,259,002✔
4020
    /* unused */ (void) width;
27,259,002✔
4021
    /* unused */ (void) height;
27,259,002✔
4022
    /* unused */ (void) x;
27,259,002✔
4023
    /* unused */ (void) y;
27,259,002✔
4024
    /* unused */ (void) depth;
27,259,002✔
4025
    /* unused */ (void) error;
27,259,002✔
4026
    /* unused */ (void) direction;
27,259,002✔
4027
}
31,038,318✔
4028

4029

4030
static void
4031
diffuse_none_carry(int32_t *carry_curr, int32_t *carry_next,
×
4032
                   int32_t *carry_far, int width, int height,
4033
                   int depth, int x, int y, int32_t error,
4034
                   int direction, int channel)
4035
{
4036
    /* unused */ (void) carry_curr;
4037
    /* unused */ (void) carry_next;
4038
    /* unused */ (void) carry_far;
4039
    /* unused */ (void) width;
4040
    /* unused */ (void) height;
4041
    /* unused */ (void) depth;
4042
    /* unused */ (void) x;
4043
    /* unused */ (void) y;
4044
    /* unused */ (void) error;
4045
    /* unused */ (void) direction;
4046
    /* unused */ (void) channel;
4047
}
×
4048

4049

4050
static void
4051
diffuse_fs(unsigned char *data, int width, int height,
70,430,256✔
4052
           int x, int y, int depth, int error, int direction)
4053
{
4054
    /* Floyd Steinberg Method
4055
     *          curr    7/16
4056
     *  3/16    5/16    1/16
4057
     */
4058
    int pos;
4059
    int forward;
4060

4061
    pos = y * width + x;
70,430,256✔
4062
    forward = direction >= 0;
70,430,256✔
4063

4064
    if (forward) {
70,430,256✔
4065
        if (x < width - 1) {
69,215,256✔
4066
            error_diffuse_normal(data, pos + 1, depth, error, 7, 16);
69,144,759✔
4067
        }
23,048,253✔
4068
        if (y < height - 1) {
69,215,256✔
4069
            if (x > 0) {
69,121,332✔
4070
                error_diffuse_normal(data,
92,067,972✔
4071
                                     pos + width - 1,
69,050,979✔
4072
                                     depth, error, 3, 16);
23,016,993✔
4073
            }
23,016,993✔
4074
            error_diffuse_normal(data,
92,161,776✔
4075
                                 pos + width,
23,040,444✔
4076
                                 depth, error, 5, 16);
23,040,444✔
4077
            if (x < width - 1) {
69,121,332✔
4078
                error_diffuse_normal(data,
92,067,972✔
4079
                                     pos + width + 1,
69,050,979✔
4080
                                     depth, error, 1, 16);
23,016,993✔
4081
            }
23,016,993✔
4082
        }
23,040,444✔
4083
    } else {
23,071,752✔
4084
        if (x > 0) {
1,215,000✔
4085
            error_diffuse_normal(data, pos - 1, depth, error, 7, 16);
1,212,975✔
4086
        }
404,325✔
4087
        if (y < height - 1) {
1,215,000✔
4088
            if (x < width - 1) {
1,209,600✔
4089
                error_diffuse_normal(data,
1,610,112✔
4090
                                     pos + width + 1,
1,207,584✔
4091
                                     depth, error, 3, 16);
402,528✔
4092
            }
402,528✔
4093
            error_diffuse_normal(data,
1,612,800✔
4094
                                 pos + width,
403,200✔
4095
                                 depth, error, 5, 16);
403,200✔
4096
            if (x > 0) {
1,209,600✔
4097
                error_diffuse_normal(data,
1,610,112✔
4098
                                     pos + width - 1,
1,207,584✔
4099
                                     depth, error, 1, 16);
402,528✔
4100
            }
402,528✔
4101
        }
403,200✔
4102
    }
4103
}
70,430,256✔
4104

4105

4106
static void
4107
diffuse_fs_carry(int32_t *carry_curr, int32_t *carry_next,
×
4108
                 int32_t *carry_far, int width, int height,
4109
                 int depth, int x, int y, int32_t error,
4110
                 int direction, int channel)
4111
{
4112
    /* Floyd Steinberg Method
4113
     *          curr    7/16
4114
     *  3/16    5/48    1/16
4115
     */
4116
    int forward;
4117

4118
    /* unused */ (void) carry_far;
4119
    if (error == 0) {
×
4120
        return;
×
4121
    }
4122

4123
    forward = direction >= 0;
×
4124
    if (forward) {
×
4125
        if (x + 1 < width) {
×
4126
            size_t base;
4127
            int32_t term;
4128

4129
            base = ((size_t)(x + 1) * (size_t)depth)
×
4130
                 + (size_t)channel;
×
4131
            term = diffuse_fixed_term(error, 7, 16);
×
4132
            carry_curr[base] += term;
×
4133
        }
4134
        if (y + 1 < height) {
×
4135
            if (x > 0) {
×
4136
                size_t base;
4137
                int32_t term;
4138

4139
                base = ((size_t)(x - 1) * (size_t)depth)
×
4140
                     + (size_t)channel;
×
4141
                term = diffuse_fixed_term(error, 3, 16);
×
4142
                carry_next[base] += term;
×
4143
            }
4144
            {
4145
                size_t base;
4146
                int32_t term;
4147

4148
                base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
4149
                term = diffuse_fixed_term(error, 5, 16);
×
4150
                carry_next[base] += term;
×
4151
            }
4152
            if (x + 1 < width) {
×
4153
                size_t base;
4154
                int32_t term;
4155

4156
                base = ((size_t)(x + 1) * (size_t)depth)
×
4157
                     + (size_t)channel;
×
4158
                term = diffuse_fixed_term(error, 1, 16);
×
4159
                carry_next[base] += term;
×
4160
            }
4161
        }
4162
    } else {
4163
        if (x - 1 >= 0) {
×
4164
            size_t base;
4165
            int32_t term;
4166

4167
            base = ((size_t)(x - 1) * (size_t)depth)
×
4168
                 + (size_t)channel;
×
4169
            term = diffuse_fixed_term(error, 7, 16);
×
4170
            carry_curr[base] += term;
×
4171
        }
4172
        if (y + 1 < height) {
×
4173
            if (x + 1 < width) {
×
4174
                size_t base;
4175
                int32_t term;
4176

4177
                base = ((size_t)(x + 1) * (size_t)depth)
×
4178
                     + (size_t)channel;
×
4179
                term = diffuse_fixed_term(error, 3, 16);
×
4180
                carry_next[base] += term;
×
4181
            }
4182
            {
4183
                size_t base;
4184
                int32_t term;
4185

4186
                base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
4187
                term = diffuse_fixed_term(error, 5, 16);
×
4188
                carry_next[base] += term;
×
4189
            }
4190
            if (x - 1 >= 0) {
×
4191
                size_t base;
4192
                int32_t term;
4193

4194
                base = ((size_t)(x - 1) * (size_t)depth)
×
4195
                     + (size_t)channel;
×
4196
                term = diffuse_fixed_term(error, 1, 16);
×
4197
                carry_next[base] += term;
×
4198
            }
4199
        }
4200
    }
4201
}
4202

4203

4204
static void
4205
diffuse_atkinson(unsigned char *data, int width, int height,
28,352,460✔
4206
                 int x, int y, int depth, int error, int direction)
4207
{
4208
    /* Atkinson's Method
4209
     *          curr    1/8    1/8
4210
     *   1/8     1/8    1/8
4211
     *           1/8
4212
     */
4213
    int pos;
4214
    int sign;
4215

4216
    pos = y * width + x;
28,352,460✔
4217
    sign = direction >= 0 ? 1 : -1;
28,352,460!
4218

4219
    if (x + sign >= 0 && x + sign < width) {
28,352,460!
4220
        error_diffuse_fast(data, pos + sign, depth, error, 1, 8);
28,296,945✔
4221
    }
9,458,715✔
4222
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
28,352,460!
4223
        error_diffuse_fast(data, pos + sign * 2, depth, error, 1, 8);
28,241,430✔
4224
    }
9,440,010✔
4225
    if (y < height - 1) {
28,352,460✔
4226
        int row;
4227

4228
        row = pos + width;
28,278,756✔
4229
        if (x - sign >= 0 && x - sign < width) {
28,278,756!
4230
            error_diffuse_fast(data,
37,657,392✔
4231
                               row + (-sign),
9,433,950✔
4232
                               depth, error, 1, 8);
9,433,950✔
4233
        }
9,433,950✔
4234
        error_diffuse_fast(data, row, depth, error, 1, 8);
28,278,756✔
4235
        if (x + sign >= 0 && x + sign < width) {
28,278,756!
4236
            error_diffuse_fast(data,
37,657,392✔
4237
                               row + sign,
9,433,950✔
4238
                               depth, error, 1, 8);
9,433,950✔
4239
        }
9,433,950✔
4240
    }
9,452,586✔
4241
    if (y < height - 2) {
28,352,460✔
4242
        error_diffuse_fast(data, pos + width * 2, depth, error, 1, 8);
28,205,052✔
4243
    }
9,427,752✔
4244
}
28,352,460✔
4245

4246

4247
static void
4248
diffuse_atkinson_carry(int32_t *carry_curr, int32_t *carry_next,
×
4249
                       int32_t *carry_far, int width, int height,
4250
                       int depth, int x, int y, int32_t error,
4251
                       int direction, int channel)
4252
{
4253
    /* Atkinson's Method
4254
     *          curr    1/8    1/8
4255
     *   1/8     1/8    1/8
4256
     *           1/8
4257
     */
4258
    int sign;
4259
    int32_t term;
4260

4261
    if (error == 0) {
×
4262
        return;
×
4263
    }
4264

4265
    term = diffuse_fixed_term(error, 1, 8);
×
4266
    sign = direction >= 0 ? 1 : -1;
×
4267
    if (x + sign >= 0 && x + sign < width) {
×
4268
        size_t base;
4269

4270
        base = ((size_t)(x + sign) * (size_t)depth)
×
4271
             + (size_t)channel;
×
4272
        carry_curr[base] += term;
×
4273
    }
4274
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
×
4275
        size_t base;
4276

4277
        base = ((size_t)(x + sign * 2) * (size_t)depth)
×
4278
             + (size_t)channel;
×
4279
        carry_curr[base] += term;
×
4280
    }
4281
    if (y + 1 < height) {
×
4282
        if (x - sign >= 0 && x - sign < width) {
×
4283
            size_t base;
4284

4285
            base = ((size_t)(x - sign) * (size_t)depth)
×
4286
                 + (size_t)channel;
×
4287
            carry_next[base] += term;
×
4288
        }
4289
        {
4290
            size_t base;
4291

4292
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
4293
            carry_next[base] += term;
×
4294
        }
4295
        if (x + sign >= 0 && x + sign < width) {
×
4296
            size_t base;
4297

4298
            base = ((size_t)(x + sign) * (size_t)depth)
×
4299
                 + (size_t)channel;
×
4300
            carry_next[base] += term;
×
4301
        }
4302
    }
4303
    if (y + 2 < height) {
×
4304
        size_t base;
4305

4306
        base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
4307
        carry_far[base] += term;
×
4308
    }
4309
}
4310

4311

4312
static void
4313
diffuse_jajuni(unsigned char *data, int width, int height,
396,900✔
4314
               int x, int y, int depth, int error, int direction)
4315
{
4316
    /* Jarvis, Judice & Ninke Method
4317
     *                  curr    7/48    5/48
4318
     *  3/48    5/48    7/48    5/48    3/48
4319
     *  1/48    3/48    5/48    3/48    1/48
4320
     */
4321
    int pos;
4322
    int sign;
4323
    static const int row0_offsets[] = { 1, 2 };
4324
    static const int row0_weights[] = { 7, 5 };
4325
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4326
    static const int row1_weights[] = { 3, 5, 7, 5, 3 };
4327
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
4328
    static const int row2_weights[] = { 1, 3, 5, 3, 1 };
4329
    int i;
4330

4331
    pos = y * width + x;
396,900✔
4332
    sign = direction >= 0 ? 1 : -1;
396,900!
4333

4334
    for (i = 0; i < 2; ++i) {
1,190,700✔
4335
        int neighbor;
4336

4337
        neighbor = x + sign * row0_offsets[i];
793,800✔
4338
        if (neighbor < 0 || neighbor >= width) {
793,800!
4339
            continue;
5,670✔
4340
        }
4341
        error_diffuse_precise(data,
1,050,840✔
4342
                              pos + (neighbor - x),
788,130✔
4343
                              depth, error,
262,710✔
4344
                              row0_weights[i], 48);
788,130✔
4345
    }
262,710✔
4346
    if (y < height - 1) {
396,900✔
4347
        int row;
4348

4349
        row = pos + width;
395,010✔
4350
        for (i = 0; i < 5; ++i) {
2,370,060✔
4351
            int neighbor;
4352

4353
            neighbor = x + sign * row1_offsets[i];
1,975,050✔
4354
            if (neighbor < 0 || neighbor >= width) {
1,975,050✔
4355
                continue;
11,286✔
4356
            }
4357
            error_diffuse_precise(data,
2,618,352✔
4358
                                  row + (neighbor - x),
1,963,764✔
4359
                                  depth, error,
654,588✔
4360
                                  row1_weights[i], 48);
1,963,764✔
4361
        }
654,588✔
4362
    }
131,670✔
4363
    if (y < height - 2) {
396,900✔
4364
        int row;
4365

4366
        row = pos + width * 2;
393,120✔
4367
        for (i = 0; i < 5; ++i) {
2,358,720✔
4368
            int neighbor;
4369

4370
            neighbor = x + sign * row2_offsets[i];
1,965,600✔
4371
            if (neighbor < 0 || neighbor >= width) {
1,965,600✔
4372
                continue;
11,232✔
4373
            }
4374
            error_diffuse_precise(data,
2,605,824✔
4375
                                  row + (neighbor - x),
1,954,368✔
4376
                                  depth, error,
651,456✔
4377
                                  row2_weights[i], 48);
1,954,368✔
4378
        }
651,456✔
4379
    }
131,040✔
4380
}
396,900✔
4381

4382

4383
static void
4384
diffuse_jajuni_carry(int32_t *carry_curr, int32_t *carry_next,
×
4385
                     int32_t *carry_far, int width, int height,
4386
                     int depth, int x, int y, int32_t error,
4387
                     int direction, int channel)
4388
{
4389
    /* Jarvis, Judice & Ninke Method
4390
     *                  curr    7/48    5/48
4391
     *  3/48    5/48    7/48    5/48    3/48
4392
     *  1/48    3/48    5/48    3/48    1/48
4393
     */
4394
    static const int row0_offsets[] = { 1, 2 };
4395
    static const int row0_weights[] = { 7, 5 };
4396
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4397
    static const int row1_weights[] = { 3, 5, 7, 5, 3 };
4398
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
4399
    static const int row2_weights[] = { 1, 3, 5, 3, 1 };
4400
    int sign;
4401
    int i;
4402

4403
    if (error == 0) {
×
4404
        return;
×
4405
    }
4406

4407
    sign = direction >= 0 ? 1 : -1;
×
4408
    for (i = 0; i < 2; ++i) {
×
4409
        int neighbor;
4410
        int32_t term;
4411

4412
        neighbor = x + sign * row0_offsets[i];
×
4413
        if (neighbor < 0 || neighbor >= width) {
×
4414
            continue;
×
4415
        }
4416
        term = diffuse_fixed_term(error, row0_weights[i], 48);
×
4417
        carry_curr[((size_t)neighbor * (size_t)depth)
×
4418
                   + (size_t)channel] += term;
×
4419
    }
4420
    if (y + 1 < height) {
×
4421
        for (i = 0; i < 5; ++i) {
×
4422
            int neighbor;
4423
            int32_t term;
4424

4425
            neighbor = x + sign * row1_offsets[i];
×
4426
            if (neighbor < 0 || neighbor >= width) {
×
4427
                continue;
×
4428
            }
4429
            term = diffuse_fixed_term(error, row1_weights[i], 48);
×
4430
            carry_next[((size_t)neighbor * (size_t)depth)
×
4431
                       + (size_t)channel] += term;
×
4432
        }
4433
    }
4434
    if (y + 2 < height) {
×
4435
        for (i = 0; i < 5; ++i) {
×
4436
            int neighbor;
4437
            int32_t term;
4438

4439
            neighbor = x + sign * row2_offsets[i];
×
4440
            if (neighbor < 0 || neighbor >= width) {
×
4441
                continue;
×
4442
            }
4443
            term = diffuse_fixed_term(error, row2_weights[i], 48);
×
4444
            carry_far[((size_t)neighbor * (size_t)depth)
×
4445
                      + (size_t)channel] += term;
×
4446
        }
4447
    }
4448
}
4449

4450

4451
static void
4452
diffuse_stucki(unsigned char *data, int width, int height,
119,700✔
4453
               int x, int y, int depth, int error, int direction)
4454
{
4455
    /* Stucki's Method
4456
     *                  curr    8/48    4/48
4457
     *  2/48    4/48    8/48    4/48    2/48
4458
     *  1/48    2/48    4/48    2/48    1/48
4459
     */
4460
    int pos;
4461
    int sign;
4462
    static const int row0_offsets[] = { 1, 2 };
4463
    static const int row0_num[] = { 1, 1 };
4464
    static const int row0_den[] = { 6, 12 };
4465
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4466
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
4467
    static const int row1_den[] = { 24, 12, 6, 12, 24 };
4468
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
4469
    static const int row2_num[] = { 1, 1, 1, 1, 1 };
4470
    static const int row2_den[] = { 48, 24, 12, 24, 48 };
4471
    int i;
4472

4473
    pos = y * width + x;
119,700✔
4474
    sign = direction >= 0 ? 1 : -1;
119,700!
4475

4476
    for (i = 0; i < 2; ++i) {
359,100✔
4477
        int neighbor;
4478

4479
        neighbor = x + sign * row0_offsets[i];
239,400✔
4480
        if (neighbor < 0 || neighbor >= width) {
239,400!
4481
            continue;
2,700✔
4482
        }
4483
        error_diffuse_precise(data,
315,600✔
4484
                              pos + (neighbor - x),
236,700✔
4485
                              depth, error,
78,900✔
4486
                              row0_num[i], row0_den[i]);
236,700✔
4487
    }
78,900✔
4488
    if (y < height - 1) {
119,700✔
4489
        int row;
4490

4491
        row = pos + width;
118,503✔
4492
        for (i = 0; i < 5; ++i) {
711,018✔
4493
            int neighbor;
4494

4495
            neighbor = x + sign * row1_offsets[i];
592,515✔
4496
            if (neighbor < 0 || neighbor >= width) {
592,515✔
4497
                continue;
5,346✔
4498
            }
4499
            error_diffuse_precise(data,
782,892✔
4500
                                  row + (neighbor - x),
587,169✔
4501
                                  depth, error,
195,723✔
4502
                                  row1_num[i], row1_den[i]);
587,169✔
4503
        }
195,723✔
4504
    }
39,501✔
4505
    if (y < height - 2) {
119,700✔
4506
        int row;
4507

4508
        row = pos + width * 2;
117,306✔
4509
        for (i = 0; i < 5; ++i) {
703,836✔
4510
            int neighbor;
4511

4512
            neighbor = x + sign * row2_offsets[i];
586,530✔
4513
            if (neighbor < 0 || neighbor >= width) {
586,530✔
4514
                continue;
5,292✔
4515
            }
4516
            error_diffuse_precise(data,
774,984✔
4517
                                  row + (neighbor - x),
581,238✔
4518
                                  depth, error,
193,746✔
4519
                                  row2_num[i], row2_den[i]);
581,238✔
4520
        }
193,746✔
4521
    }
39,102✔
4522
}
119,700✔
4523

4524

4525
static void
4526
diffuse_stucki_carry(int32_t *carry_curr, int32_t *carry_next,
×
4527
                     int32_t *carry_far, int width, int height,
4528
                     int depth, int x, int y, int32_t error,
4529
                     int direction, int channel)
4530
{
4531
    /* Stucki's Method
4532
     *                  curr    8/48    4/48
4533
     *  2/48    4/48    8/48    4/48    2/48
4534
     *  1/48    2/48    4/48    2/48    1/48
4535
     */
4536
    static const int row0_offsets[] = { 1, 2 };
4537
    static const int row0_num[] = { 1, 1 };
4538
    static const int row0_den[] = { 6, 12 };
4539
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4540
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
4541
    static const int row1_den[] = { 24, 12, 6, 12, 24 };
4542
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
4543
    static const int row2_num[] = { 1, 1, 1, 1, 1 };
4544
    static const int row2_den[] = { 48, 24, 12, 24, 48 };
4545
    int sign;
4546
    int i;
4547

4548
    if (error == 0) {
×
4549
        return;
×
4550
    }
4551

4552
    sign = direction >= 0 ? 1 : -1;
×
4553
    for (i = 0; i < 2; ++i) {
×
4554
        int neighbor;
4555
        int32_t term;
4556

4557
        neighbor = x + sign * row0_offsets[i];
×
4558
        if (neighbor < 0 || neighbor >= width) {
×
4559
            continue;
×
4560
        }
4561
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
4562
        carry_curr[((size_t)neighbor * (size_t)depth)
×
4563
                   + (size_t)channel] += term;
×
4564
    }
4565
    if (y + 1 < height) {
×
4566
        for (i = 0; i < 5; ++i) {
×
4567
            int neighbor;
4568
            int32_t term;
4569

4570
            neighbor = x + sign * row1_offsets[i];
×
4571
            if (neighbor < 0 || neighbor >= width) {
×
4572
                continue;
×
4573
            }
4574
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
4575
            carry_next[((size_t)neighbor * (size_t)depth)
×
4576
                       + (size_t)channel] += term;
×
4577
        }
4578
    }
4579
    if (y + 2 < height) {
×
4580
        for (i = 0; i < 5; ++i) {
×
4581
            int neighbor;
4582
            int32_t term;
4583

4584
            neighbor = x + sign * row2_offsets[i];
×
4585
            if (neighbor < 0 || neighbor >= width) {
×
4586
                continue;
×
4587
            }
4588
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
4589
            carry_far[((size_t)neighbor * (size_t)depth)
×
4590
                      + (size_t)channel] += term;
×
4591
        }
4592
    }
4593
}
4594

4595

4596
static void
4597
diffuse_burkes(unsigned char *data, int width, int height,
67,500✔
4598
               int x, int y, int depth, int error, int direction)
4599
{
4600
    /* Burkes' Method
4601
     *                  curr    4/16    2/16
4602
     *  1/16    2/16    4/16    2/16    1/16
4603
     */
4604
    int pos;
4605
    int sign;
4606
    static const int row0_offsets[] = { 1, 2 };
4607
    static const int row0_num[] = { 1, 1 };
4608
    static const int row0_den[] = { 4, 8 };
4609
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4610
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
4611
    static const int row1_den[] = { 16, 8, 4, 8, 16 };
4612
    int i;
4613

4614
    pos = y * width + x;
67,500✔
4615
    sign = direction >= 0 ? 1 : -1;
67,500!
4616

4617
    for (i = 0; i < 2; ++i) {
202,500✔
4618
        int neighbor;
4619

4620
        neighbor = x + sign * row0_offsets[i];
135,000✔
4621
        if (neighbor < 0 || neighbor >= width) {
135,000!
4622
            continue;
2,025✔
4623
        }
4624
        error_diffuse_normal(data,
177,300✔
4625
                             pos + (neighbor - x),
132,975✔
4626
                             depth, error,
44,325✔
4627
                             row0_num[i], row0_den[i]);
132,975✔
4628
    }
44,325✔
4629
    if (y < height - 1) {
67,500✔
4630
        int row;
4631

4632
        row = pos + width;
66,600✔
4633
        for (i = 0; i < 5; ++i) {
399,600✔
4634
            int neighbor;
4635

4636
            neighbor = x + sign * row1_offsets[i];
333,000✔
4637
            if (neighbor < 0 || neighbor >= width) {
333,000✔
4638
                continue;
3,996✔
4639
            }
4640
            error_diffuse_normal(data,
438,672✔
4641
                                 row + (neighbor - x),
329,004✔
4642
                                 depth, error,
109,668✔
4643
                                 row1_num[i], row1_den[i]);
329,004✔
4644
        }
109,668✔
4645
    }
22,200✔
4646
}
67,500✔
4647

4648
static void
4649
diffuse_burkes_carry(int32_t *carry_curr, int32_t *carry_next,
×
4650
                     int32_t *carry_far, int width, int height,
4651
                     int depth, int x, int y, int32_t error,
4652
                     int direction, int channel)
4653
{
4654
    /* Burkes' Method
4655
     *                  curr    4/16    2/16
4656
     *  1/16    2/16    4/16    2/16    1/16
4657
     */
4658
    static const int row0_offsets[] = { 1, 2 };
4659
    static const int row0_num[] = { 1, 1 };
4660
    static const int row0_den[] = { 4, 8 };
4661
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4662
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
4663
    static const int row1_den[] = { 16, 8, 4, 8, 16 };
4664
    int sign;
4665
    int i;
4666

4667
    /* unused */ (void) carry_far;
4668

4669
    if (error == 0) {
×
4670
        return;
×
4671
    }
4672

4673
    sign = direction >= 0 ? 1 : -1;
×
4674
    for (i = 0; i < 2; ++i) {
×
4675
        int neighbor;
4676
        int32_t term;
4677

4678
        neighbor = x + sign * row0_offsets[i];
×
4679
        if (neighbor < 0 || neighbor >= width) {
×
4680
            continue;
×
4681
        }
4682
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
4683
        carry_curr[((size_t)neighbor * (size_t)depth)
×
4684
                   + (size_t)channel] += term;
×
4685
    }
4686
    if (y + 1 < height) {
×
4687
        for (i = 0; i < 5; ++i) {
×
4688
            int neighbor;
4689
            int32_t term;
4690

4691
            neighbor = x + sign * row1_offsets[i];
×
4692
            if (neighbor < 0 || neighbor >= width) {
×
4693
                continue;
×
4694
            }
4695
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
4696
            carry_next[((size_t)neighbor * (size_t)depth)
×
4697
                       + (size_t)channel] += term;
×
4698
        }
4699
    }
4700
}
4701

4702
static void
4703
diffuse_sierra1(unsigned char *data, int width, int height,
×
4704
                int x, int y, int depth, int error, int direction)
4705
{
4706
    /* Sierra Lite Method
4707
     *          curr    2/4
4708
     *  1/4     1/4
4709
     */
4710
    static const int row0_offsets[] = { 1 };
4711
    static const int row0_num[] = { 1 };
4712
    static const int row0_den[] = { 2 };
4713
    static const int row1_offsets[] = { -1, 0 };
4714
    static const int row1_num[] = { 1, 1 };
4715
    static const int row1_den[] = { 4, 4 };
4716
    int pos;
4717
    int sign;
4718
    int i;
4719
    int neighbor;
4720
    int row;
4721

4722
    pos = y * width + x;
×
4723
    sign = direction >= 0 ? 1 : -1;
×
4724

4725
    for (i = 0; i < 1; ++i) {
×
4726
        neighbor = x + sign * row0_offsets[i];
×
4727
        if (neighbor < 0 || neighbor >= width) {
×
4728
            continue;
×
4729
        }
4730
        error_diffuse_normal(data,
×
4731
                             pos + (neighbor - x),
×
4732
                             depth, error,
4733
                             row0_num[i], row0_den[i]);
×
4734
    }
4735
    if (y < height - 1) {
×
4736
        row = pos + width;
×
4737
        for (i = 0; i < 2; ++i) {
×
4738
            neighbor = x + sign * row1_offsets[i];
×
4739
            if (neighbor < 0 || neighbor >= width) {
×
4740
                continue;
×
4741
            }
4742
            error_diffuse_normal(data,
×
4743
                                 row + (neighbor - x),
×
4744
                                 depth, error,
4745
                                 row1_num[i], row1_den[i]);
×
4746
        }
4747
    }
4748
}
×
4749

4750

4751
static void
4752
diffuse_sierra1_carry(int32_t *carry_curr, int32_t *carry_next,
×
4753
                      int32_t *carry_far, int width, int height,
4754
                      int depth, int x, int y, int32_t error,
4755
                      int direction, int channel)
4756
{
4757
    /* Sierra Lite Method
4758
     *          curr    2/4
4759
     *  1/4     1/4
4760
     */
4761
    static const int row0_offsets[] = { 1 };
4762
    static const int row0_num[] = { 1 };
4763
    static const int row0_den[] = { 2 };
4764
    static const int row1_offsets[] = { -1, 0 };
4765
    static const int row1_num[] = { 1, 1 };
4766
    static const int row1_den[] = { 4, 4 };
4767
    int sign;
4768
    int i;
4769
    int neighbor;
4770
    int32_t term;
4771

4772
    /* unused */ (void) carry_far;
4773

4774
    if (error == 0) {
×
4775
        return;
×
4776
    }
4777

4778
    sign = direction >= 0 ? 1 : -1;
×
4779
    for (i = 0; i < 1; ++i) {
×
4780
        neighbor = x + sign * row0_offsets[i];
×
4781
        if (neighbor < 0 || neighbor >= width) {
×
4782
            continue;
×
4783
        }
4784
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
4785
        carry_curr[((size_t)neighbor * (size_t)depth)
×
4786
                   + (size_t)channel] += term;
×
4787
    }
4788
    if (y + 1 < height) {
×
4789
        for (i = 0; i < 2; ++i) {
×
4790
            neighbor = x + sign * row1_offsets[i];
×
4791
            if (neighbor < 0 || neighbor >= width) {
×
4792
                continue;
×
4793
            }
4794
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
4795
            carry_next[((size_t)neighbor * (size_t)depth)
×
4796
                       + (size_t)channel] += term;
×
4797
        }
4798
    }
4799
}
4800

4801

4802
static void
4803
diffuse_sierra2(unsigned char *data, int width, int height,
×
4804
                int x, int y, int depth, int error, int direction)
4805
{
4806
    /* Sierra Two-row Method
4807
     *                  curr    4/32    3/32
4808
     *  1/32    2/32    3/32    2/32    1/32
4809
     *                  2/32    3/32    2/32
4810
     */
4811
    static const int row0_offsets[] = { 1, 2 };
4812
    static const int row0_num[] = { 4, 3 };
4813
    static const int row0_den[] = { 32, 32 };
4814
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4815
    static const int row1_num[] = { 1, 2, 3, 2, 1 };
4816
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
4817
    static const int row2_offsets[] = { -1, 0, 1 };
4818
    static const int row2_num[] = { 2, 3, 2 };
4819
    static const int row2_den[] = { 32, 32, 32 };
4820
    int pos;
4821
    int sign;
4822
    int i;
4823
    int neighbor;
4824
    int row;
4825

4826
    pos = y * width + x;
×
4827
    sign = direction >= 0 ? 1 : -1;
×
4828

4829
    for (i = 0; i < 2; ++i) {
×
4830
        neighbor = x + sign * row0_offsets[i];
×
4831
        if (neighbor < 0 || neighbor >= width) {
×
4832
            continue;
×
4833
        }
4834
        error_diffuse_precise(data,
×
4835
                              pos + (neighbor - x),
×
4836
                              depth, error,
4837
                              row0_num[i], row0_den[i]);
×
4838
    }
4839
    if (y < height - 1) {
×
4840
        row = pos + width;
×
4841
        for (i = 0; i < 5; ++i) {
×
4842
            neighbor = x + sign * row1_offsets[i];
×
4843
            if (neighbor < 0 || neighbor >= width) {
×
4844
                continue;
×
4845
            }
4846
            error_diffuse_precise(data,
×
4847
                                  row + (neighbor - x),
×
4848
                                  depth, error,
4849
                                  row1_num[i], row1_den[i]);
×
4850
        }
4851
    }
4852
    if (y < height - 2) {
×
4853
        row = pos + width * 2;
×
4854
        for (i = 0; i < 3; ++i) {
×
4855
            neighbor = x + sign * row2_offsets[i];
×
4856
            if (neighbor < 0 || neighbor >= width) {
×
4857
                continue;
×
4858
            }
4859
            error_diffuse_precise(data,
×
4860
                                  row + (neighbor - x),
×
4861
                                  depth, error,
4862
                                  row2_num[i], row2_den[i]);
×
4863
        }
4864
    }
4865
}
×
4866

4867

4868
static void
4869
diffuse_sierra2_carry(int32_t *carry_curr, int32_t *carry_next,
×
4870
                      int32_t *carry_far, int width, int height,
4871
                      int depth, int x, int y, int32_t error,
4872
                      int direction, int channel)
4873
{
4874
    /* Sierra Two-row Method
4875
     *                  curr    4/32    3/32
4876
     *  1/32    2/32    3/32    2/32    1/32
4877
     *                  2/32    3/32    2/32
4878
     */
4879
    static const int row0_offsets[] = { 1, 2 };
4880
    static const int row0_num[] = { 4, 3 };
4881
    static const int row0_den[] = { 32, 32 };
4882
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4883
    static const int row1_num[] = { 1, 2, 3, 2, 1 };
4884
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
4885
    static const int row2_offsets[] = { -1, 0, 1 };
4886
    static const int row2_num[] = { 2, 3, 2 };
4887
    static const int row2_den[] = { 32, 32, 32 };
4888
    int sign;
4889
    int i;
4890
    int neighbor;
4891
    int32_t term;
4892

4893
    if (error == 0) {
×
4894
        return;
×
4895
    }
4896

4897
    sign = direction >= 0 ? 1 : -1;
×
4898
    for (i = 0; i < 2; ++i) {
×
4899
        neighbor = x + sign * row0_offsets[i];
×
4900
        if (neighbor < 0 || neighbor >= width) {
×
4901
            continue;
×
4902
        }
4903
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
4904
        carry_curr[((size_t)neighbor * (size_t)depth)
×
4905
                   + (size_t)channel] += term;
×
4906
    }
4907
    if (y + 1 < height) {
×
4908
        for (i = 0; i < 5; ++i) {
×
4909
            neighbor = x + sign * row1_offsets[i];
×
4910
            if (neighbor < 0 || neighbor >= width) {
×
4911
                continue;
×
4912
            }
4913
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
4914
            carry_next[((size_t)neighbor * (size_t)depth)
×
4915
                       + (size_t)channel] += term;
×
4916
        }
4917
    }
4918
    if (y + 2 < height) {
×
4919
        for (i = 0; i < 3; ++i) {
×
4920
            neighbor = x + sign * row2_offsets[i];
×
4921
            if (neighbor < 0 || neighbor >= width) {
×
4922
                continue;
×
4923
            }
4924
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
4925
            carry_far[((size_t)neighbor * (size_t)depth)
×
4926
                      + (size_t)channel] += term;
×
4927
        }
4928
    }
4929
}
4930

4931

4932
static void
4933
diffuse_sierra3(unsigned char *data, int width, int height,
×
4934
                int x, int y, int depth, int error, int direction)
4935
{
4936
    /* Sierra-3 Method
4937
     *                  curr    5/32    3/32
4938
     *  2/32    4/32    5/32    4/32    2/32
4939
     *                  2/32    3/32    2/32
4940
     */
4941
    static const int row0_offsets[] = { 1, 2 };
4942
    static const int row0_num[] = { 5, 3 };
4943
    static const int row0_den[] = { 32, 32 };
4944
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
4945
    static const int row1_num[] = { 2, 4, 5, 4, 2 };
4946
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
4947
    static const int row2_offsets[] = { -1, 0, 1 };
4948
    static const int row2_num[] = { 2, 3, 2 };
4949
    static const int row2_den[] = { 32, 32, 32 };
4950
    int pos;
4951
    int sign;
4952
    int i;
4953
    int neighbor;
4954
    int row;
4955

4956
    pos = y * width + x;
×
4957
    sign = direction >= 0 ? 1 : -1;
×
4958

4959
    for (i = 0; i < 2; ++i) {
×
4960
        neighbor = x + sign * row0_offsets[i];
×
4961
        if (neighbor < 0 || neighbor >= width) {
×
4962
            continue;
×
4963
        }
4964
        error_diffuse_precise(data,
×
4965
                              pos + (neighbor - x),
×
4966
                              depth, error,
4967
                              row0_num[i], row0_den[i]);
×
4968
    }
4969
    if (y < height - 1) {
×
4970
        row = pos + width;
×
4971
        for (i = 0; i < 5; ++i) {
×
4972
            neighbor = x + sign * row1_offsets[i];
×
4973
            if (neighbor < 0 || neighbor >= width) {
×
4974
                continue;
×
4975
            }
4976
            error_diffuse_precise(data,
×
4977
                                  row + (neighbor - x),
×
4978
                                  depth, error,
4979
                                  row1_num[i], row1_den[i]);
×
4980
        }
4981
    }
4982
    if (y < height - 2) {
×
4983
        row = pos + width * 2;
×
4984
        for (i = 0; i < 3; ++i) {
×
4985
            neighbor = x + sign * row2_offsets[i];
×
4986
            if (neighbor < 0 || neighbor >= width) {
×
4987
                continue;
×
4988
            }
4989
            error_diffuse_precise(data,
×
4990
                                  row + (neighbor - x),
×
4991
                                  depth, error,
4992
                                  row2_num[i], row2_den[i]);
×
4993
        }
4994
    }
4995
}
×
4996

4997

4998
static void
4999
diffuse_sierra3_carry(int32_t *carry_curr, int32_t *carry_next,
×
5000
                      int32_t *carry_far, int width, int height,
5001
                      int depth, int x, int y, int32_t error,
5002
                      int direction, int channel)
5003
{
5004
    /* Sierra-3 Method
5005
     *                  curr    5/32    3/32
5006
     *  2/32    4/32    5/32    4/32    2/32
5007
     *                  2/32    3/32    2/32
5008
     */
5009
    static const int row0_offsets[] = { 1, 2 };
5010
    static const int row0_num[] = { 5, 3 };
5011
    static const int row0_den[] = { 32, 32 };
5012
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
5013
    static const int row1_num[] = { 2, 4, 5, 4, 2 };
5014
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
5015
    static const int row2_offsets[] = { -1, 0, 1 };
5016
    static const int row2_num[] = { 2, 3, 2 };
5017
    static const int row2_den[] = { 32, 32, 32 };
5018
    int sign;
5019
    int i;
5020
    int neighbor;
5021
    int32_t term;
5022

5023
    if (error == 0) {
×
5024
        return;
×
5025
    }
5026

5027
    sign = direction >= 0 ? 1 : -1;
×
5028
    for (i = 0; i < 2; ++i) {
×
5029
        neighbor = x + sign * row0_offsets[i];
×
5030
        if (neighbor < 0 || neighbor >= width) {
×
5031
            continue;
×
5032
        }
5033
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
5034
        carry_curr[((size_t)neighbor * (size_t)depth)
×
5035
                   + (size_t)channel] += term;
×
5036
    }
5037
    if (y + 1 < height) {
×
5038
        for (i = 0; i < 5; ++i) {
×
5039
            neighbor = x + sign * row1_offsets[i];
×
5040
            if (neighbor < 0 || neighbor >= width) {
×
5041
                continue;
×
5042
            }
5043
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
5044
            carry_next[((size_t)neighbor * (size_t)depth)
×
5045
                       + (size_t)channel] += term;
×
5046
        }
5047
    }
5048
    if (y + 2 < height) {
×
5049
        for (i = 0; i < 3; ++i) {
×
5050
            neighbor = x + sign * row2_offsets[i];
×
5051
            if (neighbor < 0 || neighbor >= width) {
×
5052
                continue;
×
5053
            }
5054
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
5055
            carry_far[((size_t)neighbor * (size_t)depth)
×
5056
                      + (size_t)channel] += term;
×
5057
        }
5058
    }
5059
}
5060

5061

5062
static float
5063
mask_a (int x, int y, int c)
×
5064
{
5065
    return ((((x + c * 67) + y * 236) * 119) & 255 ) / 128.0 - 1.0;
×
5066
}
5067

5068
static float
5069
mask_x (int x, int y, int c)
×
5070
{
5071
    return ((((x + c * 29) ^ y* 149) * 1234) & 511 ) / 256.0 - 1.0;
×
5072
}
5073

5074
/* lookup closest color from palette with "normal" strategy */
5075
static int
5076
lookup_normal(unsigned char const * const pixel,
849,900✔
5077
              int const depth,
5078
              unsigned char const * const palette,
5079
              int const reqcolor,
5080
              unsigned short * const cachetable,
5081
              int const complexion)
5082
{
5083
    int result;
5084
    int diff;
5085
    int r;
5086
    int i;
5087
    int n;
5088
    int distant;
5089

5090
    result = (-1);
849,900✔
5091
    diff = INT_MAX;
849,900✔
5092

5093
    /* don't use cachetable in 'normal' strategy */
5094
    (void) cachetable;
283,300✔
5095

5096
    for (i = 0; i < reqcolor; i++) {
15,309,900✔
5097
        distant = 0;
14,460,000✔
5098
        r = pixel[0] - palette[i * depth + 0];
14,460,000✔
5099
        distant += r * r * complexion;
14,460,000✔
5100
        for (n = 1; n < depth; ++n) {
43,380,000✔
5101
            r = pixel[n] - palette[i * depth + n];
28,920,000✔
5102
            distant += r * r;
28,920,000✔
5103
        }
9,640,000✔
5104
        if (distant < diff) {
14,460,000✔
5105
            diff = distant;
2,211,216✔
5106
            result = i;
2,211,216✔
5107
        }
736,152✔
5108
    }
4,820,000✔
5109

5110
    return result;
849,900✔
5111
}
5112

5113

5114
/*
5115
 * Shared fast lookup flow:
5116
 *
5117
 *   pixel --> quantize --> cuckoo cache --> palette index
5118
 */
5119
static int
5120
lookup_fast_common(unsigned char const *pixel,
40,077,958✔
5121
                   unsigned char const *palette,
5122
                   int reqcolor,
5123
                   unsigned short *cachetable,
5124
                   int complexion,
5125
                   struct histogram_control control)
5126
{
5127
    int result;
5128
    unsigned int hash;
5129
    int diff;
5130
    int i;
5131
    int distant;
5132
    struct cuckoo_table32 *table;
5133
    uint32_t *slot;
5134
    SIXELSTATUS status;
5135
    unsigned char const *entry;
5136
    unsigned char const *end;
5137
    int pixel0;
5138
    int pixel1;
5139
    int pixel2;
5140
    int delta;
5141

5142
    result = (-1);
40,077,958✔
5143
    diff = INT_MAX;
40,077,958✔
5144
    hash = computeHash(pixel, 3U, &control);
40,077,958✔
5145

5146
    table = (struct cuckoo_table32 *)cachetable;
40,077,958✔
5147
    if (table != NULL) {
40,077,958!
5148
        slot = cuckoo_table32_lookup(table, hash);
40,077,958✔
5149
        if (slot != NULL && *slot != 0U) {
40,077,958!
5150
            return (int)(*slot - 1U);
38,412,769✔
5151
        }
5152
    }
538,191✔
5153

5154
    entry = palette;
1,665,189✔
5155
    end = palette + (size_t)reqcolor * 3;
1,665,189✔
5156
    pixel0 = (int)pixel[0];
1,665,189✔
5157
    pixel1 = (int)pixel[1];
1,665,189✔
5158
    pixel2 = (int)pixel[2];
1,665,189✔
5159
    /*
5160
     * Palette traversal as RGB triplets keeps the stride linear:
5161
     *
5162
     *   i -> [R][G][B]
5163
     *        |  |  |
5164
     *        `--+--'
5165
     *           v
5166
     *         entry
5167
     */
5168
    for (i = 0; entry < end; ++i, entry += 3) {
296,403,958✔
5169
        delta = pixel0 - (int)entry[0];
294,738,769✔
5170
        distant = delta * delta * complexion;
294,738,769✔
5171
        delta = pixel1 - (int)entry[1];
294,738,769✔
5172
        distant += delta * delta;
294,738,769✔
5173
        delta = pixel2 - (int)entry[2];
294,738,769✔
5174
        distant += delta * delta;
294,738,769✔
5175
        if (distant < diff) {
294,738,769✔
5176
            diff = distant;
12,447,620✔
5177
            result = i;
12,447,620✔
5178
        }
3,940,154✔
5179
    }
95,327,923✔
5180

5181
    if (table != NULL && result >= 0) {
1,665,189!
5182
        status = cuckoo_table32_insert(table,
2,203,380✔
5183
                                       hash,
538,191✔
5184
                                       (uint32_t)(result + 1));
1,665,189✔
5185
        if (SIXEL_FAILED(status)) {
1,665,189!
5186
            /* ignore cache update failure */
5187
        }
5188
    }
538,191✔
5189

5190
    return result;
1,665,189✔
5191
}
19,005,818✔
5192

5193
/* lookup closest color from palette with "fast" strategy */
5194
static int
5195
lookup_fast(unsigned char const * const pixel,
40,077,958✔
5196
            int const depth,
5197
            unsigned char const * const palette,
5198
            int const reqcolor,
5199
            unsigned short * const cachetable,
5200
            int const complexion)
5201
{
5202
    struct histogram_control control;
5203

5204
    (void)depth;
19,005,818✔
5205

5206
    control = histogram_control_make(3U);
40,077,958✔
5207

5208
    return lookup_fast_common(pixel,
59,083,776✔
5209
                              palette,
19,005,818✔
5210
                              reqcolor,
19,005,818✔
5211
                              cachetable,
19,005,818✔
5212
                              complexion,
19,005,818✔
5213
                              control);
5214
}
5215

5216
static int
5217
lookup_fast_robinhood(unsigned char const * const pixel,
×
5218
                      int const depth,
5219
                      unsigned char const * const palette,
5220
                      int const reqcolor,
5221
                      unsigned short * const cachetable,
5222
                      int const complexion)
5223
{
5224
    struct histogram_control control;
5225

5226
    (void)depth;
5227

5228
    control = histogram_control_make_for_policy(3U,
×
5229
                                                SIXEL_LUT_POLICY_ROBINHOOD);
5230

5231
    return lookup_fast_common(pixel,
×
5232
                              palette,
5233
                              reqcolor,
5234
                              cachetable,
5235
                              complexion,
5236
                              control);
5237
}
5238

5239
static int
5240
lookup_fast_hopscotch(unsigned char const * const pixel,
×
5241
                      int const depth,
5242
                      unsigned char const * const palette,
5243
                      int const reqcolor,
5244
                      unsigned short * const cachetable,
5245
                      int const complexion)
5246
{
5247
    struct histogram_control control;
5248

5249
    (void)depth;
5250

5251
    control = histogram_control_make_for_policy(3U,
×
5252
                                                SIXEL_LUT_POLICY_HOPSCOTCH);
5253

5254
    return lookup_fast_common(pixel,
×
5255
                              palette,
5256
                              reqcolor,
5257
                              cachetable,
5258
                              complexion,
5259
                              control);
5260
}
5261

5262

5263
static int
5264
lookup_mono_darkbg(unsigned char const * const pixel,
1,730,520✔
5265
                   int const depth,
5266
                   unsigned char const * const palette,
5267
                   int const reqcolor,
5268
                   unsigned short * const cachetable,
5269
                   int const complexion)
5270
{
5271
    int n;
5272
    int distant;
5273

5274
    /* unused */ (void) palette;
576,840✔
5275
    /* unused */ (void) cachetable;
576,840✔
5276
    /* unused */ (void) complexion;
576,840✔
5277

5278
    distant = 0;
1,730,520✔
5279
    for (n = 0; n < depth; ++n) {
6,922,080✔
5280
        distant += pixel[n];
5,191,560✔
5281
    }
1,730,520✔
5282
    return distant >= 128 * reqcolor ? 1: 0;
1,730,520✔
5283
}
5284

5285

5286
static int
5287
lookup_mono_lightbg(unsigned char const * const pixel,
810,000✔
5288
                    int const depth,
5289
                    unsigned char const * const palette,
5290
                    int const reqcolor,
5291
                    unsigned short * const cachetable,
5292
                    int const complexion)
5293
{
5294
    int n;
5295
    int distant;
5296

5297
    /* unused */ (void) palette;
270,000✔
5298
    /* unused */ (void) cachetable;
270,000✔
5299
    /* unused */ (void) complexion;
270,000✔
5300

5301
    distant = 0;
810,000✔
5302
    for (n = 0; n < depth; ++n) {
3,240,000✔
5303
        distant += pixel[n];
2,430,000✔
5304
    }
810,000✔
5305
    return distant < 128 * reqcolor ? 1: 0;
810,000✔
5306
}
5307

5308

5309
static SIXELSTATUS
NEW
5310
build_palette_kmeans(unsigned char **result,
×
5311
                     unsigned char const *data,
5312
                     unsigned int length,
5313
                     unsigned int depth,
5314
                     unsigned int reqcolors,
5315
                     unsigned int *ncolors,
5316
                     unsigned int *origcolors,
5317
                     int quality_mode,
5318
                     int force_palette,
5319
                     sixel_allocator_t *allocator)
5320
{
5321
    SIXELSTATUS status;
5322
    unsigned int channels;
5323
    unsigned int pixel_count;
5324
    unsigned int sample_limit;
5325
    unsigned int sample_cap;
5326
    unsigned int valid_seen;
5327
    unsigned int sample_count;
5328
    unsigned int k;
5329
    unsigned int index;
5330
    unsigned int channel;
5331
    unsigned int center_index;
5332
    unsigned int sample_index;
5333
    unsigned int replace;
5334
    unsigned int max_iterations;
5335
    unsigned int iteration;
5336
    unsigned int best_index;
5337
    unsigned int old_cluster;
5338
    unsigned int farthest_index;
5339
    unsigned int fill;
5340
    unsigned int source;
5341
    unsigned int swap_temp;
5342
    unsigned int base;
5343
    unsigned int extra_component;
5344
    unsigned int *membership;
5345
    unsigned int *order;
5346
    unsigned char *samples;
5347
    unsigned char *palette;
5348
    unsigned char *new_palette;
5349
    double *centers;
5350
    double *distance_cache;
5351
    double total_weight;
5352
    double random_point;
5353
    double best_distance;
5354
    double distance;
5355
    double diff;
5356
    double update;
5357
    double farthest_distance;
5358
    unsigned long *counts;
5359
    unsigned long *accum;
5360
    unsigned long *channel_sum;
5361
    unsigned long rand_value;
5362
    int changed;
5363

5364
    status = SIXEL_BAD_ARGUMENT;
×
5365
    channels = depth;
×
5366
    pixel_count = 0U;
×
5367
    sample_limit = 50000U;
×
5368
    sample_cap = sample_limit;
×
5369
    valid_seen = 0U;
×
5370
    sample_count = 0U;
×
5371
    k = 0U;
×
5372
    index = 0U;
×
5373
    channel = 0U;
×
5374
    center_index = 0U;
×
5375
    sample_index = 0U;
×
5376
    replace = 0U;
×
5377
    max_iterations = 0U;
×
5378
    iteration = 0U;
×
5379
    best_index = 0U;
×
5380
    old_cluster = 0U;
×
5381
    farthest_index = 0U;
×
5382
    fill = 0U;
×
5383
    source = 0U;
×
5384
    swap_temp = 0U;
×
5385
    base = 0U;
×
5386
    extra_component = 0U;
×
5387
    membership = NULL;
×
5388
    order = NULL;
×
5389
    samples = NULL;
×
5390
    palette = NULL;
×
5391
    new_palette = NULL;
×
5392
    centers = NULL;
×
5393
    distance_cache = NULL;
×
5394
    counts = NULL;
×
5395
    accum = NULL;
×
5396
    channel_sum = NULL;
×
5397
    rand_value = 0UL;
×
5398
    total_weight = 0.0;
×
5399
    random_point = 0.0;
×
5400
    best_distance = 0.0;
×
5401
    distance = 0.0;
×
5402
    diff = 0.0;
×
5403
    update = 0.0;
×
5404
    farthest_distance = 0.0;
×
5405
    changed = 0;
×
5406

5407
    if (result != NULL) {
×
5408
        *result = NULL;
×
5409
    }
5410
    if (ncolors != NULL) {
×
5411
        *ncolors = 0U;
×
5412
    }
5413
    if (origcolors != NULL) {
×
5414
        *origcolors = 0U;
×
5415
    }
5416

5417
    if (channels != 3U && channels != 4U) {
×
5418
        goto end;
×
5419
    }
5420
    if (channels == 0U) {
×
5421
        goto end;
×
5422
    }
5423

5424
    pixel_count = length / channels;
×
5425
    if (pixel_count == 0U) {
×
5426
        goto end;
×
5427
    }
5428
    if (pixel_count < sample_cap) {
×
5429
        sample_cap = pixel_count;
×
5430
    }
5431
    if (sample_cap == 0U) {
×
5432
        sample_cap = 1U;
×
5433
    }
5434

5435
    samples = (unsigned char *)sixel_allocator_malloc(
×
5436
        allocator, (size_t)sample_cap * 3U);
×
5437
    if (samples == NULL) {
×
5438
        status = SIXEL_BAD_ALLOCATION;
×
5439
        goto end;
×
5440
    }
5441

5442
    /*
5443
     * Reservoir sampling keeps the distribution fair when the image is
5444
     * larger than our budget. Transparent pixels are skipped so that the
5445
     * solver only sees visible colors.
5446
     */
5447
    for (index = 0U; index < pixel_count; ++index) {
×
5448
        base = index * channels;
×
5449
        if (channels == 4U && data[base + 3U] == 0U) {
×
5450
            continue;
×
5451
        }
5452
        ++valid_seen;
×
5453
        if (sample_count < sample_cap) {
×
5454
            for (channel = 0U; channel < 3U; ++channel) {
×
5455
                samples[sample_count * 3U + channel] =
×
5456
                    data[base + channel];
×
5457
            }
5458
            ++sample_count;
×
5459
        } else {
5460
            rand_value = (unsigned long)rand();
×
5461
            replace = (unsigned int)(rand_value % valid_seen);
×
5462
            if (replace < sample_cap) {
×
5463
                for (channel = 0U; channel < 3U; ++channel) {
×
5464
                    samples[replace * 3U + channel] =
×
5465
                        data[base + channel];
×
5466
                }
5467
            }
5468
        }
5469
    }
5470

5471
    if (origcolors != NULL) {
×
5472
        *origcolors = valid_seen;
×
5473
    }
5474
    if (sample_count == 0U) {
×
5475
        goto end;
×
5476
    }
5477

5478
    if (reqcolors == 0U) {
×
5479
        reqcolors = 1U;
×
5480
    }
5481
    k = reqcolors;
×
5482
    if (k > sample_count) {
×
5483
        k = sample_count;
×
5484
    }
5485
    if (k == 0U) {
×
5486
        goto end;
×
5487
    }
5488

5489
    centers = (double *)sixel_allocator_malloc(
×
5490
        allocator, (size_t)k * 3U * sizeof(double));
×
5491
    distance_cache = (double *)sixel_allocator_malloc(
×
5492
        allocator, (size_t)sample_count * sizeof(double));
×
5493
    counts = (unsigned long *)sixel_allocator_malloc(
×
5494
        allocator, (size_t)k * sizeof(unsigned long));
×
5495
    accum = (unsigned long *)sixel_allocator_malloc(
×
5496
        allocator, (size_t)k * 3U * sizeof(unsigned long));
×
5497
    membership = (unsigned int *)sixel_allocator_malloc(
×
5498
        allocator, (size_t)sample_count * sizeof(unsigned int));
×
5499
    if (centers == NULL || distance_cache == NULL || counts == NULL ||
×
5500
            accum == NULL || membership == NULL) {
×
5501
        status = SIXEL_BAD_ALLOCATION;
×
5502
        goto end;
×
5503
    }
5504

5505
    /*
5506
     * Seed the first center uniformly from the sampled set. Subsequent
5507
     * centers use k-means++ to favour distant samples.
5508
     */
5509
    rand_value = (unsigned long)rand();
×
5510
    replace = (unsigned int)(rand_value % sample_count);
×
5511
    for (channel = 0U; channel < 3U; ++channel) {
×
5512
        centers[channel] =
×
5513
            (double)samples[replace * 3U + channel];
×
5514
    }
5515
    for (sample_index = 0U; sample_index < sample_count; ++sample_index) {
×
5516
        distance = 0.0;
×
5517
        for (channel = 0U; channel < 3U; ++channel) {
×
5518
            diff = (double)samples[sample_index * 3U + channel]
×
5519
                - centers[channel];
×
5520
            distance += diff * diff;
×
5521
        }
5522
        distance_cache[sample_index] = distance;
×
5523
    }
5524

5525
    for (center_index = 1U; center_index < k; ++center_index) {
×
5526
        total_weight = 0.0;
×
5527
        for (sample_index = 0U; sample_index < sample_count;
×
5528
                ++sample_index) {
×
5529
            total_weight += distance_cache[sample_index];
×
5530
        }
5531
        random_point = 0.0;
×
5532
        if (total_weight > 0.0) {
×
5533
            random_point =
×
5534
                ((double)rand() / ((double)RAND_MAX + 1.0)) *
×
5535
                total_weight;
5536
        }
5537
        sample_index = 0U;
×
5538
        while (sample_index + 1U < sample_count &&
×
5539
               random_point > distance_cache[sample_index]) {
×
5540
            random_point -= distance_cache[sample_index];
×
5541
            ++sample_index;
×
5542
        }
5543
        for (channel = 0U; channel < 3U; ++channel) {
×
5544
            centers[center_index * 3U + channel] =
×
5545
                (double)samples[sample_index * 3U + channel];
×
5546
        }
5547
        for (index = 0U; index < sample_count; ++index) {
×
5548
            distance = 0.0;
×
5549
            for (channel = 0U; channel < 3U; ++channel) {
×
5550
                diff = (double)samples[index * 3U + channel]
×
5551
                    - centers[center_index * 3U + channel];
×
5552
                distance += diff * diff;
×
5553
            }
5554
            if (distance < distance_cache[index]) {
×
5555
                distance_cache[index] = distance;
×
5556
            }
5557
        }
5558
    }
5559

5560
    switch (quality_mode) {
×
5561
    case SIXEL_QUALITY_LOW:
5562
        max_iterations = 6U;
×
5563
        break;
×
5564
    case SIXEL_QUALITY_HIGH:
5565
        max_iterations = 24U;
×
5566
        break;
×
5567
    case SIXEL_QUALITY_FULL:
5568
        max_iterations = 48U;
×
5569
        break;
×
5570
    case SIXEL_QUALITY_HIGHCOLOR:
5571
        max_iterations = 24U;
×
5572
        break;
×
5573
    case SIXEL_QUALITY_AUTO:
×
5574
    default:
5575
        max_iterations = 12U;
×
5576
        break;
×
5577
    }
5578
    if (max_iterations == 0U) {
×
5579
        max_iterations = 1U;
×
5580
    }
5581
    if (max_iterations > 20U) {
×
5582
        /*
5583
         * The requirements cap the Lloyd refinement at twenty passes to
5584
         * keep runtime bounded even for demanding quality presets.
5585
         */
5586
        max_iterations = 20U;
×
5587
    }
5588

5589
    /*
5590
     * Lloyd refinement assigns samples to their nearest center and moves
5591
     * each center to the mean of its cluster. Empty clusters are reseeded
5592
     * using the farthest sample to improve stability.
5593
     */
5594
    for (iteration = 0U; iteration < max_iterations; ++iteration) {
×
5595
        for (index = 0U; index < k; ++index) {
×
5596
            counts[index] = 0UL;
×
5597
        }
5598
        for (index = 0U; index < k * 3U; ++index) {
×
5599
            accum[index] = 0UL;
×
5600
        }
5601
        for (sample_index = 0U; sample_index < sample_count;
×
5602
                ++sample_index) {
×
5603
            best_index = 0U;
×
5604
            distance = 0.0;
×
5605
            for (channel = 0U; channel < 3U; ++channel) {
×
5606
                diff = (double)samples[sample_index * 3U + channel]
×
5607
                    - centers[channel];
×
5608
                distance += diff * diff;
×
5609
            }
5610
            best_distance = distance;
×
5611
            for (center_index = 1U; center_index < k;
×
5612
                    ++center_index) {
×
5613
                distance = 0.0;
×
5614
                for (channel = 0U; channel < 3U; ++channel) {
×
5615
                    diff = (double)samples[sample_index * 3U + channel]
×
5616
                        - centers[center_index * 3U + channel];
×
5617
                    distance += diff * diff;
×
5618
                }
5619
                if (distance < best_distance) {
×
5620
                    best_distance = distance;
×
5621
                    best_index = center_index;
×
5622
                }
5623
            }
5624
            membership[sample_index] = best_index;
×
5625
            distance_cache[sample_index] = best_distance;
×
5626
            counts[best_index] += 1UL;
×
5627
            channel_sum = accum + (size_t)best_index * 3U;
×
5628
            for (channel = 0U; channel < 3U; ++channel) {
×
5629
                channel_sum[channel] +=
×
5630
                    (unsigned long)samples[sample_index * 3U + channel];
×
5631
            }
5632
        }
5633
        for (center_index = 0U; center_index < k; ++center_index) {
×
5634
            if (counts[center_index] != 0UL) {
×
5635
                continue;
×
5636
            }
5637
            farthest_distance = -1.0;
×
5638
            farthest_index = 0U;
×
5639
            for (sample_index = 0U; sample_index < sample_count;
×
5640
                    ++sample_index) {
×
5641
                if (distance_cache[sample_index] > farthest_distance) {
×
5642
                    farthest_distance = distance_cache[sample_index];
×
5643
                    farthest_index = sample_index;
×
5644
                }
5645
            }
5646
            old_cluster = membership[farthest_index];
×
5647
            if (counts[old_cluster] > 0UL) {
×
5648
                counts[old_cluster] -= 1UL;
×
5649
                channel_sum = accum + (size_t)old_cluster * 3U;
×
5650
                for (channel = 0U; channel < 3U; ++channel) {
×
5651
                    extra_component =
×
5652
                        (unsigned int)samples[farthest_index * 3U + channel];
×
5653
                    if (channel_sum[channel] >=
×
5654
                            (unsigned long)extra_component) {
×
5655
                        channel_sum[channel] -=
×
5656
                            (unsigned long)extra_component;
×
5657
                    } else {
5658
                        channel_sum[channel] = 0UL;
×
5659
                    }
5660
                }
5661
            }
5662
            membership[farthest_index] = center_index;
×
5663
            counts[center_index] = 1UL;
×
5664
            channel_sum = accum + (size_t)center_index * 3U;
×
5665
            for (channel = 0U; channel < 3U; ++channel) {
×
5666
                channel_sum[channel] =
×
5667
                    (unsigned long)samples[farthest_index * 3U + channel];
×
5668
            }
5669
            distance_cache[farthest_index] = 0.0;
×
5670
        }
5671
        changed = 0;
×
5672
        for (center_index = 0U; center_index < k; ++center_index) {
×
5673
            if (counts[center_index] == 0UL) {
×
5674
                continue;
×
5675
            }
5676
            channel_sum = accum + (size_t)center_index * 3U;
×
5677
            for (channel = 0U; channel < 3U; ++channel) {
×
5678
                update = (double)channel_sum[channel]
×
5679
                    / (double)counts[center_index];
×
5680
                diff = centers[center_index * 3U + channel] - update;
×
5681
                if (diff < 0.0) {
×
5682
                    diff = -diff;
×
5683
                }
5684
                if (diff > 0.5) {
×
5685
                    changed = 1;
×
5686
                }
5687
                centers[center_index * 3U + channel] = update;
×
5688
            }
5689
        }
5690
        if (!changed) {
×
5691
            break;
×
5692
        }
5693
    }
5694

5695
    /*
5696
     * Convert the floating point centers back into the byte palette that
5697
     * callers expect.
5698
     */
5699
    palette = (unsigned char *)sixel_allocator_malloc(
×
5700
        allocator, (size_t)k * 3U);
×
5701
    if (palette == NULL) {
×
5702
        status = SIXEL_BAD_ALLOCATION;
×
5703
        goto end;
×
5704
    }
5705
    for (center_index = 0U; center_index < k; ++center_index) {
×
5706
        for (channel = 0U; channel < 3U; ++channel) {
×
5707
            update = centers[center_index * 3U + channel];
×
5708
            if (update < 0.0) {
×
5709
                update = 0.0;
×
5710
            }
5711
            if (update > 255.0) {
×
5712
                update = 255.0;
×
5713
            }
5714
            palette[center_index * 3U + channel] =
×
5715
                (unsigned char)(update + 0.5);
×
5716
        }
5717
    }
5718

5719
    if (force_palette && k < reqcolors) {
×
5720
        /*
5721
         * Populate the tail of the palette by repeating the most frequent
5722
         * clusters so the caller still receives the requested palette size.
5723
         */
5724
        new_palette = (unsigned char *)sixel_allocator_malloc(
×
5725
            allocator, (size_t)reqcolors * 3U);
×
5726
        if (new_palette == NULL) {
×
5727
            status = SIXEL_BAD_ALLOCATION;
×
5728
            goto end;
×
5729
        }
5730
        for (index = 0U; index < k * 3U; ++index) {
×
5731
            new_palette[index] = palette[index];
×
5732
        }
5733
        order = (unsigned int *)sixel_allocator_malloc(
×
5734
            allocator, (size_t)k * sizeof(unsigned int));
×
5735
        if (order == NULL) {
×
5736
            status = SIXEL_BAD_ALLOCATION;
×
5737
            goto end;
×
5738
        }
5739
        for (index = 0U; index < k; ++index) {
×
5740
            order[index] = index;
×
5741
        }
5742
        for (index = 0U; index < k; ++index) {
×
5743
            for (center_index = index + 1U; center_index < k;
×
5744
                    ++center_index) {
×
5745
                if (counts[order[center_index]] >
×
5746
                        counts[order[index]]) {
×
5747
                    swap_temp = order[index];
×
5748
                    order[index] = order[center_index];
×
5749
                    order[center_index] = swap_temp;
×
5750
                }
5751
            }
5752
        }
5753
        fill = k;
×
5754
        source = 0U;
×
5755
        while (fill < reqcolors && k > 0U) {
×
5756
            center_index = order[source];
×
5757
            for (channel = 0U; channel < 3U; ++channel) {
×
5758
                new_palette[fill * 3U + channel] =
×
5759
                    palette[center_index * 3U + channel];
×
5760
            }
5761
            ++fill;
×
5762
            ++source;
×
5763
            if (source >= k) {
×
5764
                source = 0U;
×
5765
            }
5766
        }
5767
        sixel_allocator_free(allocator, palette);
×
5768
        palette = new_palette;
×
5769
        new_palette = NULL;
×
5770
        k = reqcolors;
×
5771
    }
5772

5773
    status = SIXEL_OK;
×
5774
    if (result != NULL) {
×
5775
        *result = palette;
×
5776
    } else {
5777
        palette = NULL;
×
5778
    }
5779
    if (ncolors != NULL) {
×
5780
        *ncolors = k;
×
5781
    }
5782

5783
end:
5784
    if (status != SIXEL_OK && palette != NULL) {
×
5785
        sixel_allocator_free(allocator, palette);
×
5786
    }
5787
    if (new_palette != NULL) {
×
5788
        sixel_allocator_free(allocator, new_palette);
×
5789
    }
5790
    if (order != NULL) {
×
5791
        sixel_allocator_free(allocator, order);
×
5792
    }
5793
    if (membership != NULL) {
×
5794
        sixel_allocator_free(allocator, membership);
×
5795
    }
5796
    if (accum != NULL) {
×
5797
        sixel_allocator_free(allocator, accum);
×
5798
    }
5799
    if (counts != NULL) {
×
5800
        sixel_allocator_free(allocator, counts);
×
5801
    }
5802
    if (distance_cache != NULL) {
×
5803
        sixel_allocator_free(allocator, distance_cache);
×
5804
    }
5805
    if (centers != NULL) {
×
5806
        sixel_allocator_free(allocator, centers);
×
5807
    }
5808
    if (samples != NULL) {
×
5809
        sixel_allocator_free(allocator, samples);
×
5810
    }
5811
    return status;
×
5812
}
5813

5814

5815
/* choose colors using median-cut method */
5816
SIXELSTATUS
5817
sixel_quant_make_palette(
260✔
5818
    unsigned char          /* out */ **result,
5819
    unsigned char const    /* in */  *data,
5820
    unsigned int           /* in */  length,
5821
    int                    /* in */  pixelformat,
5822
    unsigned int           /* in */  reqcolors,
5823
    unsigned int           /* in */  *ncolors,
5824
    unsigned int           /* in */  *origcolors,
5825
    int                    /* in */  methodForLargest,
5826
    int                    /* in */  methodForRep,
5827
    int                    /* in */  qualityMode,
5828
    int                    /* in */  force_palette,
5829
    int                    /* in */  use_reversible,
5830
    int                    /* in */  quantize_model,
5831
    sixel_allocator_t      /* in */  *allocator)
5832
{
5833
    SIXELSTATUS status = SIXEL_FALSE;
260✔
5834
    unsigned int i;
5835
    unsigned int n;
5836
    int ret;
5837
    tupletable2 colormap;
5838
    unsigned int depth;
5839
    int result_depth;
5840

5841
    result_depth = sixel_helper_compute_depth(pixelformat);
260✔
5842
    if (result_depth <= 0) {
260!
5843
        *result = NULL;
×
5844
        goto end;
×
5845
    }
5846

5847
    depth = (unsigned int)result_depth;
260✔
5848

5849
    if (quantize_model == SIXEL_QUANTIZE_MODEL_KMEANS) {
260!
NEW
5850
        status = build_palette_kmeans(result,
×
5851
                                      data,
5852
                                      length,
5853
                                      depth,
5854
                                      reqcolors,
5855
                                      ncolors,
5856
                                      origcolors,
5857
                                      qualityMode,
5858
                                      force_palette,
5859
                                      allocator);
5860
        if (SIXEL_SUCCEEDED(status)) {
×
5861
            if (use_reversible) {
×
5862
                sixel_quant_reversible_palette(*result,
×
5863
                                               *ncolors,
5864
                                               depth);
5865
            }
5866
            return status;
×
5867
        }
5868
    }
5869

5870
    ret = computeColorMapFromInput(data, length, depth,
378✔
5871
                                   reqcolors, methodForLargest,
118✔
5872
                                   methodForRep, qualityMode,
118✔
5873
                                   force_palette, use_reversible,
118✔
5874
                                   &colormap, origcolors, allocator);
118✔
5875
    if (ret != 0) {
260!
5876
        *result = NULL;
×
5877
        goto end;
×
5878
    }
5879
    *ncolors = colormap.size;
260✔
5880
    quant_trace(stderr, "tupletable size: %d\n", *ncolors);
260✔
5881
    *result = (unsigned char *)sixel_allocator_malloc(allocator, *ncolors * depth);
260✔
5882
    for (i = 0; i < *ncolors; i++) {
17,031✔
5883
        for (n = 0; n < depth; ++n) {
67,084✔
5884
            (*result)[i * depth + n] = colormap.table[i]->tuple[n];
50,313✔
5885
        }
17,967✔
5886
    }
5,989✔
5887

5888
    if (use_reversible) {
260!
5889
        sixel_quant_reversible_palette(*result, *ncolors, depth);
×
5890
    }
5891

5892
    sixel_allocator_free(allocator, colormap.table);
260✔
5893

5894
    status = SIXEL_OK;
260✔
5895

5896
end:
142✔
5897
    return status;
260✔
5898
}
118✔
5899

5900

5901
/* apply color palette into specified pixel buffers */
5902
SIXELSTATUS
5903
sixel_quant_apply_palette(
285✔
5904
    sixel_index_t     /* out */ *result,
5905
    unsigned char     /* in */  *data,
5906
    int               /* in */  width,
5907
    int               /* in */  height,
5908
    int               /* in */  depth,
5909
    unsigned char     /* in */  *palette,
5910
    int               /* in */  reqcolor,
5911
    int               /* in */  methodForDiffuse,
5912
    int               /* in */  methodForScan,
5913
    int               /* in */  methodForCarry,
5914
    int               /* in */  foptimize,
5915
    int               /* in */  foptimize_palette,
5916
    int               /* in */  complexion,
5917
    unsigned short    /* in */  *cachetable,
5918
    int               /* in */  *ncolors,
5919
    sixel_allocator_t /* in */  *allocator)
5920
{
170✔
5921
#if _MSC_VER
5922
    enum { max_depth = 4 };
5923
#else
5924
    const size_t max_depth = 4;
285✔
5925
#endif
5926
    unsigned char copy[max_depth];
170✔
5927
    SIXELSTATUS status = SIXEL_FALSE;
285✔
5928
    int sum1, sum2;
5929
    int n;
5930
    unsigned short *indextable;
5931
    size_t cache_size;
5932
    int allocated_cache;
5933
    int use_cache;
5934
    int cache_policy;
5935
    unsigned char new_palette[SIXEL_PALETTE_MAX * 4];
5936
    unsigned short migration_map[SIXEL_PALETTE_MAX];
5937
    int (*f_lookup)(unsigned char const * const pixel,
5938
                    int const depth,
5939
                    unsigned char const * const palette,
5940
                    int const reqcolor,
5941
                    unsigned short * const cachetable,
5942
                    int const complexion);
5943
    int use_varerr;
5944
    int use_positional;
5945
    int carry_mode;
5946

5947
    /* check bad reqcolor */
5948
    if (reqcolor < 1) {
285!
5949
        status = SIXEL_BAD_ARGUMENT;
×
5950
        sixel_helper_set_additional_message(
×
5951
            "sixel_quant_apply_palette: "
5952
            "a bad argument is detected, reqcolor < 0.");
5953
        goto end;
×
5954
    }
5955

5956
    /* NOTE: diffuse_jajuni, diffuse_stucki, and diffuse_burkes reference at
5957
     * minimum the position pos + width * 1 - 2, so width must be at least 2
5958
     * to avoid underflow.
5959
     * On the other hand, diffuse_fs and diffuse_atkinson
5960
     * reference pos + width * 1 - 1, but since these functions are only called
5961
     * when width >= 1, they do not cause underflow.
5962
     */
5963
    use_varerr = (depth == 3
400✔
5964
                  && methodForDiffuse == SIXEL_DIFFUSE_LSO2);
285!
5965
    use_positional = (methodForDiffuse == SIXEL_DIFFUSE_A_DITHER
400✔
5966
                      || methodForDiffuse == SIXEL_DIFFUSE_X_DITHER);
285!
5967
    carry_mode = (methodForCarry == SIXEL_CARRY_ENABLE)
285✔
5968
               ? SIXEL_CARRY_ENABLE
5969
               : SIXEL_CARRY_DISABLE;
170!
5970

5971
    f_lookup = NULL;
285✔
5972
    if (reqcolor == 2) {
285✔
5973
        sum1 = 0;
19✔
5974
        sum2 = 0;
19✔
5975
        for (n = 0; n < depth; ++n) {
76✔
5976
            sum1 += palette[n];
57✔
5977
        }
21✔
5978
        for (n = depth; n < depth + depth; ++n) {
76✔
5979
            sum2 += palette[n];
57✔
5980
        }
21✔
5981
        if (sum1 == 0 && sum2 == 255 * 3) {
19!
5982
            f_lookup = lookup_mono_darkbg;
12✔
5983
        } else if (sum1 == 255 * 3 && sum2 == 0) {
11!
5984
            f_lookup = lookup_mono_lightbg;
3✔
5985
        }
1✔
5986
    }
7✔
5987
    if (f_lookup == NULL) {
285✔
5988
        if (foptimize && depth == 3) {
270!
5989
            f_lookup = lookup_fast;
264✔
5990
        } else {
108✔
5991
            f_lookup = lookup_normal;
6✔
5992
        }
5993
    }
110✔
5994

5995
    if (f_lookup == lookup_fast) {
285✔
5996
        if (histogram_lut_policy == SIXEL_LUT_POLICY_ROBINHOOD) {
264!
5997
            f_lookup = lookup_fast_robinhood;
×
5998
        } else if (histogram_lut_policy == SIXEL_LUT_POLICY_HOPSCOTCH) {
264!
5999
            f_lookup = lookup_fast_hopscotch;
×
6000
        }
6001
    }
108✔
6002

6003
    indextable = cachetable;
285✔
6004
    allocated_cache = 0;
285✔
6005
    cache_policy = SIXEL_LUT_POLICY_AUTO;
285✔
6006
    use_cache = 0;
285✔
6007
    if (f_lookup == lookup_fast) {
285✔
6008
        cache_policy = histogram_lut_policy;
264✔
6009
        use_cache = 1;
264✔
6010
    } else if (f_lookup == lookup_fast_robinhood) {
129!
6011
        cache_policy = SIXEL_LUT_POLICY_ROBINHOOD;
×
6012
        use_cache = 1;
×
6013
    } else if (f_lookup == lookup_fast_hopscotch) {
21!
6014
        cache_policy = SIXEL_LUT_POLICY_HOPSCOTCH;
×
6015
        use_cache = 1;
×
6016
    }
6017
    if (cache_policy == SIXEL_LUT_POLICY_AUTO) {
285!
6018
        cache_policy = SIXEL_LUT_POLICY_6BIT;
285✔
6019
    }
115✔
6020
    if (use_cache) {
285✔
6021
        if (cachetable == NULL) {
264!
6022
            status = sixel_quant_cache_prepare(&indextable,
×
6023
                                               &cache_size,
6024
                                               cache_policy,
6025
                                               reqcolor,
6026
                                               allocator);
6027
            if (SIXEL_FAILED(status)) {
×
6028
                quant_trace(stderr,
×
6029
                            "Unable to allocate lookup cache.\n");
6030
                goto end;
×
6031
            }
6032
            allocated_cache = 1;
×
6033
        } else {
6034
            sixel_quant_cache_clear(indextable, cache_policy);
264✔
6035
        }
6036
    }
108✔
6037

6038
    if (use_positional) {
285!
6039
        status = apply_palette_positional(result, data, width, height,
×
6040
                                          depth, palette, reqcolor,
6041
                                          methodForDiffuse, methodForScan,
6042
                                          foptimize_palette, f_lookup,
6043
                                          indextable, complexion, copy,
6044
                                          new_palette, migration_map,
6045
                                          ncolors);
6046
    } else if (use_varerr) {
285!
6047
        status = apply_palette_variable(result, data, width, height,
×
6048
                                        depth, palette, reqcolor,
6049
                                        methodForScan, foptimize_palette,
6050
                                        f_lookup, indextable, complexion,
6051
                                        new_palette, migration_map,
6052
                                        ncolors,
6053
                                        methodForDiffuse,
6054
                                        carry_mode);
6055
    } else {
6056
        status = apply_palette_fixed(result, data, width, height,
400✔
6057
                                     depth, palette, reqcolor,
115✔
6058
                                     methodForScan, foptimize_palette,
115✔
6059
                                     f_lookup, indextable, complexion,
115✔
6060
                                     new_palette, migration_map,
115✔
6061
                                     ncolors, methodForDiffuse,
115✔
6062
                                     carry_mode);
115✔
6063
    }
6064
    if (SIXEL_FAILED(status)) {
285!
6065
        goto end;
×
6066
    }
6067

6068
    if (allocated_cache) {
285!
6069
        sixel_quant_cache_release(indextable,
×
6070
                                  cache_policy,
6071
                                  allocator);
6072
    }
6073

6074
    status = SIXEL_OK;
285✔
6075

6076
end:
170✔
6077
    return status;
285✔
6078
}
6079

6080

6081
void
6082
sixel_quant_free_palette(
260✔
6083
    unsigned char       /* in */ *data,
6084
    sixel_allocator_t   /* in */ *allocator)
6085
{
6086
    sixel_allocator_free(allocator, data);
260✔
6087
}
260✔
6088

6089

6090
#if HAVE_TESTS
6091
static int
6092
test1(void)
×
6093
{
6094
    int nret = EXIT_FAILURE;
×
6095
    sample minval[1] = { 1 };
×
6096
    sample maxval[1] = { 2 };
×
6097
    unsigned int retval;
6098

6099
    retval = largestByLuminosity(minval, maxval, 1);
×
6100
    if (retval != 0) {
×
6101
        goto error;
×
6102
    }
6103
    nret = EXIT_SUCCESS;
×
6104

6105
error:
6106
    return nret;
×
6107
}
6108

6109

6110
int
6111
sixel_quant_tests_main(void)
×
6112
{
6113
    int nret = EXIT_FAILURE;
×
6114
    size_t i;
6115
    typedef int (* testcase)(void);
6116

6117
    static testcase const testcases[] = {
6118
        test1,
6119
    };
6120

6121
    for (i = 0; i < sizeof(testcases) / sizeof(testcase); ++i) {
×
6122
        nret = testcases[i]();
×
6123
        if (nret != EXIT_SUCCESS) {
×
6124
            goto error;
×
6125
        }
6126
    }
6127

6128
    nret = EXIT_SUCCESS;
×
6129

6130
error:
6131
    return nret;
×
6132
}
6133
#endif  /* HAVE_TESTS */
6134

6135
/* emacs Local Variables:      */
6136
/* emacs mode: c               */
6137
/* emacs tab-width: 4          */
6138
/* emacs indent-tabs-mode: nil */
6139
/* emacs c-basic-offset: 4     */
6140
/* emacs End:                  */
6141
/* vim: set expandtab ts=4 sts=4 sw=4 : */
6142
/* EOF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc