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

saitoha / libsixel / 19391148264

15 Nov 2025 02:12PM UTC coverage: 43.89% (+0.5%) from 43.379%
19391148264

push

github

saitoha
reorganize dithering headers

8474 of 27760 branches covered (30.53%)

322 of 1019 new or added lines in 4 files covered. (31.6%)

2 existing lines in 1 file now uncovered.

11759 of 26792 relevant lines covered (43.89%)

1075858.54 hits per line

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

46.62
/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,
50,814✔
39
                             int index,
40
                             int limit,
41
                             int *start,
42
                             int *end,
43
                             int *step,
44
                             int *direction)
45
{
46
    if (serpentine && (index & 1)) {
50,814✔
47
        *start = limit - 1;
675✔
48
        *end = -1;
675✔
49
        *step = -1;
675✔
50
        *direction = -1;
675✔
51
    } else {
225✔
52
        *start = 0;
50,139✔
53
        *end = limit;
50,139✔
54
        *step = 1;
50,139✔
55
        *direction = 1;
50,139✔
56
    }
57
}
50,814✔
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(
281,667,771✔
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;
281,667,771✔
76

77
    c = *data + (error * numerator * 2 / denominator + 1) / 2;
281,667,771✔
78
    if (c < 0) {
281,667,771✔
79
        c = 0;
2,682,054✔
80
    }
912,428✔
81
    if (c >= 1 << 8) {
281,667,771✔
82
        c = (1 << 8) - 1;
1,454,339✔
83
    }
456,051✔
84
    *data = (unsigned char)c;
281,667,771✔
85
}
281,667,771✔
86

87
static void
88
error_diffuse_fast(
169,233,156✔
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;
169,233,156✔
99

100
    c = *data + error * numerator / denominator;
169,233,156✔
101
    if (c < 0) {
169,233,156✔
102
        c = 0;
7,009,606✔
103
    }
2,347,020✔
104
    if (c >= 1 << 8) {
169,233,156✔
105
        c = (1 << 8) - 1;
459,165✔
106
    }
152,477✔
107
    *data = (unsigned char)c;
169,233,156✔
108
}
169,233,156✔
109

110
/* error diffusion with precise strategy */
111
static void
112
error_diffuse_precise(
6,111,369✔
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;
6,111,369✔
123

124
    c = (int)(*data + error * numerator / (double)denominator + 0.5);
6,111,369✔
125
    if (c < 0) {
6,111,369✔
126
        c = 0;
70,867✔
127
    }
25,863✔
128
    if (c >= 1 << 8) {
6,111,369!
NEW
129
        c = (1 << 8) - 1;
×
130
    }
131
    *data = (unsigned char)c;
6,111,369✔
132
}
6,111,369✔
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
NEW
147
diffuse_fixed_term(int32_t error, int numerator, int denominator)
×
148
{
149
    int64_t delta;
150

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

NEW
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(
256✔
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;
256✔
380
#endif
381
    SIXELSTATUS status = SIXEL_FALSE;
256✔
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;
256✔
396
    int32_t *carry_next = NULL;
256✔
397
    int32_t *carry_far = NULL;
256✔
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) {
256!
NEW
421
        status = SIXEL_BAD_ARGUMENT;
×
NEW
422
        goto end;
×
423
    }
424

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

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

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

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

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

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

547
            color_index = f_lookup(source_pixel, depth, palette,
55,191,176✔
548
                                   reqcolor, indextable,
15,929,378✔
549
                                   complexion);
15,929,378✔
550

551
            if (optimize_palette) {
39,261,798✔
552
                if (migration_map[color_index] == 0) {
29,869,278✔
553
                    output_index = *ncolors;
16,514✔
554
                    for (n = 0; n < depth; ++n) {
66,056✔
555
                        new_palette[output_index * depth + n]
49,542✔
556
                            = palette[color_index * depth + n];
66,396✔
557
                    }
16,854✔
558
                    ++*ncolors;
16,514✔
559
                    migration_map[color_index] = *ncolors;
16,514✔
560
                } else {
5,618✔
561
                    output_index = migration_map[color_index] - 1;
29,852,764✔
562
                }
563
                result[pos] = output_index;
29,869,278✔
564
            } else {
12,798,538✔
565
                output_index = color_index;
9,392,520✔
566
                result[pos] = output_index;
9,392,520✔
567
            }
568

569
            for (n = 0; n < depth; ++n) {
157,047,192✔
570
                if (optimize_palette) {
117,785,394✔
571
                    palette_value = new_palette[output_index * depth + n];
89,607,834✔
572
                } else {
38,395,614✔
573
                    palette_value = palette[color_index * depth + n];
28,177,560✔
574
                }
575
                if (use_carry) {
117,785,394!
NEW
576
                    target_scaled = (int32_t)palette_value
×
577
                                  << VARERR_SCALE_SHIFT;
NEW
578
                    error_scaled = accum_scaled[n] - target_scaled;
×
NEW
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;
117,785,394✔
584
                    f_diffuse(data + n, width, height, x, y,
165,573,528✔
585
                              depth, offset, direction);
47,788,134✔
586
                }
587
            }
47,788,134✔
588
        }
15,929,378✔
589
        if (use_carry) {
50,814!
NEW
590
            tmp = carry_curr;
×
NEW
591
            carry_curr = carry_next;
×
NEW
592
            carry_next = carry_far;
×
NEW
593
            carry_far = tmp;
×
NEW
594
            if (carry_len > 0) {
×
NEW
595
                memset(carry_far, 0x00, carry_len * sizeof(int32_t));
×
596
            }
597
        }
598
        sixel_dither_pipeline_row_notify(dither, y);
50,814✔
599
    }
17,914✔
600

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

605
    status = SIXEL_OK;
256✔
606

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

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

628

629
static void
NEW
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;
NEW
646
}
×
647

648
static void
649
diffuse_fs(unsigned char *data, int width, int height,
70,430,256✔
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;
70,430,256✔
660
    forward = direction >= 0;
70,430,256✔
661

662
    if (forward) {
70,430,256✔
663
        if (x < width - 1) {
69,215,256✔
664
            error_diffuse_normal(data, pos + 1, depth, error, 7, 16);
69,144,759✔
665
        }
23,048,253✔
666
        if (y < height - 1) {
69,215,256✔
667
            if (x > 0) {
69,121,332✔
668
                error_diffuse_normal(data,
92,067,972✔
669
                                     pos + width - 1,
69,050,979✔
670
                                     depth, error, 3, 16);
23,016,993✔
671
            }
23,016,993✔
672
            error_diffuse_normal(data,
92,161,776✔
673
                                 pos + width,
23,040,444✔
674
                                 depth, error, 5, 16);
23,040,444✔
675
            if (x < width - 1) {
69,121,332✔
676
                error_diffuse_normal(data,
92,067,972✔
677
                                     pos + width + 1,
69,050,979✔
678
                                     depth, error, 1, 16);
23,016,993✔
679
            }
23,016,993✔
680
        }
23,040,444✔
681
    } else {
23,071,752✔
682
        if (x > 0) {
1,215,000✔
683
            error_diffuse_normal(data, pos - 1, depth, error, 7, 16);
1,212,975✔
684
        }
404,325✔
685
        if (y < height - 1) {
1,215,000✔
686
            if (x < width - 1) {
1,209,600✔
687
                error_diffuse_normal(data,
1,610,112✔
688
                                     pos + width + 1,
1,207,584✔
689
                                     depth, error, 3, 16);
402,528✔
690
            }
402,528✔
691
            error_diffuse_normal(data,
1,612,800✔
692
                                 pos + width,
403,200✔
693
                                 depth, error, 5, 16);
403,200✔
694
            if (x > 0) {
1,209,600✔
695
                error_diffuse_normal(data,
1,610,112✔
696
                                     pos + width - 1,
1,207,584✔
697
                                     depth, error, 1, 16);
402,528✔
698
            }
402,528✔
699
        }
403,200✔
700
    }
701
}
70,430,256✔
702

703

704
static void
NEW
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;
NEW
717
    if (error == 0) {
×
NEW
718
        return;
×
719
    }
720

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

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

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

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

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

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

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

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

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

801

802
static void
803
diffuse_atkinson(unsigned char *data, int width, int height,
28,312,560✔
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;
28,312,560✔
815
    sign = direction >= 0 ? 1 : -1;
28,312,560!
816

817
    if (x + sign >= 0 && x + sign < width) {
28,312,560!
818
        error_diffuse_fast(data, pos + sign, depth, error, 1, 8);
28,257,345✔
819
    }
9,419,115✔
820
    if (x + sign * 2 >= 0 && x + sign * 2 < width) {
28,312,560!
821
        error_diffuse_fast(data, pos + sign * 2, depth, error, 1, 8);
28,202,130✔
822
    }
9,400,710✔
823
    if (y < height - 1) {
28,312,560✔
824
        int row;
825

826
        row = pos + width;
28,239,255✔
827
        if (x - sign >= 0 && x - sign < width) {
28,239,255!
828
            error_diffuse_fast(data,
37,578,984✔
829
                               row + (-sign),
9,394,746✔
830
                               depth, error, 1, 8);
9,394,746✔
831
        }
9,394,746✔
832
        error_diffuse_fast(data, row, depth, error, 1, 8);
28,239,255✔
833
        if (x + sign >= 0 && x + sign < width) {
28,239,255!
834
            error_diffuse_fast(data,
37,578,984✔
835
                               row + sign,
9,394,746✔
836
                               depth, error, 1, 8);
9,394,746✔
837
        }
9,394,746✔
838
    }
9,413,085✔
839
    if (y < height - 2) {
28,312,560✔
840
        error_diffuse_fast(data, pos + width * 2, depth, error, 1, 8);
28,165,950✔
841
    }
9,388,650✔
842
}
28,312,560✔
843

844

845
static void
NEW
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

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

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

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

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

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

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

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

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

909

910
static void
911
diffuse_jajuni(unsigned char *data, int width, int height,
396,900✔
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;
396,900✔
930
    sign = direction >= 0 ? 1 : -1;
396,900!
931

932
    for (i = 0; i < 2; ++i) {
1,190,700✔
933
        int neighbor;
934

935
        neighbor = x + sign * row0_offsets[i];
793,800✔
936
        if (neighbor < 0 || neighbor >= width) {
793,800!
937
            continue;
5,670✔
938
        }
939
        error_diffuse_precise(data,
1,050,840✔
940
                              pos + (neighbor - x),
788,130✔
941
                              depth, error,
262,710✔
942
                              row0_weights[i], 48);
788,130✔
943
    }
262,710✔
944
    if (y < height - 1) {
396,900✔
945
        int row;
946

947
        row = pos + width;
395,010✔
948
        for (i = 0; i < 5; ++i) {
2,370,060✔
949
            int neighbor;
950

951
            neighbor = x + sign * row1_offsets[i];
1,975,050✔
952
            if (neighbor < 0 || neighbor >= width) {
1,975,050✔
953
                continue;
11,286✔
954
            }
955
            error_diffuse_precise(data,
2,618,352✔
956
                                  row + (neighbor - x),
1,963,764✔
957
                                  depth, error,
654,588✔
958
                                  row1_weights[i], 48);
1,963,764✔
959
        }
654,588✔
960
    }
131,670✔
961
    if (y < height - 2) {
396,900✔
962
        int row;
963

964
        row = pos + width * 2;
393,120✔
965
        for (i = 0; i < 5; ++i) {
2,358,720✔
966
            int neighbor;
967

968
            neighbor = x + sign * row2_offsets[i];
1,965,600✔
969
            if (neighbor < 0 || neighbor >= width) {
1,965,600✔
970
                continue;
11,232✔
971
            }
972
            error_diffuse_precise(data,
2,605,824✔
973
                                  row + (neighbor - x),
1,954,368✔
974
                                  depth, error,
651,456✔
975
                                  row2_weights[i], 48);
1,954,368✔
976
        }
651,456✔
977
    }
131,040✔
978
}
396,900✔
979

980

981
static void
NEW
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

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

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

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

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

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

1048

1049
static void
1050
diffuse_stucki(unsigned char *data, int width, int height,
119,700✔
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;
119,700✔
1072
    sign = direction >= 0 ? 1 : -1;
119,700!
1073

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

1077
        neighbor = x + sign * row0_offsets[i];
239,400✔
1078
        if (neighbor < 0 || neighbor >= width) {
239,400!
1079
            continue;
2,700✔
1080
        }
1081
        error_diffuse_precise(data,
315,600✔
1082
                              pos + (neighbor - x),
236,700✔
1083
                              depth, error,
78,900✔
1084
                              row0_num[i], row0_den[i]);
236,700✔
1085
    }
78,900✔
1086
    if (y < height - 1) {
119,700✔
1087
        int row;
1088

1089
        row = pos + width;
118,503✔
1090
        for (i = 0; i < 5; ++i) {
711,018✔
1091
            int neighbor;
1092

1093
            neighbor = x + sign * row1_offsets[i];
592,515✔
1094
            if (neighbor < 0 || neighbor >= width) {
592,515✔
1095
                continue;
5,346✔
1096
            }
1097
            error_diffuse_precise(data,
782,892✔
1098
                                  row + (neighbor - x),
587,169✔
1099
                                  depth, error,
195,723✔
1100
                                  row1_num[i], row1_den[i]);
587,169✔
1101
        }
195,723✔
1102
    }
39,501✔
1103
    if (y < height - 2) {
119,700✔
1104
        int row;
1105

1106
        row = pos + width * 2;
117,306✔
1107
        for (i = 0; i < 5; ++i) {
703,836✔
1108
            int neighbor;
1109

1110
            neighbor = x + sign * row2_offsets[i];
586,530✔
1111
            if (neighbor < 0 || neighbor >= width) {
586,530✔
1112
                continue;
5,292✔
1113
            }
1114
            error_diffuse_precise(data,
774,984✔
1115
                                  row + (neighbor - x),
581,238✔
1116
                                  depth, error,
193,746✔
1117
                                  row2_num[i], row2_den[i]);
581,238✔
1118
        }
193,746✔
1119
    }
39,102✔
1120
}
119,700✔
1121

1122

1123
static void
NEW
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

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

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

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

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

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

1193

1194
static void
1195
diffuse_burkes(unsigned char *data, int width, int height,
67,500✔
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;
67,500✔
1213
    sign = direction >= 0 ? 1 : -1;
67,500!
1214

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

1218
        neighbor = x + sign * row0_offsets[i];
135,000✔
1219
        if (neighbor < 0 || neighbor >= width) {
135,000!
1220
            continue;
2,025✔
1221
        }
1222
        error_diffuse_normal(data,
177,300✔
1223
                             pos + (neighbor - x),
132,975✔
1224
                             depth, error,
44,325✔
1225
                             row0_num[i], row0_den[i]);
132,975✔
1226
    }
44,325✔
1227
    if (y < height - 1) {
67,500✔
1228
        int row;
1229

1230
        row = pos + width;
66,600✔
1231
        for (i = 0; i < 5; ++i) {
399,600✔
1232
            int neighbor;
1233

1234
            neighbor = x + sign * row1_offsets[i];
333,000✔
1235
            if (neighbor < 0 || neighbor >= width) {
333,000✔
1236
                continue;
3,996✔
1237
            }
1238
            error_diffuse_normal(data,
438,672✔
1239
                                 row + (neighbor - x),
329,004✔
1240
                                 depth, error,
109,668✔
1241
                                 row1_num[i], row1_den[i]);
329,004✔
1242
        }
109,668✔
1243
    }
22,200✔
1244
}
67,500✔
1245

1246
static void
NEW
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

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

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

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

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

1300
static void
NEW
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

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

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

1348

1349
static void
NEW
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

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

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

1399

1400
static void
NEW
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

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

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

1465

1466
static void
NEW
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

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

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

1529

1530
static void
NEW
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

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

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

1595

1596
static void
NEW
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

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

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