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

saitoha / libsixel / 19391318627

15 Nov 2025 02:27PM UTC coverage: 43.106% (-0.8%) from 43.89%
19391318627

push

github

saitoha
build: fix aborttrace helper guards for unused function warnings

8488 of 27890 branches covered (30.43%)

11529 of 26746 relevant lines covered (43.11%)

863769.02 hits per line

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

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

23
#include "config.h"
24

25
#include <stdlib.h>
26
#include <string.h>
27
#include <stdint.h>
28
#include <limits.h>
29

30
#include "dither-diffusion-fixed.h"
31
#include "dither-common-pipeline.h"
32

33
/*
34
 * Local serpentine traversal helper.  The function mirrors the behaviour used
35
 * by other dithering strategies without forcing additional shared headers.
36
 */
37
static void
38
sixel_dither_scanline_params(int serpentine,
32,900✔
39
                             int index,
40
                             int limit,
41
                             int *start,
42
                             int *end,
43
                             int *step,
44
                             int *direction)
45
{
46
    if (serpentine && (index & 1)) {
32,900✔
47
        *start = limit - 1;
450✔
48
        *end = -1;
450✔
49
        *step = -1;
450✔
50
        *direction = -1;
450✔
51
    } else {
52
        *start = 0;
32,450✔
53
        *end = limit;
32,450✔
54
        *step = 1;
32,450✔
55
        *direction = 1;
32,450✔
56
    }
57
}
32,900✔
58

59
#define VARERR_SCALE_SHIFT 12
60
#define VARERR_SCALE       (1 << VARERR_SCALE_SHIFT)
61
#define VARERR_ROUND       (1 << (VARERR_SCALE_SHIFT - 1))
62
#define VARERR_MAX_VALUE   (255 * VARERR_SCALE)
63

64
static void
65
error_diffuse_normal(
187,778,514✔
66
    unsigned char /* in */    *data,      /* base address of pixel buffer */
67
    int           /* in */    pos,        /* address of the destination pixel */
68
    int           /* in */    depth,      /* color depth in bytes */
69
    int           /* in */    error,      /* error energy */
70
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
71
    int           /* in */    denominator /* denominator of diffusion coefficient */)
72
{
73
    int c;
74

75
    data += pos * depth;
187,778,514✔
76

77
    c = *data + (error * numerator * 2 / denominator + 1) / 2;
187,778,514✔
78
    if (c < 0) {
187,778,514✔
79
        c = 0;
1,769,626✔
80
    }
81
    if (c >= 1 << 8) {
187,778,514✔
82
        c = (1 << 8) - 1;
998,288✔
83
    }
84
    *data = (unsigned char)c;
187,778,514✔
85
}
187,778,514✔
86

87
static void
88
error_diffuse_fast(
112,822,104✔
89
    unsigned char /* in */    *data,      /* base address of pixel buffer */
90
    int           /* in */    pos,        /* address of the destination pixel */
91
    int           /* in */    depth,      /* color depth in bytes */
92
    int           /* in */    error,      /* error energy */
93
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
94
    int           /* in */    denominator /* denominator of diffusion coefficient */)
95
{
96
    int c;
97

98
    data += pos * depth;
112,822,104✔
99

100
    c = *data + error * numerator / denominator;
112,822,104✔
101
    if (c < 0) {
112,822,104✔
102
        c = 0;
4,662,586✔
103
    }
104
    if (c >= 1 << 8) {
112,822,104✔
105
        c = (1 << 8) - 1;
306,688✔
106
    }
107
    *data = (unsigned char)c;
112,822,104✔
108
}
112,822,104✔
109

110
/* error diffusion with precise strategy */
111
static void
112
error_diffuse_precise(
4,074,246✔
113
    unsigned char /* in */    *data,      /* base address of pixel buffer */
114
    int           /* in */    pos,        /* address of the destination pixel */
115
    int           /* in */    depth,      /* color depth in bytes */
116
    int           /* in */    error,      /* error energy */
117
    int           /* in */    numerator,  /* numerator of diffusion coefficient */
118
    int           /* in */    denominator /* denominator of diffusion coefficient */)
119
{
120
    int c;
121

122
    data += pos * depth;
4,074,246✔
123

124
    c = (int)(*data + error * numerator / (double)denominator + 0.5);
4,074,246✔
125
    if (c < 0) {
4,074,246✔
126
        c = 0;
45,004✔
127
    }
128
    if (c >= 1 << 8) {
4,074,246!
129
        c = (1 << 8) - 1;
×
130
    }
131
    *data = (unsigned char)c;
4,074,246✔
132
}
4,074,246✔
133

134
typedef void (*diffuse_fixed_carry_mode)(int32_t *carry_curr,
135
                                         int32_t *carry_next,
136
                                         int32_t *carry_far,
137
                                         int width,
138
                                         int height,
139
                                         int depth,
140
                                         int x,
141
                                         int y,
142
                                         int32_t error,
143
                                         int direction,
144
                                         int channel);
145

146
static int32_t
147
diffuse_fixed_term(int32_t error, int numerator, int denominator)
×
148
{
149
    int64_t delta;
150

151
    delta = (int64_t)error * (int64_t)numerator;
×
152
    if (delta >= 0) {
×
153
        delta = (delta + denominator / 2) / denominator;
×
154
    } else {
155
        delta = (delta - denominator / 2) / denominator;
×
156
    }
157

158
    return (int32_t)delta;
×
159
}
160

161
static void diffuse_none(unsigned char *data,
162
                         int width,
163
                         int height,
164
                         int x,
165
                         int y,
166
                         int depth,
167
                         int error,
168
                         int direction);
169

170
static void diffuse_none_carry(int32_t *carry_curr,
171
                               int32_t *carry_next,
172
                               int32_t *carry_far,
173
                               int width,
174
                               int height,
175
                               int depth,
176
                               int x,
177
                               int y,
178
                               int32_t error,
179
                               int direction,
180
                               int channel);
181

182
static void diffuse_fs(unsigned char *data,
183
                       int width,
184
                       int height,
185
                       int x,
186
                       int y,
187
                       int depth,
188
                       int error,
189
                       int direction);
190

191
static void diffuse_fs_carry(int32_t *carry_curr,
192
                             int32_t *carry_next,
193
                             int32_t *carry_far,
194
                             int width,
195
                             int height,
196
                             int depth,
197
                             int x,
198
                             int y,
199
                             int32_t error,
200
                             int direction,
201
                             int channel);
202

203
static void diffuse_atkinson(unsigned char *data,
204
                             int width,
205
                             int height,
206
                             int x,
207
                             int y,
208
                             int depth,
209
                             int error,
210
                             int direction);
211

212
static void diffuse_atkinson_carry(int32_t *carry_curr,
213
                                   int32_t *carry_next,
214
                                   int32_t *carry_far,
215
                                   int width,
216
                                   int height,
217
                                   int depth,
218
                                   int x,
219
                                   int y,
220
                                   int32_t error,
221
                                   int direction,
222
                                   int channel);
223

224
static void diffuse_jajuni(unsigned char *data,
225
                           int width,
226
                           int height,
227
                           int x,
228
                           int y,
229
                           int depth,
230
                           int error,
231
                           int direction);
232

233
static void diffuse_jajuni_carry(int32_t *carry_curr,
234
                                 int32_t *carry_next,
235
                                 int32_t *carry_far,
236
                                 int width,
237
                                 int height,
238
                                 int depth,
239
                                 int x,
240
                                 int y,
241
                                 int32_t error,
242
                                 int direction,
243
                                 int channel);
244

245
static void diffuse_stucki(unsigned char *data,
246
                           int width,
247
                           int height,
248
                           int x,
249
                           int y,
250
                           int depth,
251
                           int error,
252
                           int direction);
253

254
static void diffuse_stucki_carry(int32_t *carry_curr,
255
                                 int32_t *carry_next,
256
                                 int32_t *carry_far,
257
                                 int width,
258
                                 int height,
259
                                 int depth,
260
                                 int x,
261
                                 int y,
262
                                 int32_t error,
263
                                 int direction,
264
                                 int channel);
265

266
static void diffuse_burkes(unsigned char *data,
267
                           int width,
268
                           int height,
269
                           int x,
270
                           int y,
271
                           int depth,
272
                           int error,
273
                           int direction);
274

275
static void diffuse_burkes_carry(int32_t *carry_curr,
276
                                 int32_t *carry_next,
277
                                 int32_t *carry_far,
278
                                 int width,
279
                                 int height,
280
                                 int depth,
281
                                 int x,
282
                                 int y,
283
                                 int32_t error,
284
                                 int direction,
285
                                 int channel);
286

287
static void diffuse_sierra1(unsigned char *data,
288
                            int width,
289
                            int height,
290
                            int x,
291
                            int y,
292
                            int depth,
293
                            int error,
294
                            int direction);
295

296
static void diffuse_sierra1_carry(int32_t *carry_curr,
297
                                  int32_t *carry_next,
298
                                  int32_t *carry_far,
299
                                  int width,
300
                                  int height,
301
                                  int depth,
302
                                  int x,
303
                                  int y,
304
                                  int32_t error,
305
                                  int direction,
306
                                  int channel);
307

308
static void diffuse_sierra2(unsigned char *data,
309
                            int width,
310
                            int height,
311
                            int x,
312
                            int y,
313
                            int depth,
314
                            int error,
315
                            int direction);
316

317
static void diffuse_sierra2_carry(int32_t *carry_curr,
318
                                  int32_t *carry_next,
319
                                  int32_t *carry_far,
320
                                  int width,
321
                                  int height,
322
                                  int depth,
323
                                  int x,
324
                                  int y,
325
                                  int32_t error,
326
                                  int direction,
327
                                  int channel);
328

329
static void diffuse_sierra3(unsigned char *data,
330
                            int width,
331
                            int height,
332
                            int x,
333
                            int y,
334
                            int depth,
335
                            int error,
336
                            int direction);
337

338
static void diffuse_sierra3_carry(int32_t *carry_curr,
339
                                  int32_t *carry_next,
340
                                  int32_t *carry_far,
341
                                  int width,
342
                                  int height,
343
                                  int depth,
344
                                  int x,
345
                                  int y,
346
                                  int32_t error,
347
                                  int direction,
348
                                  int channel);
349

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

420
    if (depth > max_channels) {
170!
421
        status = SIXEL_BAD_ARGUMENT;
×
422
        goto end;
×
423
    }
424

425
    use_carry = (method_for_carry == SIXEL_CARRY_ENABLE);
170✔
426
    carry_len = 0;
170✔
427

428
    if (depth != 3) {
170!
429
        f_diffuse = diffuse_none;
×
430
        f_diffuse_carry = diffuse_none_carry;
×
431
        use_carry = 0;
×
432
    } else {
433
        switch (method_for_diffuse) {
170!
434
        case SIXEL_DIFFUSE_NONE:
86✔
435
            f_diffuse = diffuse_none;
86✔
436
            f_diffuse_carry = diffuse_none_carry;
86✔
437
            break;
86✔
438
        case SIXEL_DIFFUSE_ATKINSON:
44✔
439
            f_diffuse = diffuse_atkinson;
44✔
440
            f_diffuse_carry = diffuse_atkinson_carry;
44✔
441
            break;
44✔
442
        case SIXEL_DIFFUSE_FS:
34✔
443
            f_diffuse = diffuse_fs;
34✔
444
            f_diffuse_carry = diffuse_fs_carry;
34✔
445
            break;
34✔
446
        case SIXEL_DIFFUSE_JAJUNI:
2✔
447
            f_diffuse = diffuse_jajuni;
2✔
448
            f_diffuse_carry = diffuse_jajuni_carry;
2✔
449
            break;
2✔
450
        case SIXEL_DIFFUSE_STUCKI:
2✔
451
            f_diffuse = diffuse_stucki;
2✔
452
            f_diffuse_carry = diffuse_stucki_carry;
2✔
453
            break;
2✔
454
        case SIXEL_DIFFUSE_BURKES:
2✔
455
            f_diffuse = diffuse_burkes;
2✔
456
            f_diffuse_carry = diffuse_burkes_carry;
2✔
457
            break;
2✔
458
        case SIXEL_DIFFUSE_SIERRA1:
×
459
            f_diffuse = diffuse_sierra1;
×
460
            f_diffuse_carry = diffuse_sierra1_carry;
×
461
            break;
×
462
        case SIXEL_DIFFUSE_SIERRA2:
×
463
            f_diffuse = diffuse_sierra2;
×
464
            f_diffuse_carry = diffuse_sierra2_carry;
×
465
            break;
×
466
        case SIXEL_DIFFUSE_SIERRA3:
×
467
            f_diffuse = diffuse_sierra3;
×
468
            f_diffuse_carry = diffuse_sierra3_carry;
×
469
            break;
×
470
        default:
×
471
            f_diffuse = diffuse_none;
×
472
            f_diffuse_carry = diffuse_none_carry;
×
473
            break;
×
474
        }
475
    }
476

477
    if (use_carry) {
170!
478
        carry_len = (size_t)width * (size_t)depth;
×
479
        if (carry_len > 0) {
×
480
            carry_curr = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
481
            if (carry_curr == NULL) {
×
482
                status = SIXEL_BAD_ALLOCATION;
×
483
                goto end;
×
484
            }
485
            carry_next = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
486
            if (carry_next == NULL) {
×
487
                status = SIXEL_BAD_ALLOCATION;
×
488
                goto end;
×
489
            }
490
            carry_far = (int32_t *)calloc(carry_len, sizeof(int32_t));
×
491
            if (carry_far == NULL) {
×
492
                status = SIXEL_BAD_ALLOCATION;
×
493
                goto end;
×
494
            }
495
        } else {
496
            use_carry = 0;
×
497
        }
498
    }
499

500
    serpentine = (method_for_scan == SIXEL_SCAN_SERPENTINE);
170✔
501

502
    if (optimize_palette) {
170✔
503
        *ncolors = 0;
130✔
504
        memset(new_palette, 0x00,
130✔
505
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
130✔
506
        memset(migration_map, 0x00,
130✔
507
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
508
    } else {
509
        *ncolors = reqcolor;
40✔
510
    }
511

512
    for (y = 0; y < height; ++y) {
33,070✔
513
        sixel_dither_scanline_params(serpentine, y, width,
32,900✔
514
                        &start, &end, &step, &direction);
515
        for (x = start; x != end; x += step) {
23,365,320✔
516
            pos = y * width + x;
23,332,420✔
517
            base = (size_t)pos * (size_t)depth;
23,332,420✔
518
            carry_base = (size_t)x * (size_t)depth;
23,332,420✔
519
            if (use_carry) {
23,332,420!
520
                for (n = 0; n < depth; ++n) {
×
521
                    accum = ((int64_t)data[base + n]
×
522
                             << VARERR_SCALE_SHIFT)
×
523
                           + carry_curr[carry_base + (size_t)n];
×
524
                    if (accum < INT32_MIN) {
×
525
                        accum = INT32_MIN;
×
526
                    } else if (accum > INT32_MAX) {
×
527
                        accum = INT32_MAX;
×
528
                    }
529
                    clamped = accum;
×
530
                    if (clamped < 0) {
×
531
                        clamped = 0;
×
532
                    } else if (clamped > VARERR_MAX_VALUE) {
×
533
                        clamped = VARERR_MAX_VALUE;
×
534
                    }
535
                    accum_scaled[n] = (int32_t)clamped;
×
536
                    corrected[n]
537
                        = (unsigned char)((clamped + VARERR_ROUND)
×
538
                                          >> VARERR_SCALE_SHIFT);
×
539
                    data[base + n] = corrected[n];
×
540
                    carry_curr[carry_base + (size_t)n] = 0;
×
541
                }
542
                source_pixel = corrected;
×
543
            } else {
544
                source_pixel = data + base;
23,332,420✔
545
            }
546

547
            color_index = f_lookup(source_pixel, depth, palette,
23,332,420✔
548
                                   reqcolor, indextable,
549
                                   complexion);
550

551
            if (optimize_palette) {
23,332,420✔
552
                if (migration_map[color_index] == 0) {
17,070,740✔
553
                    output_index = *ncolors;
10,896✔
554
                    for (n = 0; n < depth; ++n) {
43,584✔
555
                        new_palette[output_index * depth + n]
32,688✔
556
                            = palette[color_index * depth + n];
32,688✔
557
                    }
558
                    ++*ncolors;
10,896✔
559
                    migration_map[color_index] = *ncolors;
10,896✔
560
                } else {
561
                    output_index = migration_map[color_index] - 1;
17,059,844✔
562
                }
563
                result[pos] = output_index;
17,070,740✔
564
            } else {
565
                output_index = color_index;
6,261,680✔
566
                result[pos] = output_index;
6,261,680✔
567
            }
568

569
            for (n = 0; n < depth; ++n) {
93,329,680✔
570
                if (optimize_palette) {
69,997,260✔
571
                    palette_value = new_palette[output_index * depth + n];
51,212,220✔
572
                } else {
573
                    palette_value = palette[color_index * depth + n];
18,785,040✔
574
                }
575
                if (use_carry) {
69,997,260!
576
                    target_scaled = (int32_t)palette_value
×
577
                                  << VARERR_SCALE_SHIFT;
578
                    error_scaled = accum_scaled[n] - target_scaled;
×
579
                    f_diffuse_carry(carry_curr, carry_next, carry_far,
×
580
                                    width, height, depth,
581
                                    x, y, error_scaled, direction, n);
582
                } else {
583
                    offset = (int)source_pixel[n] - palette_value;
69,997,260✔
584
                    f_diffuse(data + n, width, height, x, y,
69,997,260✔
585
                              depth, offset, direction);
586
                }
587
            }
588
        }
589
        if (use_carry) {
32,900!
590
            tmp = carry_curr;
×
591
            carry_curr = carry_next;
×
592
            carry_next = carry_far;
×
593
            carry_far = tmp;
×
594
            if (carry_len > 0) {
×
595
                memset(carry_far, 0x00, carry_len * sizeof(int32_t));
×
596
            }
597
        }
598
        sixel_dither_pipeline_row_notify(dither, y);
32,900✔
599
    }
600

601
    if (optimize_palette) {
170✔
602
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
130✔
603
    }
604

605
    status = SIXEL_OK;
170✔
606

607
end:
170✔
608
    free(carry_far);
170✔
609
    free(carry_next);
170✔
610
    free(carry_curr);
170✔
611
    return status;
170✔
612
}
613

614
static void
615
diffuse_none(unsigned char *data, int width, int height,
3,779,316✔
616
             int x, int y, int depth, int error, int direction)
617
{
618
    /* unused */ (void) data;
619
    /* unused */ (void) width;
620
    /* unused */ (void) height;
621
    /* unused */ (void) x;
622
    /* unused */ (void) y;
623
    /* unused */ (void) depth;
624
    /* unused */ (void) error;
625
    /* unused */ (void) direction;
626
}
3,779,316✔
627

628

629
static void
630
diffuse_none_carry(int32_t *carry_curr, int32_t *carry_next,
×
631
                   int32_t *carry_far, int width, int height,
632
                   int depth, int x, int y, int32_t error,
633
                   int direction, int channel)
634
{
635
    /* unused */ (void) carry_curr;
636
    /* unused */ (void) carry_next;
637
    /* unused */ (void) carry_far;
638
    /* unused */ (void) width;
639
    /* unused */ (void) height;
640
    /* unused */ (void) depth;
641
    /* unused */ (void) x;
642
    /* unused */ (void) y;
643
    /* unused */ (void) error;
644
    /* unused */ (void) direction;
645
    /* unused */ (void) channel;
646
}
×
647

648
static void
649
diffuse_fs(unsigned char *data, int width, int height,
46,953,504✔
650
           int x, int y, int depth, int error, int direction)
651
{
652
    /* Floyd Steinberg Method
653
     *          curr    7/16
654
     *  3/16    5/16    1/16
655
     */
656
    int pos;
657
    int forward;
658

659
    pos = y * width + x;
46,953,504✔
660
    forward = direction >= 0;
46,953,504✔
661

662
    if (forward) {
46,953,504✔
663
        if (x < width - 1) {
46,143,504✔
664
            error_diffuse_normal(data, pos + 1, depth, error, 7, 16);
46,096,506✔
665
        }
666
        if (y < height - 1) {
46,143,504✔
667
            if (x > 0) {
46,080,888✔
668
                error_diffuse_normal(data,
46,033,986✔
669
                                     pos + width - 1,
46,033,986✔
670
                                     depth, error, 3, 16);
671
            }
672
            error_diffuse_normal(data,
46,080,888✔
673
                                 pos + width,
674
                                 depth, error, 5, 16);
675
            if (x < width - 1) {
46,080,888✔
676
                error_diffuse_normal(data,
46,033,986✔
677
                                     pos + width + 1,
46,033,986✔
678
                                     depth, error, 1, 16);
679
            }
680
        }
681
    } else {
682
        if (x > 0) {
810,000✔
683
            error_diffuse_normal(data, pos - 1, depth, error, 7, 16);
808,650✔
684
        }
685
        if (y < height - 1) {
810,000✔
686
            if (x < width - 1) {
806,400✔
687
                error_diffuse_normal(data,
805,056✔
688
                                     pos + width + 1,
805,056✔
689
                                     depth, error, 3, 16);
690
            }
691
            error_diffuse_normal(data,
806,400✔
692
                                 pos + width,
693
                                 depth, error, 5, 16);
694
            if (x > 0) {
806,400✔
695
                error_diffuse_normal(data,
805,056✔
696
                                     pos + width - 1,
805,056✔
697
                                     depth, error, 1, 16);
698
            }
699
        }
700
    }
701
}
46,953,504✔
702

703

704
static void
705
diffuse_fs_carry(int32_t *carry_curr, int32_t *carry_next,
×
706
                 int32_t *carry_far, int width, int height,
707
                 int depth, int x, int y, int32_t error,
708
                 int direction, int channel)
709
{
710
    /* Floyd Steinberg Method
711
     *          curr    7/16
712
     *  3/16    5/48    1/16
713
     */
714
    int forward;
715

716
    /* unused */ (void) carry_far;
717
    if (error == 0) {
×
718
        return;
×
719
    }
720

721
    forward = direction >= 0;
×
722
    if (forward) {
×
723
        if (x + 1 < width) {
×
724
            size_t base;
725
            int32_t term;
726

727
            base = ((size_t)(x + 1) * (size_t)depth)
×
728
                 + (size_t)channel;
×
729
            term = diffuse_fixed_term(error, 7, 16);
×
730
            carry_curr[base] += term;
×
731
        }
732
        if (y + 1 < height) {
×
733
            if (x > 0) {
×
734
                size_t base;
735
                int32_t term;
736

737
                base = ((size_t)(x - 1) * (size_t)depth)
×
738
                     + (size_t)channel;
×
739
                term = diffuse_fixed_term(error, 3, 16);
×
740
                carry_next[base] += term;
×
741
            }
742
            {
743
                size_t base;
744
                int32_t term;
745

746
                base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
747
                term = diffuse_fixed_term(error, 5, 16);
×
748
                carry_next[base] += term;
×
749
            }
750
            if (x + 1 < width) {
×
751
                size_t base;
752
                int32_t term;
753

754
                base = ((size_t)(x + 1) * (size_t)depth)
×
755
                     + (size_t)channel;
×
756
                term = diffuse_fixed_term(error, 1, 16);
×
757
                carry_next[base] += term;
×
758
            }
759
        }
760
    } else {
761
        if (x - 1 >= 0) {
×
762
            size_t base;
763
            int32_t term;
764

765
            base = ((size_t)(x - 1) * (size_t)depth)
×
766
                 + (size_t)channel;
×
767
            term = diffuse_fixed_term(error, 7, 16);
×
768
            carry_curr[base] += term;
×
769
        }
770
        if (y + 1 < height) {
×
771
            if (x + 1 < width) {
×
772
                size_t base;
773
                int32_t term;
774

775
                base = ((size_t)(x + 1) * (size_t)depth)
×
776
                     + (size_t)channel;
×
777
                term = diffuse_fixed_term(error, 3, 16);
×
778
                carry_next[base] += term;
×
779
            }
780
            {
781
                size_t base;
782
                int32_t term;
783

784
                base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
785
                term = diffuse_fixed_term(error, 5, 16);
×
786
                carry_next[base] += term;
×
787
            }
788
            if (x - 1 >= 0) {
×
789
                size_t base;
790
                int32_t term;
791

792
                base = ((size_t)(x - 1) * (size_t)depth)
×
793
                     + (size_t)channel;
×
794
                term = diffuse_fixed_term(error, 1, 16);
×
795
                carry_next[base] += term;
×
796
            }
797
        }
798
    }
799
}
800

801

802
static void
803
diffuse_atkinson(unsigned char *data, int width, int height,
18,875,040✔
804
                 int x, int y, int depth, int error, int direction)
805
{
806
    /* Atkinson's Method
807
     *          curr    1/8    1/8
808
     *   1/8     1/8    1/8
809
     *           1/8
810
     */
811
    int pos;
812
    int sign;
813

814
    pos = y * width + x;
18,875,040✔
815
    sign = direction >= 0 ? 1 : -1;
18,875,040!
816

817
    if (x + sign >= 0 && x + sign < width) {
18,875,040!
818
        error_diffuse_fast(data, pos + sign, depth, error, 1, 8);
18,838,230✔
819
    }
820
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
18,875,040!
821
        error_diffuse_fast(data, pos + sign * 2, depth, error, 1, 8);
18,801,420✔
822
    }
823
    if (y < height - 1) {
18,875,040✔
824
        int row;
825

826
        row = pos + width;
18,826,170✔
827
        if (x - sign >= 0 && x - sign < width) {
18,826,170!
828
            error_diffuse_fast(data,
18,789,492✔
829
                               row + (-sign),
830
                               depth, error, 1, 8);
831
        }
832
        error_diffuse_fast(data, row, depth, error, 1, 8);
18,826,170✔
833
        if (x + sign >= 0 && x + sign < width) {
18,826,170!
834
            error_diffuse_fast(data,
18,789,492✔
835
                               row + sign,
836
                               depth, error, 1, 8);
837
        }
838
    }
839
    if (y < height - 2) {
18,875,040✔
840
        error_diffuse_fast(data, pos + width * 2, depth, error, 1, 8);
18,777,300✔
841
    }
842
}
18,875,040✔
843

844

845
static void
846
diffuse_atkinson_carry(int32_t *carry_curr, int32_t *carry_next,
×
847
                       int32_t *carry_far, int width, int height,
848
                       int depth, int x, int y, int32_t error,
849
                       int direction, int channel)
850
{
851
    /* Atkinson's Method
852
     *          curr    1/8    1/8
853
     *   1/8     1/8    1/8
854
     *           1/8
855
     */
856
    int sign;
857
    int32_t term;
858

859
    if (error == 0) {
×
860
        return;
×
861
    }
862

863
    term = diffuse_fixed_term(error, 1, 8);
×
864
    sign = direction >= 0 ? 1 : -1;
×
865
    if (x + sign >= 0 && x + sign < width) {
×
866
        size_t base;
867

868
        base = ((size_t)(x + sign) * (size_t)depth)
×
869
             + (size_t)channel;
×
870
        carry_curr[base] += term;
×
871
    }
872
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
×
873
        size_t base;
874

875
        base = ((size_t)(x + sign * 2) * (size_t)depth)
×
876
             + (size_t)channel;
×
877
        carry_curr[base] += term;
×
878
    }
879
    if (y + 1 < height) {
×
880
        if (x - sign >= 0 && x - sign < width) {
×
881
            size_t base;
882

883
            base = ((size_t)(x - sign) * (size_t)depth)
×
884
                 + (size_t)channel;
×
885
            carry_next[base] += term;
×
886
        }
887
        {
888
            size_t base;
889

890
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
891
            carry_next[base] += term;
×
892
        }
893
        if (x + sign >= 0 && x + sign < width) {
×
894
            size_t base;
895

896
            base = ((size_t)(x + sign) * (size_t)depth)
×
897
                 + (size_t)channel;
×
898
            carry_next[base] += term;
×
899
        }
900
    }
901
    if (y + 2 < height) {
×
902
        size_t base;
903

904
        base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
905
        carry_far[base] += term;
×
906
    }
907
}
908

909

910
static void
911
diffuse_jajuni(unsigned char *data, int width, int height,
264,600✔
912
               int x, int y, int depth, int error, int direction)
913
{
914
    /* Jarvis, Judice & Ninke Method
915
     *                  curr    7/48    5/48
916
     *  3/48    5/48    7/48    5/48    3/48
917
     *  1/48    3/48    5/48    3/48    1/48
918
     */
919
    int pos;
920
    int sign;
921
    static const int row0_offsets[] = { 1, 2 };
922
    static const int row0_weights[] = { 7, 5 };
923
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
924
    static const int row1_weights[] = { 3, 5, 7, 5, 3 };
925
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
926
    static const int row2_weights[] = { 1, 3, 5, 3, 1 };
927
    int i;
928

929
    pos = y * width + x;
264,600✔
930
    sign = direction >= 0 ? 1 : -1;
264,600!
931

932
    for (i = 0; i < 2; ++i) {
793,800✔
933
        int neighbor;
934

935
        neighbor = x + sign * row0_offsets[i];
529,200✔
936
        if (neighbor < 0 || neighbor >= width) {
529,200!
937
            continue;
3,780✔
938
        }
939
        error_diffuse_precise(data,
525,420✔
940
                              pos + (neighbor - x),
525,420✔
941
                              depth, error,
942
                              row0_weights[i], 48);
525,420✔
943
    }
944
    if (y < height - 1) {
264,600✔
945
        int row;
946

947
        row = pos + width;
263,340✔
948
        for (i = 0; i < 5; ++i) {
1,580,040✔
949
            int neighbor;
950

951
            neighbor = x + sign * row1_offsets[i];
1,316,700✔
952
            if (neighbor < 0 || neighbor >= width) {
1,316,700✔
953
                continue;
7,524✔
954
            }
955
            error_diffuse_precise(data,
1,309,176✔
956
                                  row + (neighbor - x),
1,309,176✔
957
                                  depth, error,
958
                                  row1_weights[i], 48);
1,309,176✔
959
        }
960
    }
961
    if (y < height - 2) {
264,600✔
962
        int row;
963

964
        row = pos + width * 2;
262,080✔
965
        for (i = 0; i < 5; ++i) {
1,572,480✔
966
            int neighbor;
967

968
            neighbor = x + sign * row2_offsets[i];
1,310,400✔
969
            if (neighbor < 0 || neighbor >= width) {
1,310,400✔
970
                continue;
7,488✔
971
            }
972
            error_diffuse_precise(data,
1,302,912✔
973
                                  row + (neighbor - x),
1,302,912✔
974
                                  depth, error,
975
                                  row2_weights[i], 48);
1,302,912✔
976
        }
977
    }
978
}
264,600✔
979

980

981
static void
982
diffuse_jajuni_carry(int32_t *carry_curr, int32_t *carry_next,
×
983
                     int32_t *carry_far, int width, int height,
984
                     int depth, int x, int y, int32_t error,
985
                     int direction, int channel)
986
{
987
    /* Jarvis, Judice & Ninke Method
988
     *                  curr    7/48    5/48
989
     *  3/48    5/48    7/48    5/48    3/48
990
     *  1/48    3/48    5/48    3/48    1/48
991
     */
992
    static const int row0_offsets[] = { 1, 2 };
993
    static const int row0_weights[] = { 7, 5 };
994
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
995
    static const int row1_weights[] = { 3, 5, 7, 5, 3 };
996
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
997
    static const int row2_weights[] = { 1, 3, 5, 3, 1 };
998
    int sign;
999
    int i;
1000

1001
    if (error == 0) {
×
1002
        return;
×
1003
    }
1004

1005
    sign = direction >= 0 ? 1 : -1;
×
1006
    for (i = 0; i < 2; ++i) {
×
1007
        int neighbor;
1008
        int32_t term;
1009

1010
        neighbor = x + sign * row0_offsets[i];
×
1011
        if (neighbor < 0 || neighbor >= width) {
×
1012
            continue;
×
1013
        }
1014
        term = diffuse_fixed_term(error, row0_weights[i], 48);
×
1015
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1016
                   + (size_t)channel] += term;
×
1017
    }
1018
    if (y + 1 < height) {
×
1019
        for (i = 0; i < 5; ++i) {
×
1020
            int neighbor;
1021
            int32_t term;
1022

1023
            neighbor = x + sign * row1_offsets[i];
×
1024
            if (neighbor < 0 || neighbor >= width) {
×
1025
                continue;
×
1026
            }
1027
            term = diffuse_fixed_term(error, row1_weights[i], 48);
×
1028
            carry_next[((size_t)neighbor * (size_t)depth)
×
1029
                       + (size_t)channel] += term;
×
1030
        }
1031
    }
1032
    if (y + 2 < height) {
×
1033
        for (i = 0; i < 5; ++i) {
×
1034
            int neighbor;
1035
            int32_t term;
1036

1037
            neighbor = x + sign * row2_offsets[i];
×
1038
            if (neighbor < 0 || neighbor >= width) {
×
1039
                continue;
×
1040
            }
1041
            term = diffuse_fixed_term(error, row2_weights[i], 48);
×
1042
            carry_far[((size_t)neighbor * (size_t)depth)
×
1043
                      + (size_t)channel] += term;
×
1044
        }
1045
    }
1046
}
1047

1048

1049
static void
1050
diffuse_stucki(unsigned char *data, int width, int height,
79,800✔
1051
               int x, int y, int depth, int error, int direction)
1052
{
1053
    /* Stucki's Method
1054
     *                  curr    8/48    4/48
1055
     *  2/48    4/48    8/48    4/48    2/48
1056
     *  1/48    2/48    4/48    2/48    1/48
1057
     */
1058
    int pos;
1059
    int sign;
1060
    static const int row0_offsets[] = { 1, 2 };
1061
    static const int row0_num[] = { 1, 1 };
1062
    static const int row0_den[] = { 6, 12 };
1063
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1064
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
1065
    static const int row1_den[] = { 24, 12, 6, 12, 24 };
1066
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
1067
    static const int row2_num[] = { 1, 1, 1, 1, 1 };
1068
    static const int row2_den[] = { 48, 24, 12, 24, 48 };
1069
    int i;
1070

1071
    pos = y * width + x;
79,800✔
1072
    sign = direction >= 0 ? 1 : -1;
79,800!
1073

1074
    for (i = 0; i < 2; ++i) {
239,400✔
1075
        int neighbor;
1076

1077
        neighbor = x + sign * row0_offsets[i];
159,600✔
1078
        if (neighbor < 0 || neighbor >= width) {
159,600!
1079
            continue;
1,800✔
1080
        }
1081
        error_diffuse_precise(data,
157,800✔
1082
                              pos + (neighbor - x),
157,800✔
1083
                              depth, error,
1084
                              row0_num[i], row0_den[i]);
157,800✔
1085
    }
1086
    if (y < height - 1) {
79,800✔
1087
        int row;
1088

1089
        row = pos + width;
79,002✔
1090
        for (i = 0; i < 5; ++i) {
474,012✔
1091
            int neighbor;
1092

1093
            neighbor = x + sign * row1_offsets[i];
395,010✔
1094
            if (neighbor < 0 || neighbor >= width) {
395,010✔
1095
                continue;
3,564✔
1096
            }
1097
            error_diffuse_precise(data,
391,446✔
1098
                                  row + (neighbor - x),
391,446✔
1099
                                  depth, error,
1100
                                  row1_num[i], row1_den[i]);
391,446✔
1101
        }
1102
    }
1103
    if (y < height - 2) {
79,800✔
1104
        int row;
1105

1106
        row = pos + width * 2;
78,204✔
1107
        for (i = 0; i < 5; ++i) {
469,224✔
1108
            int neighbor;
1109

1110
            neighbor = x + sign * row2_offsets[i];
391,020✔
1111
            if (neighbor < 0 || neighbor >= width) {
391,020✔
1112
                continue;
3,528✔
1113
            }
1114
            error_diffuse_precise(data,
387,492✔
1115
                                  row + (neighbor - x),
387,492✔
1116
                                  depth, error,
1117
                                  row2_num[i], row2_den[i]);
387,492✔
1118
        }
1119
    }
1120
}
79,800✔
1121

1122

1123
static void
1124
diffuse_stucki_carry(int32_t *carry_curr, int32_t *carry_next,
×
1125
                     int32_t *carry_far, int width, int height,
1126
                     int depth, int x, int y, int32_t error,
1127
                     int direction, int channel)
1128
{
1129
    /* Stucki's Method
1130
     *                  curr    8/48    4/48
1131
     *  2/48    4/48    8/48    4/48    2/48
1132
     *  1/48    2/48    4/48    2/48    1/48
1133
     */
1134
    static const int row0_offsets[] = { 1, 2 };
1135
    static const int row0_num[] = { 1, 1 };
1136
    static const int row0_den[] = { 6, 12 };
1137
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1138
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
1139
    static const int row1_den[] = { 24, 12, 6, 12, 24 };
1140
    static const int row2_offsets[] = { -2, -1, 0, 1, 2 };
1141
    static const int row2_num[] = { 1, 1, 1, 1, 1 };
1142
    static const int row2_den[] = { 48, 24, 12, 24, 48 };
1143
    int sign;
1144
    int i;
1145

1146
    if (error == 0) {
×
1147
        return;
×
1148
    }
1149

1150
    sign = direction >= 0 ? 1 : -1;
×
1151
    for (i = 0; i < 2; ++i) {
×
1152
        int neighbor;
1153
        int32_t term;
1154

1155
        neighbor = x + sign * row0_offsets[i];
×
1156
        if (neighbor < 0 || neighbor >= width) {
×
1157
            continue;
×
1158
        }
1159
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1160
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1161
                   + (size_t)channel] += term;
×
1162
    }
1163
    if (y + 1 < height) {
×
1164
        for (i = 0; i < 5; ++i) {
×
1165
            int neighbor;
1166
            int32_t term;
1167

1168
            neighbor = x + sign * row1_offsets[i];
×
1169
            if (neighbor < 0 || neighbor >= width) {
×
1170
                continue;
×
1171
            }
1172
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1173
            carry_next[((size_t)neighbor * (size_t)depth)
×
1174
                       + (size_t)channel] += term;
×
1175
        }
1176
    }
1177
    if (y + 2 < height) {
×
1178
        for (i = 0; i < 5; ++i) {
×
1179
            int neighbor;
1180
            int32_t term;
1181

1182
            neighbor = x + sign * row2_offsets[i];
×
1183
            if (neighbor < 0 || neighbor >= width) {
×
1184
                continue;
×
1185
            }
1186
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
1187
            carry_far[((size_t)neighbor * (size_t)depth)
×
1188
                      + (size_t)channel] += term;
×
1189
        }
1190
    }
1191
}
1192

1193

1194
static void
1195
diffuse_burkes(unsigned char *data, int width, int height,
45,000✔
1196
               int x, int y, int depth, int error, int direction)
1197
{
1198
    /* Burkes' Method
1199
     *                  curr    4/16    2/16
1200
     *  1/16    2/16    4/16    2/16    1/16
1201
     */
1202
    int pos;
1203
    int sign;
1204
    static const int row0_offsets[] = { 1, 2 };
1205
    static const int row0_num[] = { 1, 1 };
1206
    static const int row0_den[] = { 4, 8 };
1207
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1208
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
1209
    static const int row1_den[] = { 16, 8, 4, 8, 16 };
1210
    int i;
1211

1212
    pos = y * width + x;
45,000✔
1213
    sign = direction >= 0 ? 1 : -1;
45,000!
1214

1215
    for (i = 0; i < 2; ++i) {
135,000✔
1216
        int neighbor;
1217

1218
        neighbor = x + sign * row0_offsets[i];
90,000✔
1219
        if (neighbor < 0 || neighbor >= width) {
90,000!
1220
            continue;
1,350✔
1221
        }
1222
        error_diffuse_normal(data,
88,650✔
1223
                             pos + (neighbor - x),
88,650✔
1224
                             depth, error,
1225
                             row0_num[i], row0_den[i]);
88,650✔
1226
    }
1227
    if (y < height - 1) {
45,000✔
1228
        int row;
1229

1230
        row = pos + width;
44,400✔
1231
        for (i = 0; i < 5; ++i) {
266,400✔
1232
            int neighbor;
1233

1234
            neighbor = x + sign * row1_offsets[i];
222,000✔
1235
            if (neighbor < 0 || neighbor >= width) {
222,000✔
1236
                continue;
2,664✔
1237
            }
1238
            error_diffuse_normal(data,
219,336✔
1239
                                 row + (neighbor - x),
219,336✔
1240
                                 depth, error,
1241
                                 row1_num[i], row1_den[i]);
219,336✔
1242
        }
1243
    }
1244
}
45,000✔
1245

1246
static void
1247
diffuse_burkes_carry(int32_t *carry_curr, int32_t *carry_next,
×
1248
                     int32_t *carry_far, int width, int height,
1249
                     int depth, int x, int y, int32_t error,
1250
                     int direction, int channel)
1251
{
1252
    /* Burkes' Method
1253
     *                  curr    4/16    2/16
1254
     *  1/16    2/16    4/16    2/16    1/16
1255
     */
1256
    static const int row0_offsets[] = { 1, 2 };
1257
    static const int row0_num[] = { 1, 1 };
1258
    static const int row0_den[] = { 4, 8 };
1259
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1260
    static const int row1_num[] = { 1, 1, 1, 1, 1 };
1261
    static const int row1_den[] = { 16, 8, 4, 8, 16 };
1262
    int sign;
1263
    int i;
1264

1265
    /* unused */ (void) carry_far;
1266

1267
    if (error == 0) {
×
1268
        return;
×
1269
    }
1270

1271
    sign = direction >= 0 ? 1 : -1;
×
1272
    for (i = 0; i < 2; ++i) {
×
1273
        int neighbor;
1274
        int32_t term;
1275

1276
        neighbor = x + sign * row0_offsets[i];
×
1277
        if (neighbor < 0 || neighbor >= width) {
×
1278
            continue;
×
1279
        }
1280
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1281
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1282
                   + (size_t)channel] += term;
×
1283
    }
1284
    if (y + 1 < height) {
×
1285
        for (i = 0; i < 5; ++i) {
×
1286
            int neighbor;
1287
            int32_t term;
1288

1289
            neighbor = x + sign * row1_offsets[i];
×
1290
            if (neighbor < 0 || neighbor >= width) {
×
1291
                continue;
×
1292
            }
1293
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1294
            carry_next[((size_t)neighbor * (size_t)depth)
×
1295
                       + (size_t)channel] += term;
×
1296
        }
1297
    }
1298
}
1299

1300
static void
1301
diffuse_sierra1(unsigned char *data, int width, int height,
×
1302
                int x, int y, int depth, int error, int direction)
1303
{
1304
    /* Sierra Lite Method
1305
     *          curr    2/4
1306
     *  1/4     1/4
1307
     */
1308
    static const int row0_offsets[] = { 1 };
1309
    static const int row0_num[] = { 1 };
1310
    static const int row0_den[] = { 2 };
1311
    static const int row1_offsets[] = { -1, 0 };
1312
    static const int row1_num[] = { 1, 1 };
1313
    static const int row1_den[] = { 4, 4 };
1314
    int pos;
1315
    int sign;
1316
    int i;
1317
    int neighbor;
1318
    int row;
1319

1320
    pos = y * width + x;
×
1321
    sign = direction >= 0 ? 1 : -1;
×
1322

1323
    for (i = 0; i < 1; ++i) {
×
1324
        neighbor = x + sign * row0_offsets[i];
×
1325
        if (neighbor < 0 || neighbor >= width) {
×
1326
            continue;
×
1327
        }
1328
        error_diffuse_normal(data,
×
1329
                             pos + (neighbor - x),
×
1330
                             depth, error,
1331
                             row0_num[i], row0_den[i]);
×
1332
    }
1333
    if (y < height - 1) {
×
1334
        row = pos + width;
×
1335
        for (i = 0; i < 2; ++i) {
×
1336
            neighbor = x + sign * row1_offsets[i];
×
1337
            if (neighbor < 0 || neighbor >= width) {
×
1338
                continue;
×
1339
            }
1340
            error_diffuse_normal(data,
×
1341
                                 row + (neighbor - x),
×
1342
                                 depth, error,
1343
                                 row1_num[i], row1_den[i]);
×
1344
        }
1345
    }
1346
}
×
1347

1348

1349
static void
1350
diffuse_sierra1_carry(int32_t *carry_curr, int32_t *carry_next,
×
1351
                      int32_t *carry_far, int width, int height,
1352
                      int depth, int x, int y, int32_t error,
1353
                      int direction, int channel)
1354
{
1355
    /* Sierra Lite Method
1356
     *          curr    2/4
1357
     *  1/4     1/4
1358
     */
1359
    static const int row0_offsets[] = { 1 };
1360
    static const int row0_num[] = { 1 };
1361
    static const int row0_den[] = { 2 };
1362
    static const int row1_offsets[] = { -1, 0 };
1363
    static const int row1_num[] = { 1, 1 };
1364
    static const int row1_den[] = { 4, 4 };
1365
    int sign;
1366
    int i;
1367
    int neighbor;
1368
    int32_t term;
1369

1370
    /* unused */ (void) carry_far;
1371

1372
    if (error == 0) {
×
1373
        return;
×
1374
    }
1375

1376
    sign = direction >= 0 ? 1 : -1;
×
1377
    for (i = 0; i < 1; ++i) {
×
1378
        neighbor = x + sign * row0_offsets[i];
×
1379
        if (neighbor < 0 || neighbor >= width) {
×
1380
            continue;
×
1381
        }
1382
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1383
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1384
                   + (size_t)channel] += term;
×
1385
    }
1386
    if (y + 1 < height) {
×
1387
        for (i = 0; i < 2; ++i) {
×
1388
            neighbor = x + sign * row1_offsets[i];
×
1389
            if (neighbor < 0 || neighbor >= width) {
×
1390
                continue;
×
1391
            }
1392
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1393
            carry_next[((size_t)neighbor * (size_t)depth)
×
1394
                       + (size_t)channel] += term;
×
1395
        }
1396
    }
1397
}
1398

1399

1400
static void
1401
diffuse_sierra2(unsigned char *data, int width, int height,
×
1402
                int x, int y, int depth, int error, int direction)
1403
{
1404
    /* Sierra Two-row Method
1405
     *                  curr    4/32    3/32
1406
     *  1/32    2/32    3/32    2/32    1/32
1407
     *                  2/32    3/32    2/32
1408
     */
1409
    static const int row0_offsets[] = { 1, 2 };
1410
    static const int row0_num[] = { 4, 3 };
1411
    static const int row0_den[] = { 32, 32 };
1412
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1413
    static const int row1_num[] = { 1, 2, 3, 2, 1 };
1414
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
1415
    static const int row2_offsets[] = { -1, 0, 1 };
1416
    static const int row2_num[] = { 2, 3, 2 };
1417
    static const int row2_den[] = { 32, 32, 32 };
1418
    int pos;
1419
    int sign;
1420
    int i;
1421
    int neighbor;
1422
    int row;
1423

1424
    pos = y * width + x;
×
1425
    sign = direction >= 0 ? 1 : -1;
×
1426

1427
    for (i = 0; i < 2; ++i) {
×
1428
        neighbor = x + sign * row0_offsets[i];
×
1429
        if (neighbor < 0 || neighbor >= width) {
×
1430
            continue;
×
1431
        }
1432
        error_diffuse_precise(data,
×
1433
                              pos + (neighbor - x),
×
1434
                              depth, error,
1435
                              row0_num[i], row0_den[i]);
×
1436
    }
1437
    if (y < height - 1) {
×
1438
        row = pos + width;
×
1439
        for (i = 0; i < 5; ++i) {
×
1440
            neighbor = x + sign * row1_offsets[i];
×
1441
            if (neighbor < 0 || neighbor >= width) {
×
1442
                continue;
×
1443
            }
1444
            error_diffuse_precise(data,
×
1445
                                  row + (neighbor - x),
×
1446
                                  depth, error,
1447
                                  row1_num[i], row1_den[i]);
×
1448
        }
1449
    }
1450
    if (y < height - 2) {
×
1451
        row = pos + width * 2;
×
1452
        for (i = 0; i < 3; ++i) {
×
1453
            neighbor = x + sign * row2_offsets[i];
×
1454
            if (neighbor < 0 || neighbor >= width) {
×
1455
                continue;
×
1456
            }
1457
            error_diffuse_precise(data,
×
1458
                                  row + (neighbor - x),
×
1459
                                  depth, error,
1460
                                  row2_num[i], row2_den[i]);
×
1461
        }
1462
    }
1463
}
×
1464

1465

1466
static void
1467
diffuse_sierra2_carry(int32_t *carry_curr, int32_t *carry_next,
×
1468
                      int32_t *carry_far, int width, int height,
1469
                      int depth, int x, int y, int32_t error,
1470
                      int direction, int channel)
1471
{
1472
    /* Sierra Two-row Method
1473
     *                  curr    4/32    3/32
1474
     *  1/32    2/32    3/32    2/32    1/32
1475
     *                  2/32    3/32    2/32
1476
     */
1477
    static const int row0_offsets[] = { 1, 2 };
1478
    static const int row0_num[] = { 4, 3 };
1479
    static const int row0_den[] = { 32, 32 };
1480
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1481
    static const int row1_num[] = { 1, 2, 3, 2, 1 };
1482
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
1483
    static const int row2_offsets[] = { -1, 0, 1 };
1484
    static const int row2_num[] = { 2, 3, 2 };
1485
    static const int row2_den[] = { 32, 32, 32 };
1486
    int sign;
1487
    int i;
1488
    int neighbor;
1489
    int32_t term;
1490

1491
    if (error == 0) {
×
1492
        return;
×
1493
    }
1494

1495
    sign = direction >= 0 ? 1 : -1;
×
1496
    for (i = 0; i < 2; ++i) {
×
1497
        neighbor = x + sign * row0_offsets[i];
×
1498
        if (neighbor < 0 || neighbor >= width) {
×
1499
            continue;
×
1500
        }
1501
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1502
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1503
                   + (size_t)channel] += term;
×
1504
    }
1505
    if (y + 1 < height) {
×
1506
        for (i = 0; i < 5; ++i) {
×
1507
            neighbor = x + sign * row1_offsets[i];
×
1508
            if (neighbor < 0 || neighbor >= width) {
×
1509
                continue;
×
1510
            }
1511
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1512
            carry_next[((size_t)neighbor * (size_t)depth)
×
1513
                       + (size_t)channel] += term;
×
1514
        }
1515
    }
1516
    if (y + 2 < height) {
×
1517
        for (i = 0; i < 3; ++i) {
×
1518
            neighbor = x + sign * row2_offsets[i];
×
1519
            if (neighbor < 0 || neighbor >= width) {
×
1520
                continue;
×
1521
            }
1522
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
1523
            carry_far[((size_t)neighbor * (size_t)depth)
×
1524
                      + (size_t)channel] += term;
×
1525
        }
1526
    }
1527
}
1528

1529

1530
static void
1531
diffuse_sierra3(unsigned char *data, int width, int height,
×
1532
                int x, int y, int depth, int error, int direction)
1533
{
1534
    /* Sierra-3 Method
1535
     *                  curr    5/32    3/32
1536
     *  2/32    4/32    5/32    4/32    2/32
1537
     *                  2/32    3/32    2/32
1538
     */
1539
    static const int row0_offsets[] = { 1, 2 };
1540
    static const int row0_num[] = { 5, 3 };
1541
    static const int row0_den[] = { 32, 32 };
1542
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1543
    static const int row1_num[] = { 2, 4, 5, 4, 2 };
1544
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
1545
    static const int row2_offsets[] = { -1, 0, 1 };
1546
    static const int row2_num[] = { 2, 3, 2 };
1547
    static const int row2_den[] = { 32, 32, 32 };
1548
    int pos;
1549
    int sign;
1550
    int i;
1551
    int neighbor;
1552
    int row;
1553

1554
    pos = y * width + x;
×
1555
    sign = direction >= 0 ? 1 : -1;
×
1556

1557
    for (i = 0; i < 2; ++i) {
×
1558
        neighbor = x + sign * row0_offsets[i];
×
1559
        if (neighbor < 0 || neighbor >= width) {
×
1560
            continue;
×
1561
        }
1562
        error_diffuse_precise(data,
×
1563
                              pos + (neighbor - x),
×
1564
                              depth, error,
1565
                              row0_num[i], row0_den[i]);
×
1566
    }
1567
    if (y < height - 1) {
×
1568
        row = pos + width;
×
1569
        for (i = 0; i < 5; ++i) {
×
1570
            neighbor = x + sign * row1_offsets[i];
×
1571
            if (neighbor < 0 || neighbor >= width) {
×
1572
                continue;
×
1573
            }
1574
            error_diffuse_precise(data,
×
1575
                                  row + (neighbor - x),
×
1576
                                  depth, error,
1577
                                  row1_num[i], row1_den[i]);
×
1578
        }
1579
    }
1580
    if (y < height - 2) {
×
1581
        row = pos + width * 2;
×
1582
        for (i = 0; i < 3; ++i) {
×
1583
            neighbor = x + sign * row2_offsets[i];
×
1584
            if (neighbor < 0 || neighbor >= width) {
×
1585
                continue;
×
1586
            }
1587
            error_diffuse_precise(data,
×
1588
                                  row + (neighbor - x),
×
1589
                                  depth, error,
1590
                                  row2_num[i], row2_den[i]);
×
1591
        }
1592
    }
1593
}
×
1594

1595

1596
static void
1597
diffuse_sierra3_carry(int32_t *carry_curr, int32_t *carry_next,
×
1598
                      int32_t *carry_far, int width, int height,
1599
                      int depth, int x, int y, int32_t error,
1600
                      int direction, int channel)
1601
{
1602
    /* Sierra-3 Method
1603
     *                  curr    5/32    3/32
1604
     *  2/32    4/32    5/32    4/32    2/32
1605
     *                  2/32    3/32    2/32
1606
     */
1607
    static const int row0_offsets[] = { 1, 2 };
1608
    static const int row0_num[] = { 5, 3 };
1609
    static const int row0_den[] = { 32, 32 };
1610
    static const int row1_offsets[] = { -2, -1, 0, 1, 2 };
1611
    static const int row1_num[] = { 2, 4, 5, 4, 2 };
1612
    static const int row1_den[] = { 32, 32, 32, 32, 32 };
1613
    static const int row2_offsets[] = { -1, 0, 1 };
1614
    static const int row2_num[] = { 2, 3, 2 };
1615
    static const int row2_den[] = { 32, 32, 32 };
1616
    int sign;
1617
    int i;
1618
    int neighbor;
1619
    int32_t term;
1620

1621
    if (error == 0) {
×
1622
        return;
×
1623
    }
1624

1625
    sign = direction >= 0 ? 1 : -1;
×
1626
    for (i = 0; i < 2; ++i) {
×
1627
        neighbor = x + sign * row0_offsets[i];
×
1628
        if (neighbor < 0 || neighbor >= width) {
×
1629
            continue;
×
1630
        }
1631
        term = diffuse_fixed_term(error, row0_num[i], row0_den[i]);
×
1632
        carry_curr[((size_t)neighbor * (size_t)depth)
×
1633
                   + (size_t)channel] += term;
×
1634
    }
1635
    if (y + 1 < height) {
×
1636
        for (i = 0; i < 5; ++i) {
×
1637
            neighbor = x + sign * row1_offsets[i];
×
1638
            if (neighbor < 0 || neighbor >= width) {
×
1639
                continue;
×
1640
            }
1641
            term = diffuse_fixed_term(error, row1_num[i], row1_den[i]);
×
1642
            carry_next[((size_t)neighbor * (size_t)depth)
×
1643
                       + (size_t)channel] += term;
×
1644
        }
1645
    }
1646
    if (y + 2 < height) {
×
1647
        for (i = 0; i < 3; ++i) {
×
1648
            neighbor = x + sign * row2_offsets[i];
×
1649
            if (neighbor < 0 || neighbor >= width) {
×
1650
                continue;
×
1651
            }
1652
            term = diffuse_fixed_term(error, row2_num[i], row2_den[i]);
×
1653
            carry_far[((size_t)neighbor * (size_t)depth)
×
1654
                      + (size_t)channel] += term;
×
1655
        }
1656
    }
1657
}
1658

1659
/* emacs Local Variables:      */
1660
/* emacs mode: c               */
1661
/* emacs tab-width: 4          */
1662
/* emacs indent-tabs-mode: nil */
1663
/* emacs c-basic-offset: 4     */
1664
/* emacs End:                  */
1665
/* vim: set expandtab ts=4 sts=4 sw=4 : */
1666
/* 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