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

saitoha / libsixel / 19918707358

04 Dec 2025 05:12AM UTC coverage: 38.402% (-4.0%) from 42.395%
19918707358

push

github

saitoha
tests: fix meson msys dll lookup

9738 of 38220 branches covered (25.48%)

12841 of 33438 relevant lines covered (38.4%)

782420.02 hits per line

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

29.26
/src/dither-fixed-8bit.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2025 libsixel developers. See `AUTHORS`.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 * SOFTWARE.
23
 */
24

25
#include "config.h"
26

27
#include <stdlib.h>
28
#include <string.h>
29
#include <stdint.h>
30
#include <limits.h>
31
#if HAVE_MATH_H
32
# include <math.h>
33
#endif  /* HAVE_MATH_H */
34

35
#include "dither-fixed-8bit.h"
36
#include "dither-common-pipeline.h"
37
#include "lookup-common.h"
38

39
/*
40
 * Local serpentine traversal helper.  The function mirrors the behaviour used
41
 * by other dithering strategies without forcing additional shared headers.
42
 */
43
static void
44
sixel_dither_scanline_params(int serpentine,
49,350✔
45
                             int index,
46
                             int limit,
47
                             int *start,
48
                             int *end,
49
                             int *step,
50
                             int *direction)
51
{
52
    if (serpentine && (index & 1)) {
1,350✔
53
        *start = limit - 1;
675✔
54
        *end = -1;
675✔
55
        *step = -1;
675✔
56
        *direction = -1;
675✔
57
    } else {
58
        *start = 0;
59
        *end = limit;
60
        *step = 1;
61
        *direction = 1;
62
    }
63
}
64

65
#define VARERR_SCALE_SHIFT 12
66
#define VARERR_SCALE       (1 << VARERR_SCALE_SHIFT)
67
#define VARERR_ROUND       (1 << (VARERR_SCALE_SHIFT - 1))
68
#define VARERR_MAX_VALUE   (255 * VARERR_SCALE)
69

70
static void
71
error_diffuse_normal(
270,039,078✔
72
    unsigned char /* in */    *data,      /* base address of pixel buffer */
73
    int           /* in */    pos,        /* address of the destination pixel */
74
    int           /* in */    depth,      /* color depth in bytes */
75
    int           /* in */    error,      /* error energy */
76
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
77
    int           /* in */    denominator /* denominator of diffusion coefficient */)
78
{
79
    int c;
270,039,078✔
80

81
    data += pos * depth;
270,039,078✔
82

83
    c = *data + (error * numerator * 2 / denominator + 1) / 2;
270,039,078✔
84
    if (c < 0) {
270,039,078✔
85
        c = 0;
86
    }
87
    if (c >= 1 << 8) {
270,039,078✔
88
        c = (1 << 8) - 1;
89
    }
90
    *data = (unsigned char)c;
270,039,078✔
91
}
202,505,454✔
92

93
static void
94
error_diffuse_fast(
165,505,689✔
95
    unsigned char /* in */    *data,      /* base address of pixel buffer */
96
    int           /* in */    pos,        /* address of the destination pixel */
97
    int           /* in */    depth,      /* color depth in bytes */
98
    int           /* in */    error,      /* error energy */
99
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
100
    int           /* in */    denominator /* denominator of diffusion coefficient */)
101
{
102
    int c;
165,505,689✔
103

104
    data += pos * depth;
165,505,689✔
105

106
    c = *data + error * numerator / denominator;
165,505,689✔
107
    if (c < 0) {
165,505,689✔
108
        c = 0;
109
    }
110
    if (c >= 1 << 8) {
165,505,689✔
111
        c = (1 << 8) - 1;
112
    }
113
    *data = (unsigned char)c;
165,505,689✔
114
}
137,890,143✔
115

116
/* error diffusion with precise strategy */
117
static void
118
error_diffuse_precise(
4,706,262✔
119
    unsigned char /* in */    *data,      /* base address of pixel buffer */
120
    int           /* in */    pos,        /* address of the destination pixel */
121
    int           /* in */    depth,      /* color depth in bytes */
122
    int           /* in */    error,      /* error energy */
123
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
124
    int           /* in */    denominator /* denominator of diffusion coefficient */)
125
{
126
    int c;
4,706,262✔
127

128
    data += pos * depth;
4,706,262✔
129

130
    c = (int)(*data + error * numerator / (double)denominator + 0.5);
4,706,262✔
131
    if (c < 0) {
4,706,262✔
132
        c = 0;
133
    }
134
    if (c >= 1 << 8) {
4,706,262!
135
        c = (1 << 8) - 1;
136
    }
137
    *data = (unsigned char)c;
4,706,262✔
138
}
4,706,262✔
139

140
typedef void (*diffuse_fixed_carry_mode)(int32_t *carry_curr,
141
                                         int32_t *carry_next,
142
                                         int32_t *carry_far,
143
                                         int width,
144
                                         int height,
145
                                         int depth,
146
                                         int x,
147
                                         int y,
148
                                         int32_t error,
149
                                         int direction,
150
                                         int channel);
151

152
static int32_t
153
diffuse_fixed_term(int32_t error, int numerator, int denominator)
×
154
{
155
    int64_t delta;
×
156

157
    delta = (int64_t)error * (int64_t)numerator;
×
158
    if (delta >= 0) {
×
159
        delta = (delta + denominator / 2) / denominator;
×
160
    } else {
161
        delta = (delta - denominator / 2) / denominator;
×
162
    }
163

164
    return (int32_t)delta;
×
165
}
166

167
static void diffuse_none(unsigned char *data,
168
                         int width,
169
                         int height,
170
                         int x,
171
                         int y,
172
                         int depth,
173
                         int error,
174
                         int direction);
175

176
static void diffuse_none_carry(int32_t *carry_curr,
177
                               int32_t *carry_next,
178
                               int32_t *carry_far,
179
                               int width,
180
                               int height,
181
                               int depth,
182
                               int x,
183
                               int y,
184
                               int32_t error,
185
                               int direction,
186
                               int channel);
187

188
static void diffuse_fs(unsigned char *data,
189
                       int width,
190
                       int height,
191
                       int x,
192
                       int y,
193
                       int depth,
194
                       int error,
195
                       int direction);
196

197
static void diffuse_fs_carry(int32_t *carry_curr,
198
                             int32_t *carry_next,
199
                             int32_t *carry_far,
200
                             int width,
201
                             int height,
202
                             int depth,
203
                             int x,
204
                             int y,
205
                             int32_t error,
206
                             int direction,
207
                             int channel);
208

209
static void diffuse_atkinson(unsigned char *data,
210
                             int width,
211
                             int height,
212
                             int x,
213
                             int y,
214
                             int depth,
215
                             int error,
216
                             int direction);
217

218
static void diffuse_atkinson_carry(int32_t *carry_curr,
219
                                   int32_t *carry_next,
220
                                   int32_t *carry_far,
221
                                   int width,
222
                                   int height,
223
                                   int depth,
224
                                   int x,
225
                                   int y,
226
                                   int32_t error,
227
                                   int direction,
228
                                   int channel);
229

230
static void diffuse_jajuni(unsigned char *data,
231
                           int width,
232
                           int height,
233
                           int x,
234
                           int y,
235
                           int depth,
236
                           int error,
237
                           int direction);
238

239
static void diffuse_jajuni_carry(int32_t *carry_curr,
240
                                 int32_t *carry_next,
241
                                 int32_t *carry_far,
242
                                 int width,
243
                                 int height,
244
                                 int depth,
245
                                 int x,
246
                                 int y,
247
                                 int32_t error,
248
                                 int direction,
249
                                 int channel);
250

251
static void diffuse_stucki(unsigned char *data,
252
                           int width,
253
                           int height,
254
                           int x,
255
                           int y,
256
                           int depth,
257
                           int error,
258
                           int direction);
259

260
static void diffuse_stucki_carry(int32_t *carry_curr,
261
                                 int32_t *carry_next,
262
                                 int32_t *carry_far,
263
                                 int width,
264
                                 int height,
265
                                 int depth,
266
                                 int x,
267
                                 int y,
268
                                 int32_t error,
269
                                 int direction,
270
                                 int channel);
271

272
static void diffuse_burkes(unsigned char *data,
273
                           int width,
274
                           int height,
275
                           int x,
276
                           int y,
277
                           int depth,
278
                           int error,
279
                           int direction);
280

281
static void diffuse_burkes_carry(int32_t *carry_curr,
282
                                 int32_t *carry_next,
283
                                 int32_t *carry_far,
284
                                 int width,
285
                                 int height,
286
                                 int depth,
287
                                 int x,
288
                                 int y,
289
                                 int32_t error,
290
                                 int direction,
291
                                 int channel);
292

293
static void diffuse_sierra1(unsigned char *data,
294
                            int width,
295
                            int height,
296
                            int x,
297
                            int y,
298
                            int depth,
299
                            int error,
300
                            int direction);
301

302
static void diffuse_sierra1_carry(int32_t *carry_curr,
303
                                  int32_t *carry_next,
304
                                  int32_t *carry_far,
305
                                  int width,
306
                                  int height,
307
                                  int depth,
308
                                  int x,
309
                                  int y,
310
                                  int32_t error,
311
                                  int direction,
312
                                  int channel);
313

314
static void diffuse_sierra2(unsigned char *data,
315
                            int width,
316
                            int height,
317
                            int x,
318
                            int y,
319
                            int depth,
320
                            int error,
321
                            int direction);
322

323
static void diffuse_sierra2_carry(int32_t *carry_curr,
324
                                  int32_t *carry_next,
325
                                  int32_t *carry_far,
326
                                  int width,
327
                                  int height,
328
                                  int depth,
329
                                  int x,
330
                                  int y,
331
                                  int32_t error,
332
                                  int direction,
333
                                  int channel);
334

335
static void diffuse_sierra3(unsigned char *data,
336
                            int width,
337
                            int height,
338
                            int x,
339
                            int y,
340
                            int depth,
341
                            int error,
342
                            int direction);
343

344
static void diffuse_sierra3_carry(int32_t *carry_curr,
345
                                  int32_t *carry_next,
346
                                  int32_t *carry_far,
347
                                  int width,
348
                                  int height,
349
                                  int depth,
350
                                  int x,
351
                                  int y,
352
                                  int32_t error,
353
                                  int direction,
354
                                  int channel);
355

356
static SIXELSTATUS
357
sixel_dither_apply_fixed_impl(
255✔
358
    sixel_index_t *result,
359
    unsigned char *data,
360
    int width,
361
    int height,
362
    int band_origin,
363
    int output_start,
364
    int depth,
365
    unsigned char *palette,
366
    int reqcolor,
367
    int method_for_scan,
368
    int optimize_palette,
369
    int (*f_lookup)(const unsigned char *pixel,
370
                    int depth,
371
                    const unsigned char *palette,
372
                    int reqcolor,
373
                    unsigned short *cachetable,
374
                    int complexion),
375
    sixel_lut_t *fast_lut,
376
    int use_fast_lut,
377
    unsigned short *indextable,
378
    int complexion,
379
    unsigned char new_palette[],
380
    unsigned short migration_map[],
381
    int *ncolors,
382
    int method_for_diffuse,
383
    int method_for_carry,
384
    float *palette_float,
385
    float *new_palette_float,
386
    int float_depth,
387
    sixel_dither_t *dither)
388
{
255✔
389
#if _MSC_VER
390
    enum { max_channels = 4 };
391
#else
392
    const int max_channels = 4;
255✔
393
#endif
394
    SIXELSTATUS status = SIXEL_FALSE;
255✔
395
    int serpentine;
255✔
396
    int y;
255✔
397
    void (*f_diffuse)(unsigned char *data,
255✔
398
                      int width,
399
                      int height,
400
                      int x,
401
                      int y,
402
                      int depth,
403
                      int offset,
404
                      int direction);
405
    diffuse_fixed_carry_mode f_diffuse_carry;
255✔
406
    int use_carry;
255✔
407
    size_t carry_len;
255✔
408
    int32_t *carry_curr = NULL;
255✔
409
    int32_t *carry_next = NULL;
255✔
410
    int32_t *carry_far = NULL;
255✔
411
    unsigned char corrected[max_channels];
255✔
412
    int32_t accum_scaled[max_channels];
255✔
413
    int start;
255✔
414
    int end;
255✔
415
    int step;
255✔
416
    int direction;
255✔
417
    int x;
255✔
418
    int absolute_y;
255✔
419
    int pos;
255✔
420
    size_t base;
255✔
421
    size_t carry_base;
255✔
422
    const unsigned char *source_pixel;
255✔
423
    int color_index;
255✔
424
    int output_index;
255✔
425
    int n;
255✔
426
    int palette_value;
255✔
427
    int64_t accum;
255✔
428
    int64_t clamped;
255✔
429
    int32_t target_scaled;
255✔
430
    int32_t error_scaled;
255✔
431
    int offset;
255✔
432
    int float_index;
255✔
433
    int32_t *tmp;
255✔
434

435
    if (depth > max_channels) {
255!
436
        status = SIXEL_BAD_ARGUMENT;
×
437
        goto end;
×
438
    }
439

440
    use_carry = (method_for_carry == SIXEL_CARRY_ENABLE);
255✔
441
    carry_len = 0;
255✔
442

443
    if (depth != 3) {
255!
444
        f_diffuse = diffuse_none;
445
        f_diffuse_carry = diffuse_none_carry;
446
        use_carry = 0;
447
    } else {
448
        switch (method_for_diffuse) {
255!
449
        case SIXEL_DIFFUSE_NONE:
450
            f_diffuse = diffuse_none;
451
            f_diffuse_carry = diffuse_none_carry;
452
            break;
453
        case SIXEL_DIFFUSE_ATKINSON:
54✔
454
            f_diffuse = diffuse_atkinson;
54✔
455
            f_diffuse_carry = diffuse_atkinson_carry;
54✔
456
            break;
54✔
457
        case SIXEL_DIFFUSE_FS:
42✔
458
            f_diffuse = diffuse_fs;
42✔
459
            f_diffuse_carry = diffuse_fs_carry;
42✔
460
            break;
42✔
461
        case SIXEL_DIFFUSE_JAJUNI:
3✔
462
            f_diffuse = diffuse_jajuni;
3✔
463
            f_diffuse_carry = diffuse_jajuni_carry;
3✔
464
            break;
3✔
465
        case SIXEL_DIFFUSE_STUCKI:
×
466
            f_diffuse = diffuse_stucki;
×
467
            f_diffuse_carry = diffuse_stucki_carry;
×
468
            break;
×
469
        case SIXEL_DIFFUSE_BURKES:
×
470
            f_diffuse = diffuse_burkes;
×
471
            f_diffuse_carry = diffuse_burkes_carry;
×
472
            break;
×
473
        case SIXEL_DIFFUSE_SIERRA1:
×
474
            f_diffuse = diffuse_sierra1;
×
475
            f_diffuse_carry = diffuse_sierra1_carry;
×
476
            break;
×
477
        case SIXEL_DIFFUSE_SIERRA2:
×
478
            f_diffuse = diffuse_sierra2;
×
479
            f_diffuse_carry = diffuse_sierra2_carry;
×
480
            break;
×
481
        case SIXEL_DIFFUSE_SIERRA3:
×
482
            f_diffuse = diffuse_sierra3;
×
483
            f_diffuse_carry = diffuse_sierra3_carry;
×
484
            break;
×
485
        default:
486
            f_diffuse = diffuse_none;
487
            f_diffuse_carry = diffuse_none_carry;
488
            break;
489
        }
490
    }
491

492
    if (use_carry) {
255!
493
        carry_len = (size_t)width * (size_t)depth;
×
494
        if (carry_len > 0) {
×
495
            carry_curr = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
496
            if (carry_curr == NULL) {
×
497
                status = SIXEL_BAD_ALLOCATION;
×
498
                goto end;
×
499
            }
500
            carry_next = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
501
            if (carry_next == NULL) {
×
502
                status = SIXEL_BAD_ALLOCATION;
×
503
                goto end;
×
504
            }
505
            carry_far = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
506
            if (carry_far == NULL) {
×
507
                status = SIXEL_BAD_ALLOCATION;
×
508
                goto end;
×
509
            }
510
        } else {
511
            use_carry = 0;
512
        }
513
    }
514

515
    serpentine = (method_for_scan == SIXEL_SCAN_SERPENTINE);
255✔
516

517
    if (optimize_palette) {
255✔
518
        *ncolors = 0;
195✔
519
        memset(new_palette, 0x00,
195✔
520
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
195!
521
        if (new_palette_float != NULL && float_depth > 0) {
195!
522
            memset(new_palette_float, 0x00,
×
523
                   (size_t)SIXEL_PALETTE_MAX
524
                       * (size_t)float_depth * sizeof(float));
×
525
        }
526
        memset(migration_map, 0x00,
195✔
527
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
528
    } else {
529
        *ncolors = reqcolor;
60✔
530
    }
531

532
    for (y = 0; y < height; ++y) {
49,605✔
533
        absolute_y = band_origin + y;
49,350✔
534
        sixel_dither_scanline_params(serpentine, absolute_y, width,
49,350✔
535
                        &start, &end, &step, &direction);
536
        for (x = start; x != end; x += step) {
35,047,980✔
537
            pos = y * width + x;
34,998,630✔
538
            base = (size_t)pos * (size_t)depth;
34,998,630✔
539
            carry_base = (size_t)x * (size_t)depth;
34,998,630✔
540
            if (use_carry) {
34,998,630!
541
                for (n = 0; n < depth; ++n) {
×
542
                    accum = ((int64_t)data[base + n]
×
543
                             << VARERR_SCALE_SHIFT)
×
544
                           + carry_curr[carry_base + (size_t)n];
×
545
                    if (accum < INT32_MIN) {
×
546
                        accum = INT32_MIN;
547
                    } else if (accum > INT32_MAX) {
×
548
                        accum = INT32_MAX;
549
                    }
550
                    clamped = accum;
×
551
                    if (clamped < 0) {
×
552
                        clamped = 0;
553
                    } else if (clamped > VARERR_MAX_VALUE) {
×
554
                        clamped = VARERR_MAX_VALUE;
555
                    }
556
                    accum_scaled[n] = (int32_t)clamped;
×
557
                    corrected[n]
×
558
                        = (unsigned char)((clamped + VARERR_ROUND)
×
559
                                          >> VARERR_SCALE_SHIFT);
×
560
                    data[base + n] = corrected[n];
×
561
                    carry_curr[carry_base + (size_t)n] = 0;
×
562
                }
563
                source_pixel = corrected;
564
            } else {
565
                source_pixel = data + base;
34,998,630✔
566
            }
567

568
            if (use_fast_lut && fast_lut != NULL) {
34,998,630!
569
                color_index = sixel_lut_map_pixel(fast_lut, source_pixel);
32,458,110✔
570
            } else {
571
                color_index = f_lookup(source_pixel, depth, palette,
2,540,520✔
572
                                       reqcolor, indextable,
573
                                       complexion);
574
            }
575

576
            if (optimize_palette) {
34,998,630✔
577
                if (migration_map[color_index] == 0) {
25,606,110✔
578
                    output_index = *ncolors;
11,784✔
579
                    for (n = 0; n < depth; ++n) {
47,136✔
580
                        new_palette[output_index * depth + n]
35,352✔
581
                            = palette[color_index * depth + n];
35,352✔
582
                    }
583
                    if (palette_float != NULL
11,784!
584
                            && new_palette_float != NULL
11,784!
585
                            && float_depth > 0) {
×
586
                        for (float_index = 0;
×
587
                                float_index < float_depth;
×
588
                                ++float_index) {
×
589
                            new_palette_float[output_index * float_depth
×
590
                                              + float_index]
×
591
                                = palette_float[color_index * float_depth
×
592
                                                + float_index];
×
593
                        }
594
                    }
595
                    ++*ncolors;
11,784✔
596
                    migration_map[color_index] = *ncolors;
11,784✔
597
                } else {
598
                    output_index = migration_map[color_index] - 1;
25,594,326✔
599
                }
600
                if (absolute_y >= output_start) {
25,606,110!
601
                    result[pos] = output_index;
25,606,110✔
602
                }
603
            } else {
604
                output_index = color_index;
9,392,520✔
605
                if (absolute_y >= output_start) {
9,392,520!
606
                    result[pos] = output_index;
9,392,520✔
607
                }
608
            }
609

610
            for (n = 0; n < depth; ++n) {
139,994,520✔
611
                if (optimize_palette) {
104,995,890✔
612
                    palette_value = new_palette[output_index * depth + n];
76,818,330✔
613
                } else {
614
                    palette_value = palette[color_index * depth + n];
28,177,560✔
615
                }
616
                if (use_carry) {
104,995,890!
617
                    target_scaled = (int32_t)palette_value
×
618
                                  << VARERR_SCALE_SHIFT;
619
                    error_scaled = accum_scaled[n] - target_scaled;
×
620
                    f_diffuse_carry(carry_curr, carry_next, carry_far,
×
621
                                    width, height, depth,
622
                                    x, y, error_scaled, direction, n);
623
                } else {
624
                    offset = (int)source_pixel[n] - palette_value;
104,995,890✔
625
                    f_diffuse(data + n, width, height, x, y,
104,995,890✔
626
                              depth, offset, direction);
627
                }
628
            }
629
        }
630
        if (use_carry) {
49,350!
631
            tmp = carry_curr;
×
632
            carry_curr = carry_next;
×
633
            carry_next = carry_far;
×
634
            carry_far = tmp;
×
635
            if (carry_len > 0) {
×
636
                memset(carry_far, 0x00, carry_len * sizeof(int32_t));
×
637
            }
638
        }
639
        if (absolute_y >= output_start) {
49,350!
640
            sixel_dither_pipeline_row_notify(dither, absolute_y);
49,350✔
641
        }
642
    }
643

644
    if (optimize_palette) {
255✔
645
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
195!
646
        if (palette_float != NULL
195!
647
                && new_palette_float != NULL
195!
648
                && float_depth > 0) {
×
649
            memcpy(palette_float,
×
650
                   new_palette_float,
651
                   (size_t)(*ncolors * float_depth) * sizeof(float));
×
652
        }
653
    }
654

655
    status = SIXEL_OK;
656

657
end:
255✔
658
    free(carry_far);
255✔
659
    free(carry_next);
255✔
660
    free(carry_curr);
255✔
661
    return status;
255✔
662
}
663

664
SIXELSTATUS
665
sixel_dither_apply_fixed_8bit(sixel_dither_t *dither,
255✔
666
                              sixel_dither_context_t *context)
667
{
668
    if (dither == NULL || context == NULL) {
255!
669
        return SIXEL_BAD_ARGUMENT;
670
    }
671
    if (context->pixels == NULL || context->palette == NULL) {
255!
672
        return SIXEL_BAD_ARGUMENT;
673
    }
674
    if (context->result == NULL || context->new_palette == NULL) {
255!
675
        return SIXEL_BAD_ARGUMENT;
676
    }
677
    if (context->migration_map == NULL || context->ncolors == NULL) {
255!
678
        return SIXEL_BAD_ARGUMENT;
679
    }
680
    if (context->lookup == NULL) {
255!
681
        return SIXEL_BAD_ARGUMENT;
682
    }
683

684
    return sixel_dither_apply_fixed_impl(context->result,
255✔
685
                                         context->pixels,
686
                                         context->width,
687
                                         context->height,
688
                                         context->band_origin,
689
                                         context->output_start,
690
                                         context->depth,
691
                                         context->palette,
692
                                         context->reqcolor,
693
                                         context->method_for_scan,
694
                                         context->optimize_palette,
695
                                         context->lookup,
696
                                         context->lut,
697
                                         context->lut != NULL,
255✔
698
                                         context->indextable,
699
                                         context->complexion,
700
                                         context->new_palette,
701
                                         context->migration_map,
702
                                         context->ncolors,
703
                                         context->method_for_diffuse,
704
                                         context->method_for_carry,
705
                                         context->palette_float,
706
                                         context->new_palette_float,
707
                                         context->float_depth,
708
                                         dither);
709
}
710

711
static void
712
diffuse_none(unsigned char *data, int width, int height,
9,289,818✔
713
             int x, int y, int depth, int error, int direction)
714
{
715
    /* unused */ (void) data;
9,289,818✔
716
    /* unused */ (void) width;
9,289,818✔
717
    /* unused */ (void) height;
9,289,818✔
718
    /* unused */ (void) x;
9,289,818✔
719
    /* unused */ (void) y;
9,289,818✔
720
    /* unused */ (void) depth;
9,289,818✔
721
    /* unused */ (void) error;
9,289,818✔
722
    /* unused */ (void) direction;
9,289,818✔
723
}
9,289,818✔
724

725

726
static void
727
diffuse_none_carry(int32_t *carry_curr, int32_t *carry_next,
×
728
                   int32_t *carry_far, int width, int height,
729
                   int depth, int x, int y, int32_t error,
730
                   int direction, int channel)
731
{
732
    /* unused */ (void) carry_curr;
×
733
    /* unused */ (void) carry_next;
×
734
    /* unused */ (void) carry_far;
×
735
    /* unused */ (void) width;
×
736
    /* unused */ (void) height;
×
737
    /* unused */ (void) depth;
×
738
    /* unused */ (void) x;
×
739
    /* unused */ (void) y;
×
740
    /* unused */ (void) error;
×
741
    /* unused */ (void) direction;
×
742
    /* unused */ (void) channel;
×
743
}
×
744

745
static void
746
diffuse_fs(unsigned char *data, int width, int height,
67,625,712✔
747
           int x, int y, int depth, int error, int direction)
748
{
749
    /* Floyd Steinberg Method
750
     *          curr    7/16
751
     *  3/16    5/16    1/16
752
     */
753
    int pos;
67,625,712✔
754
    int forward;
67,625,712✔
755

756
    pos = y * width + x;
67,625,712✔
757
    forward = direction >= 0;
67,625,712✔
758

759
    if (forward) {
67,625,712✔
760
        if (x < width - 1) {
66,410,712✔
761
            error_diffuse_normal(data, pos + 1, depth, error, 7, 16);
66,350,151✔
762
        }
763
        if (y < height - 1) {
66,410,712✔
764
            if (x > 0) {
66,324,024✔
765
                error_diffuse_normal(data,
66,263,580✔
766
                                     pos + width - 1,
66,263,580✔
767
                                     depth, error, 3, 16);
768
            }
769
            error_diffuse_normal(data,
66,324,024✔
770
                                 pos + width,
771
                                 depth, error, 5, 16);
772
            if (x < width - 1) {
66,324,024✔
773
                error_diffuse_normal(data,
66,263,580✔
774
                                     pos + width + 1,
775
                                     depth, error, 1, 16);
776
            }
777
        }
778
    } else {
779
        if (x > 0) {
1,215,000✔
780
            error_diffuse_normal(data, pos - 1, depth, error, 7, 16);
1,212,975✔
781
        }
782
        if (y < height - 1) {
1,215,000✔
783
            if (x < width - 1) {
1,209,600✔
784
                error_diffuse_normal(data,
1,207,584✔
785
                                     pos + width + 1,
1,207,584✔
786
                                     depth, error, 3, 16);
787
            }
788
            error_diffuse_normal(data,
1,209,600✔
789
                                 pos + width,
790
                                 depth, error, 5, 16);
791
            if (x > 0) {
1,209,600✔
792
                error_diffuse_normal(data,
1,207,584✔
793
                                     pos + width - 1,
794
                                     depth, error, 1, 16);
795
            }
796
        }
797
    }
798
}
67,625,712✔
799

800

801
static void
802
diffuse_fs_carry(int32_t *carry_curr, int32_t *carry_next,
×
803
                 int32_t *carry_far, int width, int height,
804
                 int depth, int x, int y, int32_t error,
805
                 int direction, int channel)
806
{
807
    /* Floyd Steinberg Method
808
     *          curr    7/16
809
     *  3/16    5/48    1/16
810
     */
811
    int forward;
×
812

813
    /* unused */ (void) carry_far;
×
814
    if (error == 0) {
×
815
        return;
816
    }
817

818
    forward = direction >= 0;
×
819
    if (forward) {
×
820
        if (x + 1 < width) {
×
821
            size_t base;
×
822
            int32_t term;
×
823

824
            base = ((size_t)(x + 1) * (size_t)depth)
×
825
                 + (size_t)channel;
×
826
            term = diffuse_fixed_term(error, 7, 16);
×
827
            carry_curr[base] += term;
×
828
        }
829
        if (y + 1 < height) {
×
830
            if (x > 0) {
×
831
                size_t base;
×
832
                int32_t term;
×
833

834
                base = ((size_t)(x - 1) * (size_t)depth)
×
835
                     + (size_t)channel;
×
836
                term = diffuse_fixed_term(error, 3, 16);
×
837
                carry_next[base] += term;
×
838
            }
839
            {
840
                size_t base;
×
841
                int32_t term;
×
842

843
                base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
844
                term = diffuse_fixed_term(error, 5, 16);
×
845
                carry_next[base] += term;
×
846
            }
847
            if (x + 1 < width) {
×
848
                size_t base;
×
849
                int32_t term;
×
850

851
                base = ((size_t)(x + 1) * (size_t)depth)
×
852
                     + (size_t)channel;
853
                term = diffuse_fixed_term(error, 1, 16);
×
854
                carry_next[base] += term;
×
855
            }
856
        }
857
    } else {
858
        if (x - 1 >= 0) {
×
859
            size_t base;
×
860
            int32_t term;
×
861

862
            base = ((size_t)(x - 1) * (size_t)depth)
×
863
                 + (size_t)channel;
×
864
            term = diffuse_fixed_term(error, 7, 16);
×
865
            carry_curr[base] += term;
×
866
        }
867
        if (y + 1 < height) {
×
868
            if (x + 1 < width) {
×
869
                size_t base;
×
870
                int32_t term;
×
871

872
                base = ((size_t)(x + 1) * (size_t)depth)
×
873
                     + (size_t)channel;
×
874
                term = diffuse_fixed_term(error, 3, 16);
×
875
                carry_next[base] += term;
×
876
            }
877
            {
878
                size_t base;
×
879
                int32_t term;
×
880

881
                base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
882
                term = diffuse_fixed_term(error, 5, 16);
×
883
                carry_next[base] += term;
×
884
            }
885
            if (x - 1 >= 0) {
×
886
                size_t base;
×
887
                int32_t term;
×
888

889
                base = ((size_t)(x - 1) * (size_t)depth)
×
890
                     + (size_t)channel;
891
                term = diffuse_fixed_term(error, 1, 16);
×
892
                carry_next[base] += term;
×
893
            }
894
        }
895
    }
896
}
×
897

898

899
static void
900
diffuse_atkinson(unsigned char *data, int width, int height,
27,683,460✔
901
                 int x, int y, int depth, int error, int direction)
902
{
903
    /* Atkinson's Method
904
     *          curr    1/8    1/8
905
     *   1/8     1/8    1/8
906
     *           1/8
907
     */
908
    int pos;
27,683,460✔
909
    int sign;
27,683,460✔
910

911
    pos = y * width + x;
27,683,460✔
912
    sign = direction >= 0 ? 1 : -1;
27,683,460!
913

914
    if (x + sign >= 0 && x + sign < width) {
27,683,460!
915
        error_diffuse_fast(data, pos + sign, depth, error, 1, 8);
27,632,295✔
916
    }
917
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
27,683,460!
918
        error_diffuse_fast(data, pos + sign * 2, depth, error, 1, 8);
27,581,130✔
919
    }
920
    if (y < height - 1) {
27,683,460✔
921
        int row;
27,615,546✔
922

923
        row = pos + width;
27,615,546✔
924
        if (x - sign >= 0 && x - sign < width) {
27,615,546!
925
            error_diffuse_fast(data,
27,564,543✔
926
                               row + (-sign),
927
                               depth, error, 1, 8);
928
        }
929
        error_diffuse_fast(data, row, depth, error, 1, 8);
27,615,546✔
930
        if (x + sign >= 0 && x + sign < width) {
27,615,546!
931
            error_diffuse_fast(data,
27,564,543✔
932
                               row + sign,
933
                               depth, error, 1, 8);
934
        }
935
    }
936
    if (y < height - 2) {
27,683,460✔
937
        error_diffuse_fast(data, pos + width * 2, depth, error, 1, 8);
27,547,632✔
938
    }
939
}
27,683,460✔
940

941

942
static void
943
diffuse_atkinson_carry(int32_t *carry_curr, int32_t *carry_next,
×
944
                       int32_t *carry_far, int width, int height,
945
                       int depth, int x, int y, int32_t error,
946
                       int direction, int channel)
947
{
948
    /* Atkinson's Method
949
     *          curr    1/8    1/8
950
     *   1/8     1/8    1/8
951
     *           1/8
952
     */
953
    int sign;
×
954
    int32_t term;
×
955

956
    if (error == 0) {
×
957
        return;
958
    }
959

960
    term = diffuse_fixed_term(error, 1, 8);
×
961
    sign = direction >= 0 ? 1 : -1;
×
962
    if (x + sign >= 0 && x + sign < width) {
×
963
        size_t base;
×
964

965
        base = ((size_t)(x + sign) * (size_t)depth)
×
966
             + (size_t)channel;
×
967
        carry_curr[base] += term;
×
968
    }
969
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
×
970
        size_t base;
×
971

972
        base = ((size_t)(x + sign * 2) * (size_t)depth)
×
973
             + (size_t)channel;
×
974
        carry_curr[base] += term;
×
975
    }
976
    if (y + 1 < height) {
×
977
        if (x - sign >= 0 && x - sign < width) {
×
978
            size_t base;
×
979

980
            base = ((size_t)(x - sign) * (size_t)depth)
×
981
                 + (size_t)channel;
×
982
            carry_next[base] += term;
×
983
        }
984
        {
985
            size_t base;
×
986

987
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
988
            carry_next[base] += term;
×
989
        }
990
        if (x + sign >= 0 && x + sign < width) {
×
991
            size_t base;
×
992

993
            base = ((size_t)(x + sign) * (size_t)depth)
×
994
                 + (size_t)channel;
995
            carry_next[base] += term;
×
996
        }
997
    }
998
    if (y + 2 < height) {
×
999
        size_t base;
×
1000

1001
        base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
1002
        carry_far[base] += term;
×
1003
    }
1004
}
×
1005

1006

1007
static void
1008
diffuse_jajuni(unsigned char *data, int width, int height,
396,900✔
1009
               int x, int y, int depth, int error, int direction)
1010
{
1011
    /* Jarvis, Judice & Ninke Method
1012
     *                  curr    7/48    5/48
1013
     *  3/48    5/48    7/48    5/48    3/48
1014
     *  1/48    3/48    5/48    3/48    1/48
1015
     */
1016
    int pos;
396,900✔
1017
    int sign;
396,900✔
1018
    static const int row0_offsets[] = { 1, 2 };
396,900✔
1019
    static const int row0_weights[] = { 7, 5 };
396,900✔
1020
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
396,900✔
1021
    static const int row1_weights[] = { 3, 5, 7, 5, 3 };
396,900✔
1022
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
396,900✔
1023
    static const int row2_weights[] = { 1, 3, 5, 3, 1 };
396,900✔
1024
    int i;
396,900✔
1025

1026
    pos = y * width + x;
396,900✔
1027
    sign = direction >= 0 ? 1 : -1;
396,900!
1028

1029
    for (i = 0; i < 2; ++i) {
1,190,700✔
1030
        int neighbor;
793,800✔
1031

1032
        neighbor = x + sign * row0_offsets[i];
793,800✔
1033
        if (neighbor < 0 || neighbor >= width) {
793,800!
1034
            continue;
5,670✔
1035
        }
1036
        error_diffuse_precise(data,
788,130✔
1037
                              pos + (neighbor - x),
1038
                              depth, error,
1039
                              row0_weights[i], 48);
788,130✔
1040
    }
2✔
1041
    if (y < height - 1) {
396,900✔
1042
        int row;
395,010✔
1043

1044
        row = pos + width;
395,010✔
1045
        for (i = 0; i < 5; ++i) {
2,370,060✔
1046
            int neighbor;
1,975,050✔
1047

1048
            neighbor = x + sign * row1_offsets[i];
1,975,050✔
1049
            if (neighbor < 0 || neighbor >= width) {
1,975,050✔
1050
                continue;
11,286✔
1051
            }
1052
            error_diffuse_precise(data,
1,963,764✔
1053
                                  row + (neighbor - x),
1054
                                  depth, error,
1055
                                  row1_weights[i], 48);
1,963,764✔
1056
        }
2✔
1057
    }
1058
    if (y < height - 2) {
396,900✔
1059
        int row;
393,120✔
1060

1061
        row = pos + width * 2;
393,120✔
1062
        for (i = 0; i < 5; ++i) {
2,358,720✔
1063
            int neighbor;
1,965,600✔
1064

1065
            neighbor = x + sign * row2_offsets[i];
1,965,600✔
1066
            if (neighbor < 0 || neighbor >= width) {
1,965,600✔
1067
                continue;
11,232✔
1068
            }
1069
            error_diffuse_precise(data,
1,954,368✔
1070
                                  row + (neighbor - x),
1071
                                  depth, error,
1072
                                  row2_weights[i], 48);
1,954,368✔
1073
        }
2✔
1074
    }
1075
}
396,900✔
1076

1077

1078
static void
1079
diffuse_jajuni_carry(int32_t *carry_curr, int32_t *carry_next,
×
1080
                     int32_t *carry_far, int width, int height,
1081
                     int depth, int x, int y, int32_t error,
1082
                     int direction, int channel)
1083
{
1084
    /* Jarvis, Judice & Ninke Method
1085
     *                  curr    7/48    5/48
1086
     *  3/48    5/48    7/48    5/48    3/48
1087
     *  1/48    3/48    5/48    3/48    1/48
1088
     */
1089
    static const int row0_offsets[] = { 1, 2 };
×
1090
    static const int row0_weights[] = { 7, 5 };
×
1091
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1092
    static const int row1_weights[] = { 3, 5, 7, 5, 3 };
×
1093
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
×
1094
    static const int row2_weights[] = { 1, 3, 5, 3, 1 };
×
1095
    int sign;
×
1096
    int i;
×
1097

1098
    if (error == 0) {
×
1099
        return;
1100
    }
1101

1102
    sign = direction >= 0 ? 1 : -1;
×
1103
    for (i = 0; i < 2; ++i) {
×
1104
        int neighbor;
×
1105
        int32_t term;
×
1106

1107
        neighbor = x + sign * row0_offsets[i];
×
1108
        if (neighbor < 0 || neighbor >= width) {
×
1109
            continue;
×
1110
        }
1111
        term = diffuse_fixed_term(error, row0_weights[i], 48);
×
1112
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1113
                   + (size_t)channel] += term;
×
1114
    }
×
1115
    if (y + 1 < height) {
×
1116
        for (i = 0; i < 5; ++i) {
×
1117
            int neighbor;
×
1118
            int32_t term;
×
1119

1120
            neighbor = x + sign * row1_offsets[i];
×
1121
            if (neighbor < 0 || neighbor >= width) {
×
1122
                continue;
×
1123
            }
1124
            term = diffuse_fixed_term(error, row1_weights[i], 48);
×
1125
            carry_next[((size_t)neighbor * (size_t)depth)
×
1126
                       + (size_t)channel] += term;
×
1127
        }
×
1128
    }
1129
    if (y + 2 < height) {
×
1130
        for (i = 0; i < 5; ++i) {
×
1131
            int neighbor;
×
1132
            int32_t term;
×
1133

1134
            neighbor = x + sign * row2_offsets[i];
×
1135
            if (neighbor < 0 || neighbor >= width) {
×
1136
                continue;
×
1137
            }
1138
            term = diffuse_fixed_term(error, row2_weights[i], 48);
×
1139
            carry_far[((size_t)neighbor * (size_t)depth)
×
1140
                      + (size_t)channel] += term;
×
1141
        }
×
1142
    }
1143
}
1144

1145

1146
static void
1147
diffuse_stucki(unsigned char *data, int width, int height,
×
1148
               int x, int y, int depth, int error, int direction)
1149
{
1150
    /* Stucki's Method
1151
     *                  curr    8/48    4/48
1152
     *  2/48    4/48    8/48    4/48    2/48
1153
     *  1/48    2/48    4/48    2/48    1/48
1154
     */
1155
    int pos;
×
1156
    int sign;
×
1157
    static const int row0_offsets[] = { 1, 2 };
×
1158
    static const int row0_num[] = { 1, 1 };
×
1159
    static const int row0_den[] = { 6, 12 };
×
1160
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1161
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
×
1162
    static const int row1_den[] = { 24, 12, 6, 12, 24 };
×
1163
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
×
1164
    static const int row2_num[] = { 1, 1, 1, 1, 1 };
×
1165
    static const int row2_den[] = { 48, 24, 12, 24, 48 };
×
1166
    int i;
×
1167

1168
    pos = y * width + x;
×
1169
    sign = direction >= 0 ? 1 : -1;
×
1170

1171
    for (i = 0; i < 2; ++i) {
×
1172
        int neighbor;
×
1173

1174
        neighbor = x + sign * row0_offsets[i];
×
1175
        if (neighbor < 0 || neighbor >= width) {
×
1176
            continue;
×
1177
        }
1178
        error_diffuse_precise(data,
×
1179
                              pos + (neighbor - x),
1180
                              depth, error,
1181
                              row0_num[i], row0_den[i]);
×
1182
    }
2✔
1183
    if (y < height - 1) {
×
1184
        int row;
×
1185

1186
        row = pos + width;
×
1187
        for (i = 0; i < 5; ++i) {
×
1188
            int neighbor;
×
1189

1190
            neighbor = x + sign * row1_offsets[i];
×
1191
            if (neighbor < 0 || neighbor >= width) {
×
1192
                continue;
×
1193
            }
1194
            error_diffuse_precise(data,
×
1195
                                  row + (neighbor - x),
1196
                                  depth, error,
1197
                                  row1_num[i], row1_den[i]);
×
1198
        }
2✔
1199
    }
1200
    if (y < height - 2) {
×
1201
        int row;
×
1202

1203
        row = pos + width * 2;
×
1204
        for (i = 0; i < 5; ++i) {
×
1205
            int neighbor;
×
1206

1207
            neighbor = x + sign * row2_offsets[i];
×
1208
            if (neighbor < 0 || neighbor >= width) {
×
1209
                continue;
×
1210
            }
1211
            error_diffuse_precise(data,
×
1212
                                  row + (neighbor - x),
1213
                                  depth, error,
1214
                                  row2_num[i], row2_den[i]);
×
1215
        }
2✔
1216
    }
1217
}
×
1218

1219

1220
static void
1221
diffuse_stucki_carry(int32_t *carry_curr, int32_t *carry_next,
×
1222
                     int32_t *carry_far, int width, int height,
1223
                     int depth, int x, int y, int32_t error,
1224
                     int direction, int channel)
1225
{
1226
    /* Stucki's Method
1227
     *                  curr    8/48    4/48
1228
     *  2/48    4/48    8/48    4/48    2/48
1229
     *  1/48    2/48    4/48    2/48    1/48
1230
     */
1231
    static const int row0_offsets[] = { 1, 2 };
×
1232
    static const int row0_num[] = { 1, 1 };
×
1233
    static const int row0_den[] = { 6, 12 };
×
1234
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1235
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
×
1236
    static const int row1_den[] = { 24, 12, 6, 12, 24 };
×
1237
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
×
1238
    static const int row2_num[] = { 1, 1, 1, 1, 1 };
×
1239
    static const int row2_den[] = { 48, 24, 12, 24, 48 };
×
1240
    int sign;
×
1241
    int i;
×
1242

1243
    if (error == 0) {
×
1244
        return;
1245
    }
1246

1247
    sign = direction >= 0 ? 1 : -1;
×
1248
    for (i = 0; i < 2; ++i) {
×
1249
        int neighbor;
×
1250
        int32_t term;
×
1251

1252
        neighbor = x + sign * row0_offsets[i];
×
1253
        if (neighbor < 0 || neighbor >= width) {
×
1254
            continue;
×
1255
        }
1256
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1257
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1258
                   + (size_t)channel] += term;
×
1259
    }
×
1260
    if (y + 1 < height) {
×
1261
        for (i = 0; i < 5; ++i) {
×
1262
            int neighbor;
×
1263
            int32_t term;
×
1264

1265
            neighbor = x + sign * row1_offsets[i];
×
1266
            if (neighbor < 0 || neighbor >= width) {
×
1267
                continue;
×
1268
            }
1269
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1270
            carry_next[((size_t)neighbor * (size_t)depth)
×
1271
                       + (size_t)channel] += term;
×
1272
        }
×
1273
    }
1274
    if (y + 2 < height) {
×
1275
        for (i = 0; i < 5; ++i) {
×
1276
            int neighbor;
×
1277
            int32_t term;
×
1278

1279
            neighbor = x + sign * row2_offsets[i];
×
1280
            if (neighbor < 0 || neighbor >= width) {
×
1281
                continue;
×
1282
            }
1283
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
1284
            carry_far[((size_t)neighbor * (size_t)depth)
×
1285
                      + (size_t)channel] += term;
×
1286
        }
×
1287
    }
1288
}
1289

1290

1291
static void
1292
diffuse_burkes(unsigned char *data, int width, int height,
×
1293
               int x, int y, int depth, int error, int direction)
1294
{
1295
    /* Burkes' Method
1296
     *                  curr    4/16    2/16
1297
     *  1/16    2/16    4/16    2/16    1/16
1298
     */
1299
    int pos;
×
1300
    int sign;
×
1301
    static const int row0_offsets[] = { 1, 2 };
×
1302
    static const int row0_num[] = { 1, 1 };
×
1303
    static const int row0_den[] = { 4, 8 };
×
1304
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1305
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
×
1306
    static const int row1_den[] = { 16, 8, 4, 8, 16 };
×
1307
    int i;
×
1308

1309
    pos = y * width + x;
×
1310
    sign = direction >= 0 ? 1 : -1;
×
1311

1312
    for (i = 0; i < 2; ++i) {
×
1313
        int neighbor;
×
1314

1315
        neighbor = x + sign * row0_offsets[i];
×
1316
        if (neighbor < 0 || neighbor >= width) {
×
1317
            continue;
×
1318
        }
1319
        error_diffuse_normal(data,
×
1320
                             pos + (neighbor - x),
1321
                             depth, error,
1322
                             row0_num[i], row0_den[i]);
×
1323
    }
2✔
1324
    if (y < height - 1) {
×
1325
        int row;
×
1326

1327
        row = pos + width;
×
1328
        for (i = 0; i < 5; ++i) {
×
1329
            int neighbor;
×
1330

1331
            neighbor = x + sign * row1_offsets[i];
×
1332
            if (neighbor < 0 || neighbor >= width) {
×
1333
                continue;
×
1334
            }
1335
            error_diffuse_normal(data,
×
1336
                                 row + (neighbor - x),
1337
                                 depth, error,
1338
                                 row1_num[i], row1_den[i]);
×
1339
        }
2✔
1340
    }
1341
}
×
1342

1343
static void
1344
diffuse_burkes_carry(int32_t *carry_curr, int32_t *carry_next,
×
1345
                     int32_t *carry_far, int width, int height,
1346
                     int depth, int x, int y, int32_t error,
1347
                     int direction, int channel)
1348
{
1349
    /* Burkes' Method
1350
     *                  curr    4/16    2/16
1351
     *  1/16    2/16    4/16    2/16    1/16
1352
     */
1353
    static const int row0_offsets[] = { 1, 2 };
×
1354
    static const int row0_num[] = { 1, 1 };
×
1355
    static const int row0_den[] = { 4, 8 };
×
1356
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1357
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
×
1358
    static const int row1_den[] = { 16, 8, 4, 8, 16 };
×
1359
    int sign;
×
1360
    int i;
×
1361

1362
    /* unused */ (void) carry_far;
×
1363

1364
    if (error == 0) {
×
1365
        return;
1366
    }
1367

1368
    sign = direction >= 0 ? 1 : -1;
×
1369
    for (i = 0; i < 2; ++i) {
×
1370
        int neighbor;
×
1371
        int32_t term;
×
1372

1373
        neighbor = x + sign * row0_offsets[i];
×
1374
        if (neighbor < 0 || neighbor >= width) {
×
1375
            continue;
×
1376
        }
1377
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1378
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1379
                   + (size_t)channel] += term;
×
1380
    }
×
1381
    if (y + 1 < height) {
×
1382
        for (i = 0; i < 5; ++i) {
×
1383
            int neighbor;
×
1384
            int32_t term;
×
1385

1386
            neighbor = x + sign * row1_offsets[i];
×
1387
            if (neighbor < 0 || neighbor >= width) {
×
1388
                continue;
×
1389
            }
1390
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1391
            carry_next[((size_t)neighbor * (size_t)depth)
×
1392
                       + (size_t)channel] += term;
×
1393
        }
×
1394
    }
1395
}
1396

1397
static void
1398
diffuse_sierra1(unsigned char *data, int width, int height,
×
1399
                int x, int y, int depth, int error, int direction)
1400
{
1401
    /* Sierra Lite Method
1402
     *          curr    2/4
1403
     *  1/4     1/4
1404
     */
1405
    static const int row0_offsets[] = { 1 };
×
1406
    static const int row0_num[] = { 1 };
×
1407
    static const int row0_den[] = { 2 };
×
1408
    static const int row1_offsets[] = { -1, 0 };
×
1409
    static const int row1_num[] = { 1, 1 };
×
1410
    static const int row1_den[] = { 4, 4 };
×
1411
    int pos;
×
1412
    int sign;
×
1413
    int i;
×
1414
    int neighbor;
×
1415
    int row;
×
1416

1417
    pos = y * width + x;
×
1418
    sign = direction >= 0 ? 1 : -1;
×
1419

1420
    for (i = 0; i < 1; ++i) {
×
1421
        neighbor = x + sign * row0_offsets[i];
×
1422
        if (neighbor < 0 || neighbor >= width) {
×
1423
            continue;
×
1424
        }
1425
        error_diffuse_normal(data,
×
1426
                             pos + (neighbor - x),
1427
                             depth, error,
1428
                             row0_num[i], row0_den[i]);
1429
    }
1430
    if (y < height - 1) {
×
1431
        row = pos + width;
×
1432
        for (i = 0; i < 2; ++i) {
×
1433
            neighbor = x + sign * row1_offsets[i];
×
1434
            if (neighbor < 0 || neighbor >= width) {
×
1435
                continue;
×
1436
            }
1437
            error_diffuse_normal(data,
×
1438
                                 row + (neighbor - x),
1439
                                 depth, error,
1440
                                 row1_num[i], row1_den[i]);
×
1441
        }
1442
    }
1443
}
×
1444

1445

1446
static void
1447
diffuse_sierra1_carry(int32_t *carry_curr, int32_t *carry_next,
×
1448
                      int32_t *carry_far, int width, int height,
1449
                      int depth, int x, int y, int32_t error,
1450
                      int direction, int channel)
1451
{
1452
    /* Sierra Lite Method
1453
     *          curr    2/4
1454
     *  1/4     1/4
1455
     */
1456
    static const int row0_offsets[] = { 1 };
×
1457
    static const int row0_num[] = { 1 };
×
1458
    static const int row0_den[] = { 2 };
×
1459
    static const int row1_offsets[] = { -1, 0 };
×
1460
    static const int row1_num[] = { 1, 1 };
×
1461
    static const int row1_den[] = { 4, 4 };
×
1462
    int sign;
×
1463
    int i;
×
1464
    int neighbor;
×
1465
    int32_t term;
×
1466

1467
    /* unused */ (void) carry_far;
×
1468

1469
    if (error == 0) {
×
1470
        return;
1471
    }
1472

1473
    sign = direction >= 0 ? 1 : -1;
×
1474
    for (i = 0; i < 1; ++i) {
×
1475
        neighbor = x + sign * row0_offsets[i];
×
1476
        if (neighbor < 0 || neighbor >= width) {
×
1477
            continue;
×
1478
        }
1479
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1480
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1481
                   + (size_t)channel] += term;
×
1482
    }
1483
    if (y + 1 < height) {
×
1484
        for (i = 0; i < 2; ++i) {
×
1485
            neighbor = x + sign * row1_offsets[i];
×
1486
            if (neighbor < 0 || neighbor >= width) {
×
1487
                continue;
×
1488
            }
1489
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1490
            carry_next[((size_t)neighbor * (size_t)depth)
×
1491
                       + (size_t)channel] += term;
×
1492
        }
1493
    }
1494
}
×
1495

1496

1497
static void
1498
diffuse_sierra2(unsigned char *data, int width, int height,
×
1499
                int x, int y, int depth, int error, int direction)
1500
{
1501
    /* Sierra Two-row Method
1502
     *                  curr    4/32    3/32
1503
     *  1/32    2/32    3/32    2/32    1/32
1504
     *                  2/32    3/32    2/32
1505
     */
1506
    static const int row0_offsets[] = { 1, 2 };
×
1507
    static const int row0_num[] = { 4, 3 };
×
1508
    static const int row0_den[] = { 32, 32 };
×
1509
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1510
    static const int row1_num[] = { 1, 2, 3, 2, 1 };
×
1511
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
×
1512
    static const int row2_offsets[] = { -1, 0, 1 };
×
1513
    static const int row2_num[] = { 2, 3, 2 };
×
1514
    static const int row2_den[] = { 32, 32, 32 };
×
1515
    int pos;
×
1516
    int sign;
×
1517
    int i;
×
1518
    int neighbor;
×
1519
    int row;
×
1520

1521
    pos = y * width + x;
×
1522
    sign = direction >= 0 ? 1 : -1;
×
1523

1524
    for (i = 0; i < 2; ++i) {
×
1525
        neighbor = x + sign * row0_offsets[i];
×
1526
        if (neighbor < 0 || neighbor >= width) {
×
1527
            continue;
×
1528
        }
1529
        error_diffuse_precise(data,
×
1530
                              pos + (neighbor - x),
1531
                              depth, error,
1532
                              row0_num[i], row0_den[i]);
×
1533
    }
1534
    if (y < height - 1) {
×
1535
        row = pos + width;
×
1536
        for (i = 0; i < 5; ++i) {
×
1537
            neighbor = x + sign * row1_offsets[i];
×
1538
            if (neighbor < 0 || neighbor >= width) {
×
1539
                continue;
×
1540
            }
1541
            error_diffuse_precise(data,
×
1542
                                  row + (neighbor - x),
1543
                                  depth, error,
1544
                                  row1_num[i], row1_den[i]);
×
1545
        }
1546
    }
1547
    if (y < height - 2) {
×
1548
        row = pos + width * 2;
×
1549
        for (i = 0; i < 3; ++i) {
×
1550
            neighbor = x + sign * row2_offsets[i];
×
1551
            if (neighbor < 0 || neighbor >= width) {
×
1552
                continue;
×
1553
            }
1554
            error_diffuse_precise(data,
×
1555
                                  row + (neighbor - x),
1556
                                  depth, error,
1557
                                  row2_num[i], row2_den[i]);
×
1558
        }
1559
    }
1560
}
×
1561

1562

1563
static void
1564
diffuse_sierra2_carry(int32_t *carry_curr, int32_t *carry_next,
×
1565
                      int32_t *carry_far, int width, int height,
1566
                      int depth, int x, int y, int32_t error,
1567
                      int direction, int channel)
1568
{
1569
    /* Sierra Two-row Method
1570
     *                  curr    4/32    3/32
1571
     *  1/32    2/32    3/32    2/32    1/32
1572
     *                  2/32    3/32    2/32
1573
     */
1574
    static const int row0_offsets[] = { 1, 2 };
×
1575
    static const int row0_num[] = { 4, 3 };
×
1576
    static const int row0_den[] = { 32, 32 };
×
1577
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1578
    static const int row1_num[] = { 1, 2, 3, 2, 1 };
×
1579
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
×
1580
    static const int row2_offsets[] = { -1, 0, 1 };
×
1581
    static const int row2_num[] = { 2, 3, 2 };
×
1582
    static const int row2_den[] = { 32, 32, 32 };
×
1583
    int sign;
×
1584
    int i;
×
1585
    int neighbor;
×
1586
    int32_t term;
×
1587

1588
    if (error == 0) {
×
1589
        return;
1590
    }
1591

1592
    sign = direction >= 0 ? 1 : -1;
×
1593
    for (i = 0; i < 2; ++i) {
×
1594
        neighbor = x + sign * row0_offsets[i];
×
1595
        if (neighbor < 0 || neighbor >= width) {
×
1596
            continue;
×
1597
        }
1598
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1599
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1600
                   + (size_t)channel] += term;
×
1601
    }
1602
    if (y + 1 < height) {
×
1603
        for (i = 0; i < 5; ++i) {
×
1604
            neighbor = x + sign * row1_offsets[i];
×
1605
            if (neighbor < 0 || neighbor >= width) {
×
1606
                continue;
×
1607
            }
1608
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1609
            carry_next[((size_t)neighbor * (size_t)depth)
×
1610
                       + (size_t)channel] += term;
×
1611
        }
1612
    }
1613
    if (y + 2 < height) {
×
1614
        for (i = 0; i < 3; ++i) {
×
1615
            neighbor = x + sign * row2_offsets[i];
×
1616
            if (neighbor < 0 || neighbor >= width) {
×
1617
                continue;
×
1618
            }
1619
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
1620
            carry_far[((size_t)neighbor * (size_t)depth)
×
1621
                      + (size_t)channel] += term;
×
1622
        }
1623
    }
1624
}
×
1625

1626

1627
static void
1628
diffuse_sierra3(unsigned char *data, int width, int height,
×
1629
                int x, int y, int depth, int error, int direction)
1630
{
1631
    /* Sierra-3 Method
1632
     *                  curr    5/32    3/32
1633
     *  2/32    4/32    5/32    4/32    2/32
1634
     *                  2/32    3/32    2/32
1635
     */
1636
    static const int row0_offsets[] = { 1, 2 };
×
1637
    static const int row0_num[] = { 5, 3 };
×
1638
    static const int row0_den[] = { 32, 32 };
×
1639
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1640
    static const int row1_num[] = { 2, 4, 5, 4, 2 };
×
1641
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
×
1642
    static const int row2_offsets[] = { -1, 0, 1 };
×
1643
    static const int row2_num[] = { 2, 3, 2 };
×
1644
    static const int row2_den[] = { 32, 32, 32 };
×
1645
    int pos;
×
1646
    int sign;
×
1647
    int i;
×
1648
    int neighbor;
×
1649
    int row;
×
1650

1651
    pos = y * width + x;
×
1652
    sign = direction >= 0 ? 1 : -1;
×
1653

1654
    for (i = 0; i < 2; ++i) {
×
1655
        neighbor = x + sign * row0_offsets[i];
×
1656
        if (neighbor < 0 || neighbor >= width) {
×
1657
            continue;
×
1658
        }
1659
        error_diffuse_precise(data,
×
1660
                              pos + (neighbor - x),
1661
                              depth, error,
1662
                              row0_num[i], row0_den[i]);
×
1663
    }
1664
    if (y < height - 1) {
×
1665
        row = pos + width;
×
1666
        for (i = 0; i < 5; ++i) {
×
1667
            neighbor = x + sign * row1_offsets[i];
×
1668
            if (neighbor < 0 || neighbor >= width) {
×
1669
                continue;
×
1670
            }
1671
            error_diffuse_precise(data,
×
1672
                                  row + (neighbor - x),
1673
                                  depth, error,
1674
                                  row1_num[i], row1_den[i]);
×
1675
        }
1676
    }
1677
    if (y < height - 2) {
×
1678
        row = pos + width * 2;
×
1679
        for (i = 0; i < 3; ++i) {
×
1680
            neighbor = x + sign * row2_offsets[i];
×
1681
            if (neighbor < 0 || neighbor >= width) {
×
1682
                continue;
×
1683
            }
1684
            error_diffuse_precise(data,
×
1685
                                  row + (neighbor - x),
1686
                                  depth, error,
1687
                                  row2_num[i], row2_den[i]);
×
1688
        }
1689
    }
1690
}
×
1691

1692

1693
static void
1694
diffuse_sierra3_carry(int32_t *carry_curr, int32_t *carry_next,
×
1695
                      int32_t *carry_far, int width, int height,
1696
                      int depth, int x, int y, int32_t error,
1697
                      int direction, int channel)
1698
{
1699
    /* Sierra-3 Method
1700
     *                  curr    5/32    3/32
1701
     *  2/32    4/32    5/32    4/32    2/32
1702
     *                  2/32    3/32    2/32
1703
     */
1704
    static const int row0_offsets[] = { 1, 2 };
×
1705
    static const int row0_num[] = { 5, 3 };
×
1706
    static const int row0_den[] = { 32, 32 };
×
1707
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
×
1708
    static const int row1_num[] = { 2, 4, 5, 4, 2 };
×
1709
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
×
1710
    static const int row2_offsets[] = { -1, 0, 1 };
×
1711
    static const int row2_num[] = { 2, 3, 2 };
×
1712
    static const int row2_den[] = { 32, 32, 32 };
×
1713
    int sign;
×
1714
    int i;
×
1715
    int neighbor;
×
1716
    int32_t term;
×
1717

1718
    if (error == 0) {
×
1719
        return;
1720
    }
1721

1722
    sign = direction >= 0 ? 1 : -1;
×
1723
    for (i = 0; i < 2; ++i) {
×
1724
        neighbor = x + sign * row0_offsets[i];
×
1725
        if (neighbor < 0 || neighbor >= width) {
×
1726
            continue;
×
1727
        }
1728
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1729
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1730
                   + (size_t)channel] += term;
×
1731
    }
1732
    if (y + 1 < height) {
×
1733
        for (i = 0; i < 5; ++i) {
×
1734
            neighbor = x + sign * row1_offsets[i];
×
1735
            if (neighbor < 0 || neighbor >= width) {
×
1736
                continue;
×
1737
            }
1738
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1739
            carry_next[((size_t)neighbor * (size_t)depth)
×
1740
                       + (size_t)channel] += term;
×
1741
        }
1742
    }
1743
    if (y + 2 < height) {
×
1744
        for (i = 0; i < 3; ++i) {
×
1745
            neighbor = x + sign * row2_offsets[i];
×
1746
            if (neighbor < 0 || neighbor >= width) {
×
1747
                continue;
×
1748
            }
1749
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
1750
            carry_far[((size_t)neighbor * (size_t)depth)
×
1751
                      + (size_t)channel] += term;
×
1752
        }
1753
    }
1754
}
×
1755

1756
/* emacs Local Variables:      */
1757
/* emacs mode: c               */
1758
/* emacs tab-width: 4          */
1759
/* emacs indent-tabs-mode: nil */
1760
/* emacs c-basic-offset: 4     */
1761
/* emacs End:                  */
1762
/* vim: set expandtab ts=4 sts=4 sw=4 : */
1763
/* EOF */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc