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

saitoha / libsixel / 21352218274

26 Jan 2026 09:13AM UTC coverage: 76.071% (+0.02%) from 76.048%
21352218274

push

github

saitoha
tests: accept mapped img2sixel exit codes

20865 of 44891 branches covered (46.48%)

36477 of 47951 relevant lines covered (76.07%)

19455207.94 hits per line

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

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

25
#if defined(HAVE_CONFIG_H)
26
#include "config.h"
27
#endif
28

29
#if HAVE_MATH_H
30
# include <math.h>
31
#endif  /* HAVE_MATH_H */
32
#include <ctype.h>
33
#include <limits.h>
34
#include <stdlib.h>
35
#include <string.h>
36

37
#include "compat_stub.h"
38
#include "dither-positional-float32.h"
39
#include "dither-common-pipeline.h"
40
#include "pixelformat.h"
41
#include "lookup-common.h"
42
#include "bluenoise_64x64.h"
43

44
static void
45
sixel_dither_scanline_params_positional_float32(int serpentine,
8,224✔
46
                             int index,
47
                             int limit,
48
                             int *start,
49
                             int *end,
50
                             int *step,
51
                             int *direction)
52
{
53
    if (serpentine && (index & 1)) {
7,840!
54
        *start = limit - 1;
3,600✔
55
        *end = -1;
3,600✔
56
        *step = -1;
3,600✔
57
        *direction = -1;
3,600✔
58
    } else {
1,575✔
59
        *start = 0;
2,890✔
60
        *end = limit;
2,890✔
61
        *step = 1;
2,890✔
62
        *direction = 1;
5,974✔
63
    }
64
}
5,140✔
65

66
/*
67
 * Cache SIXEL_DITHER_*_DITHER_STRENGTH for positional arithmetic dithers to
68
 * avoid getenv() in inner loops. Invalid values fall back to defaults.
69
 */
70
static float g_sixel_pos_strength_a_float32 = 0.150f;
71
static float g_sixel_pos_strength_x_float32 = 0.100f;
72
static int g_sixel_pos_inited_float32 = 0;
73

74
static void sixel_positional_strength_init_float32(void);
75
static float positional_mask_blue_float32(int x, int y, int c);
76

77
static float
78
positional_mask_a_float32(int x, int y, int c)
196,608✔
79
{
80
    sixel_positional_strength_init_float32();
196,608✔
81
    return (((((x + c * 67) + y * 236) * 119) & 255) / 128.0f
282,624✔
82
            - 1.0f) * g_sixel_pos_strength_a_float32;
196,608✔
83
}
84

85
static float
86
positional_mask_x_float32(int x, int y, int c)
12,960,000✔
87
{
88
    sixel_positional_strength_init_float32();
12,960,000✔
89
    return (((((x + c * 29) ^ (y * 149)) * 1234) & 511) / 256.0f
18,630,000✔
90
            - 1.0f) * g_sixel_pos_strength_x_float32;
12,960,000✔
91
}
92

93
/*
94
 * Keep per-file suffixes so unity builds do not merge identical static
95
 * helper symbols from other positional dither sources.
96
 */
97
typedef struct {
98
    float strength;
99
    int ox;
100
    int oy;
101
    int per_channel;
102
    int size;
103
} sixel_bluenoise_conf_float32_t;
104

105
static sixel_bluenoise_conf_float32_t g_sixel_bn_conf_float32;
106
static int g_sixel_bn_inited_float32 = 0;
107

108
static int
109
sixel_bn_parse_int_float32(char const *text, int *out_value)
×
110
{
111
    char *endptr;
112
    long value;
113

114
    if (text == NULL || text[0] == '\0') {
×
115
        return 0;
116
    }
117

118
    value = strtol(text, &endptr, 10);
×
119
    if (endptr == text || *endptr != '\0') {
×
120
        return 0;
121
    }
122
    if (value > INT_MAX || value < INT_MIN) {
×
123
        return 0;
124
    }
125

126
    *out_value = (int)value;
×
127
    return 1;
×
128
}
129

130
static int
131
sixel_bn_parse_float_float32(char const *text, float *out_value)
×
132
{
133
    char *endptr;
134
    double value;
135

136
    if (text == NULL || text[0] == '\0') {
×
137
        return 0;
138
    }
139

140
    value = strtod(text, &endptr);
×
141
    if (endptr == text || *endptr != '\0') {
×
142
        return 0;
143
    }
144

145
    *out_value = (float)value;
×
146
    return 1;
×
147
}
148

149
static int
150
sixel_bn_parse_phase_float32(char const *text, int *out_ox, int *out_oy)
×
151
{
152
    char *endptr;
153
    char const *comma;
154
    long ox;
155
    long oy;
156

157
    if (text == NULL || text[0] == '\0') {
×
158
        return 0;
159
    }
160

161
    comma = strchr(text, ',');
×
162
    if (comma == NULL) {
×
163
        return 0;
164
    }
165

166
    ox = strtol(text, &endptr, 10);
×
167
    if (endptr == text || endptr != comma) {
×
168
        return 0;
169
    }
170

171
    oy = strtol(comma + 1, &endptr, 10);
×
172
    if (endptr == comma + 1 || *endptr != '\0') {
×
173
        return 0;
174
    }
175
    if (ox > INT_MAX || ox < INT_MIN || oy > INT_MAX || oy < INT_MIN) {
×
176
        return 0;
177
    }
178

179
    *out_ox = (int)ox;
×
180
    *out_oy = (int)oy;
×
181
    return 1;
×
182
}
183

184
static void
185
sixel_positional_strength_init_float32(void)
13,156,608✔
186
{
187
    char const *text;
7,400,592✔
188
    float strength_a;
7,400,592✔
189
    float strength_x;
7,400,592✔
190
    int parsed;
7,400,592✔
191

192
    if (g_sixel_pos_inited_float32 != 0) {
13,156,608✔
193
        return;
13,156,576✔
194
    }
195

196
    /*
197
     * Default strengths are per-dither values. Environment overrides use
198
     * the same parser for consistency and fall back to defaults on error.
199
     */
200
    strength_a = 0.150f;
32✔
201
    text = sixel_compat_getenv("SIXEL_DITHER_A_DITHER_STRENGTH");
32✔
202
    if (text != NULL) {
32!
203
        parsed = sixel_bn_parse_float_float32(text, &strength_a);
×
204
        if (parsed == 0) {
×
205
            strength_a = 0.150f;
×
206
        }
207
    }
208

209
    strength_x = 0.100f;
32✔
210
    text = sixel_compat_getenv("SIXEL_DITHER_X_DITHER_STRENGTH");
32✔
211
    if (text != NULL) {
32!
212
        parsed = sixel_bn_parse_float_float32(text, &strength_x);
×
213
        if (parsed == 0) {
×
214
            strength_x = 0.100f;
×
215
        }
216
    }
217

218
    g_sixel_pos_strength_a_float32 = strength_a;
32✔
219
    g_sixel_pos_strength_x_float32 = strength_x;
32✔
220
    g_sixel_pos_inited_float32 = 1;
32✔
221
}
5,756,016!
222

223
static unsigned int
224
sixel_bn_hash32_float32(unsigned int value)
×
225
{
226
    value += 0x9e3779b9U;
×
227
    value ^= value >> 16;
×
228
    value *= 0x85ebca6bU;
×
229
    value ^= value >> 13;
×
230
    value *= 0xc2b2ae35U;
×
231
    value ^= value >> 16;
×
232
    return value;
×
233
}
234

235
static int
236
sixel_bn_str_equal_nocase_float32(char const *left, char const *right)
×
237
{
238
    unsigned char lc;
239
    unsigned char rc;
240

241
    if (left == NULL || right == NULL) {
×
242
        return 0;
243
    }
244

245
    while (*left != '\0' && *right != '\0') {
×
246
        lc = (unsigned char)tolower((unsigned char)*left);
×
247
        rc = (unsigned char)tolower((unsigned char)*right);
×
248
        if (lc != rc) {
×
249
            return 0;
250
        }
251
        ++left;
×
252
        ++right;
×
253
    }
254

255
    return (*left == '\0' && *right == '\0');
×
256
}
257

258
/*
259
 * Cache bluenoise configuration at first use so we do not hit getenv()
260
 * inside pixel loops. Invalid values fall back to defaults.
261
 */
262
static void
263
sixel_bluenoise_conf_init_from_env_float32(void)
×
264
{
265
    char const *text;
266
    float strength;
267
    int size;
268
    int ox;
269
    int oy;
270
    int seed;
271
    int phase_set;
272
    int parsed;
273
    int per_channel;
274
    unsigned int hash;
275

276
    if (g_sixel_bn_inited_float32 != 0) {
×
277
        return;
×
278
    }
279

280
    strength = 0.055f;
×
281
    text = sixel_compat_getenv("SIXEL_DITHER_BLUENOISE_STRENGTH");
×
282
    if (text != NULL) {
×
283
        parsed = sixel_bn_parse_float_float32(text, &strength);
×
284
        if (parsed == 0) {
×
285
            strength = 0.055f;
×
286
        }
287
    }
288

289
    ox = 0;
×
290
    oy = 0;
×
291
    phase_set = 0;
×
292
    text = sixel_compat_getenv("SIXEL_DITHER_BLUENOISE_PHASE");
×
293
    if (text != NULL) {
×
294
        phase_set = 1;
×
295
        parsed = sixel_bn_parse_phase_float32(text, &ox, &oy);
×
296
        if (parsed == 0) {
×
297
            ox = 0;
×
298
            oy = 0;
×
299
        }
300
    }
301
    if (phase_set == 0) {
×
302
        text = sixel_compat_getenv("SIXEL_DITHER_BLUENOISE_SEED");
×
303
        if (text != NULL) {
×
304
            parsed = sixel_bn_parse_int_float32(text, &seed);
×
305
            if (parsed != 0) {
×
306
                hash = sixel_bn_hash32_float32((unsigned int)seed);
×
307
                ox = (int)(hash & 63U);
×
308
                oy = (int)((hash >> 8) & 63U);
×
309
            }
310
        }
311
    }
312

313
    per_channel = 0;
×
314
    text = sixel_compat_getenv("SIXEL_DITHER_BLUENOISE_CHANNEL");
×
315
    if (text != NULL) {
×
316
        if (sixel_bn_str_equal_nocase_float32(text, "rgb") != 0) {
×
317
            per_channel = 1;
318
        } else if (sixel_bn_str_equal_nocase_float32(text, "mono") != 0) {
×
319
            per_channel = 0;
×
320
        }
321
    }
322

323
    size = SIXEL_BN_W;
×
324
    text = sixel_compat_getenv("SIXEL_DITHER_BLUENOISE_SIZE");
×
325
    if (text != NULL) {
×
326
        parsed = sixel_bn_parse_int_float32(text, &size);
×
327
        if (parsed == 0 || size != SIXEL_BN_W) {
×
328
            size = SIXEL_BN_W;
×
329
        }
330
    }
331

332
    g_sixel_bn_conf_float32.strength = strength;
×
333
    g_sixel_bn_conf_float32.ox = ox;
×
334
    g_sixel_bn_conf_float32.oy = oy;
×
335
    g_sixel_bn_conf_float32.per_channel = per_channel;
×
336
    g_sixel_bn_conf_float32.size = size;
×
337
    g_sixel_bn_inited_float32 = 1;
×
338
}
×
339

340
static float
341
sixel_bluenoise_tri_float32(int x, int y, int c)
×
342
{
343
    /* Triangular noise blends two samples from the same tile. */
344
    static int const channel_offset_x[3] = { 17, 34, 51 };
345
    static int const channel_offset_y[3] = { 31, 62, 93 };
346
    int ox;
347
    int oy;
348
    int per_channel;
349
    int channel_x;
350
    int channel_y;
351
    int ix0;
352
    int iy0;
353
    int ix1;
354
    int iy1;
355
    float u;
356
    float v;
357

358
    ox = g_sixel_bn_conf_float32.ox;
×
359
    oy = g_sixel_bn_conf_float32.oy;
×
360
    per_channel = g_sixel_bn_conf_float32.per_channel;
×
361
    channel_x = 0;
×
362
    channel_y = 0;
×
363
    if (per_channel != 0 && c >= 0 && c < 3) {
×
364
        channel_x = channel_offset_x[c];
×
365
        channel_y = channel_offset_y[c];
×
366
    }
367

368
    ix0 = x + ox + channel_x;
×
369
    iy0 = y + oy + channel_y;
×
370
    ix1 = ix0 + 13;
×
371
    iy1 = iy0 + 29;
×
372
    u = (sixel_bn_mask(ix0, iy0) + 1.0f) * 0.5f;
×
373
    v = (sixel_bn_mask(ix1, iy1) + 1.0f) * 0.5f;
×
374

375
    return (u + v) - 1.0f;
×
376
}
377

378
static float
379
positional_mask_blue_float32(int x, int y, int c)
×
380
{
381
    sixel_bluenoise_conf_init_from_env_float32();
×
382
    return sixel_bluenoise_tri_float32(x, y, c)
×
383
        * g_sixel_bn_conf_float32.strength;
×
384
}
385

386
SIXELSTATUS
387
sixel_dither_apply_positional_float32(sixel_dither_t *dither,
32✔
388
                                      sixel_dither_context_t *context)
389
{
18✔
390
#if _MSC_VER
391
    enum { max_channels = 4 };
392
#else
393
    const int max_channels = 4;
32✔
394
#endif
395
    int serpentine;
18✔
396
    int y;
18✔
397
    int absolute_y;
18✔
398
    float (*f_mask)(int x, int y, int c);
18✔
399
    float jitter_scale;
18✔
400
    float *palette_float;
18✔
401
    float *new_palette_float;
18✔
402
    int float_depth;
18✔
403
    int float_index;
18✔
404
    unsigned char *quantized;
18✔
405
    float lookup_pixel_float[max_channels];
32✔
406
    unsigned char const *lookup_pixel;
18✔
407
    sixel_lut_t *fast_lut;
18✔
408
    int use_fast_lut;
18✔
409
    int lookup_wants_float;
18✔
410
    int use_palette_float_lookup;
18✔
411
    int need_float_pixel;
18✔
412

413
    palette_float = NULL;
32✔
414
    new_palette_float = NULL;
32✔
415
    float_depth = 0;
32✔
416
    quantized = NULL;
32✔
417
    lookup_wants_float = 0;
32✔
418

419
    if (dither == NULL || context == NULL) {
32!
420
        return SIXEL_BAD_ARGUMENT;
421
    }
422
    if (context->pixels_float == NULL || context->scratch == NULL) {
32!
423
        return SIXEL_BAD_ARGUMENT;
424
    }
425
    if (context->palette == NULL || context->result == NULL) {
32!
426
        return SIXEL_BAD_ARGUMENT;
427
    }
428

429
    switch (context->method_for_diffuse) {
32!
430
    case SIXEL_DIFFUSE_A_DITHER:
3✔
431
        f_mask = positional_mask_a_float32;
10✔
432
        break;
10✔
433
    case SIXEL_DIFFUSE_X_DITHER:
3✔
434
        f_mask = positional_mask_x_float32;
16✔
435
        break;
10✔
436
    case SIXEL_DIFFUSE_BLUENOISE_DITHER:
437
        f_mask = positional_mask_blue_float32;
×
438
        break;
×
439
    default:
440
        f_mask = positional_mask_x_float32;
6✔
441
        break;
442
    }
443

444
    serpentine = (context->method_for_scan == SIXEL_SCAN_SERPENTINE);
32✔
445
    jitter_scale = 32.0f / 255.0f;
32✔
446
    palette_float = context->palette_float;
32✔
447
    new_palette_float = context->new_palette_float;
32✔
448
    float_depth = context->float_depth;
32✔
449
    quantized = context->scratch;
32✔
450
    fast_lut = context->lut;
32✔
451
    use_fast_lut = (fast_lut != NULL);
32✔
452
    lookup_wants_float = (context->lookup_source_is_float != 0);
32✔
453
    use_palette_float_lookup = 0;
32✔
454
    if (context->prefer_palette_float_lookup != 0
32!
455
            && palette_float != NULL
14!
456
            && float_depth >= context->depth) {
×
457
        use_palette_float_lookup = 1;
12✔
458
    }
459
    need_float_pixel = lookup_wants_float || use_palette_float_lookup;
32!
460

461
    if (context->optimize_palette) {
32!
462
        int x;
18✔
463

464
        *context->ncolors = 0;
32✔
465
        memset(context->new_palette, 0x00,
34✔
466
               (size_t)SIXEL_PALETTE_MAX * (size_t)context->depth);
20!
467
        if (new_palette_float != NULL && float_depth > 0) {
32!
468
            memset(new_palette_float, 0x00,
×
469
                   (size_t)SIXEL_PALETTE_MAX
470
                       * (size_t)float_depth * sizeof(float));
471
        }
472
        memset(context->migration_map, 0x00,
32✔
473
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
474
        for (y = 0; y < context->height; ++y) {
8,256✔
475
            absolute_y = context->band_origin + y;
8,224✔
476
            int start;
4,626✔
477
            int end;
4,626✔
478
            int step;
4,626✔
479
            int direction;
4,626✔
480

481
            sixel_dither_scanline_params_positional_float32(serpentine, absolute_y,
11,822✔
482
                                         context->width,
3,598✔
483
                                         &start, &end, &step, &direction);
484
            (void)direction;
6,682✔
485
            for (x = start; x != end; x += step) {
4,393,760✔
486
                int pos;
2,466,864✔
487
                int d;
2,466,864✔
488
                int color_index;
2,466,864✔
489

490
                pos = y * context->width + x;
4,385,536✔
491
                for (d = 0; d < context->depth; ++d) {
17,542,144✔
492
                    float val;
7,400,592✔
493

494
                    val = context->pixels_float[pos * context->depth + d]
26,313,216✔
495
                        + f_mask(x, y, d) * jitter_scale;
13,156,608✔
496
                    val = sixel_pixelformat_float_channel_clamp(
13,156,608✔
497
                        context->pixelformat,
5,756,016✔
498
                        d,
5,756,016✔
499
                        val);
5,756,016✔
500
                    if (need_float_pixel) {
13,156,608!
501
                        lookup_pixel_float[d] = val;
13,156,608✔
502
                    }
5,756,016✔
503
                    if (!lookup_wants_float && !use_palette_float_lookup) {
13,156,608!
504
                        quantized[d]
×
505
                            = sixel_pixelformat_float_channel_to_byte(
×
506
                                  context->pixelformat,
507
                                  d,
508
                                  val);
509
                    }
510
                }
5,756,016✔
511
                if (lookup_wants_float) {
4,385,536!
512
                    lookup_pixel = (unsigned char const *)(void const *)
4,385,536✔
513
                        lookup_pixel_float;
514
                    if (use_fast_lut) {
4,385,536!
515
                        color_index = sixel_lut_map_pixel(fast_lut,
6,304,208✔
516
                                                         lookup_pixel);
1,918,672✔
517
                    } else {
1,918,672✔
518
                        color_index = context->lookup(lookup_pixel,
×
519
                                                      context->depth,
520
                                                      context->palette,
×
521
                                                      context->reqcolor,
522
                                                      context->indextable,
523
                                                      context->complexion);
524
                    }
525
                } else if (use_palette_float_lookup) {
1,918,672!
526
                    color_index = sixel_dither_lookup_palette_float32(
×
527
                        lookup_pixel_float,
528
                        context->depth,
529
                        palette_float,
530
                        context->reqcolor,
531
                        context->complexion,
532
                        0);
533
                } else {
534
                    lookup_pixel = quantized;
×
535
                    if (use_fast_lut) {
×
536
                        color_index = sixel_lut_map_pixel(fast_lut,
×
537
                                                         lookup_pixel);
538
                    } else {
539
                        color_index = context->lookup(lookup_pixel,
×
540
                                                      context->depth,
541
                                                      context->palette,
×
542
                                                      context->reqcolor,
543
                                                      context->indextable,
544
                                                      context->complexion);
545
                    }
546
                }
547
                if (context->migration_map[color_index] == 0) {
4,385,536✔
548
                    if (absolute_y >= context->output_start) {
4,170!
549
                        /*
550
                         * Palette indices never exceed SIXEL_PALETTE_MAX, so
551
                         * the cast to sixel_index_t (unsigned char) is safe.
552
                         */
553
                        context->result[pos]
4,170✔
554
                            = (sixel_index_t)(*context->ncolors);
6,006✔
555
                    }
1,836✔
556
                    for (d = 0; d < context->depth; ++d) {
16,680✔
557
                        context->new_palette[*context->ncolors
18,018✔
558
                                             * context->depth + d]
12,510✔
559
                            = context->palette[color_index
23,526✔
560
                                               * context->depth + d];
12,510✔
561
                    }
5,508✔
562
                    if (palette_float != NULL
4,170!
563
                            && new_palette_float != NULL
3,396!
564
                            && float_depth > 0) {
×
565
                        for (float_index = 0;
×
566
                                float_index < float_depth;
×
567
                                ++float_index) {
×
568
                            new_palette_float[*context->ncolors
×
569
                                               * float_depth
×
570
                                               + float_index]
×
571
                                = palette_float[color_index * float_depth
×
572
                                                + float_index];
×
573
                        }
574
                    }
575
                    ++*context->ncolors;
4,170✔
576
                    /*
577
                     * Migration map entries are limited to the palette size
578
                     * (<= 256), so storing them as unsigned short is safe.
579
                     */
580
                    context->migration_map[color_index]
4,170✔
581
                        = (unsigned short)(*context->ncolors);
6,006✔
582
                } else {
1,836✔
583
                    if (absolute_y >= context->output_start) {
4,381,366!
584
                        context->result[pos]
4,381,366✔
585
                            = (sixel_index_t)(context->migration_map[
10,131,874✔
586
                                  color_index] - 1);
3,833,672✔
587
                    }
1,916,836✔
588
                }
589
            }
1,918,672✔
590
            if (absolute_y >= context->output_start) {
8,224!
591
                sixel_dither_pipeline_row_notify(dither, absolute_y);
8,224✔
592
            }
3,598✔
593
        }
3,598✔
594
        memcpy(context->palette, context->new_palette,
34✔
595
               (size_t)(*context->ncolors * context->depth));
20!
596
        if (palette_float != NULL
32!
597
                && new_palette_float != NULL
26!
598
                && float_depth > 0) {
×
599
            memcpy(palette_float,
×
600
                   new_palette_float,
601
                   (size_t)(*context->ncolors * float_depth)
602
                       * sizeof(float));
603
        }
604
    } else {
14✔
605
        int x;
606

607
        for (y = 0; y < context->height; ++y) {
×
608
            absolute_y = context->band_origin + y;
×
609
            int start;
610
            int end;
611
            int step;
612
            int direction;
613

614
            sixel_dither_scanline_params_positional_float32(serpentine, absolute_y,
×
615
                                         context->width,
616
                                         &start, &end, &step, &direction);
617
            (void)direction;
618
            for (x = start; x != end; x += step) {
×
619
                int pos;
620
                int d;
621

622
                pos = y * context->width + x;
×
623
                for (d = 0; d < context->depth; ++d) {
×
624
                    float val;
625

626
                    val = context->pixels_float[pos * context->depth + d]
×
627
                        + f_mask(x, y, d) * jitter_scale;
×
628
                    val = sixel_pixelformat_float_channel_clamp(
×
629
                        context->pixelformat,
630
                        d,
631
                        val);
632
                    if (need_float_pixel) {
×
633
                        lookup_pixel_float[d] = val;
×
634
                    }
635
                    if (!lookup_wants_float && !use_palette_float_lookup) {
×
636
                        quantized[d]
×
637
                            = sixel_pixelformat_float_channel_to_byte(
×
638
                                  context->pixelformat,
639
                                  d,
640
                                  val);
641
                    }
642
                }
643
                if (absolute_y >= context->output_start) {
×
644
                    /*
645
                     * Palette indices never exceed SIXEL_PALETTE_MAX, so
646
                     * narrowing to sixel_index_t (unsigned char) is safe.
647
                     */
648
                    if (lookup_wants_float) {
×
649
                        lookup_pixel = (unsigned char const *)(void const *)
×
650
                            lookup_pixel_float;
651
                        context->result[pos] = (sixel_index_t)
×
652
                            context->lookup(
×
653
                                lookup_pixel,
654
                                context->depth,
655
                                context->palette,
×
656
                                context->reqcolor,
657
                                context->indextable,
658
                                context->complexion);
659
                    } else if (use_palette_float_lookup) {
×
660
                        context->result[pos] = (sixel_index_t)
×
661
                            sixel_dither_lookup_palette_float32(
×
662
                                lookup_pixel_float,
663
                                context->depth,
664
                                palette_float,
665
                                context->reqcolor,
666
                                context->complexion,
667
                                0);
668
                    } else {
669
                        lookup_pixel = quantized;
×
670
                        context->result[pos] = (sixel_index_t)
×
671
                            context->lookup(
×
672
                                lookup_pixel,
673
                                context->depth,
674
                                context->palette,
×
675
                                context->reqcolor,
676
                                context->indextable,
677
                                context->complexion);
678
                    }
679
                }
680
            }
681
            if (absolute_y >= context->output_start) {
×
682
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
683
            }
684
        }
685
        *context->ncolors = context->reqcolor;
×
686
    }
687

688
    return SIXEL_OK;
20✔
689
}
14✔
690

691
/* emacs Local Variables:      */
692
/* emacs mode: c               */
693
/* emacs tab-width: 4          */
694
/* emacs indent-tabs-mode: nil */
695
/* emacs c-basic-offset: 4     */
696
/* emacs End:                  */
697
/* vim: set expandtab ts=4 sts=4 sw=4 : */
698
/* 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