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

saitoha / libsixel / 19460693151

18 Nov 2025 09:18AM UTC coverage: 40.311% (-1.3%) from 41.649%
19460693151

push

github

saitoha
tests: simplify invalid option test

8950 of 31723 branches covered (28.21%)

11828 of 29342 relevant lines covered (40.31%)

674846.97 hits per line

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

0.0
/src/dither-fixed-float32.c
1
#include "config.h"
2

3
#if HAVE_MATH_H
4
# include <math.h>
5
#endif  /* HAVE_MATH_H */
6
#include <string.h>
7

8
#include "dither-fixed-float32.h"
9
#include "dither-common-pipeline.h"
10

11
static unsigned char
12
sixel_dither_float_channel_to_byte(float value)
×
13
{
14
#if HAVE_MATH_H
15
    if (!isfinite(value)) {
×
16
        value = 0.0f;
×
17
    }
18
#endif  /* HAVE_MATH_H */
19

20
    if (value <= 0.0f) {
×
21
        return 0;
×
22
    }
23
    if (value >= 1.0f) {
×
24
        return 255;
×
25
    }
26

27
    return (unsigned char)(value * 255.0f + 0.5f);
×
28
}
29

30
static float
31
sixel_dither_byte_to_float(unsigned char value)
×
32
{
33
    return (float)value / 255.0f;
×
34
}
35

36
static void
37
error_diffuse_float(float *data,
×
38
                    int pos,
39
                    int depth,
40
                    float error,
41
                    int numerator,
42
                    int denominator)
43
{
44
    float *channel;
45
    float delta;
46

47
    channel = data + ((size_t)pos * (size_t)depth);
×
48
    delta = error * ((float)numerator / (float)denominator);
×
49
    *channel += delta;
×
50
    if (*channel < 0.0f) {
×
51
        *channel = 0.0f;
×
52
    } else if (*channel > 1.0f) {
×
53
        *channel = 1.0f;
×
54
    }
55
}
×
56

57
static void
58
sixel_dither_scanline_params(int serpentine,
×
59
                             int index,
60
                             int limit,
61
                             int *start,
62
                             int *end,
63
                             int *step,
64
                             int *direction)
65
{
66
    if (serpentine && (index & 1)) {
×
67
        *start = limit - 1;
×
68
        *end = -1;
×
69
        *step = -1;
×
70
        *direction = -1;
×
71
    } else {
72
        *start = 0;
×
73
        *end = limit;
×
74
        *step = 1;
×
75
        *direction = 1;
×
76
    }
77
}
×
78

79
static void
80
diffuse_fs_float(float *data,
×
81
                 int width,
82
                 int height,
83
                 int x,
84
                 int y,
85
                 int depth,
86
                 float error,
87
                 int direction)
88
{
89
    int pos;
90
    int forward;
91

92
    pos = y * width + x;
×
93
    forward = direction >= 0;
×
94

95
    if (forward) {
×
96
        if (x < width - 1) {
×
97
            error_diffuse_float(data, pos + 1, depth, error, 7, 16);
×
98
        }
99
        if (y < height - 1) {
×
100
            if (x > 0) {
×
101
                error_diffuse_float(data,
×
102
                                    pos + width - 1,
×
103
                                    depth, error, 3, 16);
104
            }
105
            error_diffuse_float(data,
×
106
                                pos + width,
107
                                depth, error, 5, 16);
108
            if (x < width - 1) {
×
109
                error_diffuse_float(data,
×
110
                                    pos + width + 1,
×
111
                                    depth, error, 1, 16);
112
            }
113
        }
114
    } else {
115
        if (x > 0) {
×
116
            error_diffuse_float(data, pos - 1, depth, error, 7, 16);
×
117
        }
118
        if (y < height - 1) {
×
119
            if (x < width - 1) {
×
120
                error_diffuse_float(data,
×
121
                                    pos + width + 1,
×
122
                                    depth, error, 3, 16);
123
            }
124
            error_diffuse_float(data,
×
125
                                pos + width,
126
                                depth, error, 5, 16);
127
            if (x > 0) {
×
128
                error_diffuse_float(data,
×
129
                                    pos + width - 1,
×
130
                                    depth, error, 1, 16);
131
            }
132
        }
133
    }
134
}
×
135

136
#if HAVE_TESTS
137
static int g_sixel_dither_float32_diffusion_hits = 0;
138

139
void
140
sixel_dither_diffusion_tests_reset_float32_hits(void)
×
141
{
142
    g_sixel_dither_float32_diffusion_hits = 0;
×
143
}
×
144

145
int
146
sixel_dither_diffusion_tests_float32_hits(void)
×
147
{
148
    return g_sixel_dither_float32_diffusion_hits;
×
149
}
150

151
#define SIXEL_DITHER_FLOAT32_HIT()                                      \
152
    do {                                                                \
153
        ++g_sixel_dither_float32_diffusion_hits;                        \
154
    } while (0)
155
#else
156
#define SIXEL_DITHER_FLOAT32_HIT()                                      \
157
    do {                                                                \
158
    } while (0)
159
#endif
160

161
SIXELSTATUS
162
sixel_dither_apply_fixed_float32(sixel_dither_t *dither,
×
163
                                 sixel_dither_context_t *context)
164
{
×
165
#if _MSC_VER
166
    enum { max_channels = 4 };
167
#else
168
    const int max_channels = 4;
×
169
#endif
170
    SIXELSTATUS status;
171
    float *palette_float;
172
    float *new_palette_float;
173
    int float_depth;
174
    int serpentine;
175
    int y;
176
    int start;
177
    int end;
178
    int step;
179
    int direction;
180
    int x;
181
    int pos;
182
    size_t base;
183
    float *source_pixel;
184
    unsigned char quantized[max_channels];
×
185
    float snapshot[max_channels];
×
186
    int color_index;
187
    int output_index;
188
    int palette_value;
189
    float palette_value_float;
190
    float error;
191
    int n;
192
    float *data;
193
    unsigned char *palette;
194
    int float_index;
195

196
    palette_float = NULL;
×
197
    new_palette_float = NULL;
×
198
    float_depth = 0;
×
199

200
    if (dither == NULL || context == NULL) {
×
201
        return SIXEL_BAD_ARGUMENT;
×
202
    }
203
    data = context->pixels_float;
×
204
    if (data == NULL || context->palette == NULL) {
×
205
        return SIXEL_BAD_ARGUMENT;
×
206
    }
207
    if (context->result == NULL || context->new_palette == NULL) {
×
208
        return SIXEL_BAD_ARGUMENT;
×
209
    }
210
    if (context->migration_map == NULL || context->ncolors == NULL) {
×
211
        return SIXEL_BAD_ARGUMENT;
×
212
    }
213
    if (context->lookup == NULL) {
×
214
        return SIXEL_BAD_ARGUMENT;
×
215
    }
216

217
    palette = context->palette;
×
218
    palette_float = context->palette_float;
×
219
    new_palette_float = context->new_palette_float;
×
220
    float_depth = context->float_depth;
×
221
    if (context->depth > max_channels || context->depth != 3) {
×
222
        return SIXEL_BAD_ARGUMENT;
×
223
    }
224
    if (context->reqcolor < 1) {
×
225
        return SIXEL_BAD_ARGUMENT;
×
226
    }
227

228
    serpentine = (context->method_for_scan == SIXEL_SCAN_SERPENTINE);
×
229

230
    if (context->optimize_palette) {
×
231
        *context->ncolors = 0;
×
232
        memset(context->new_palette, 0x00,
×
233
               (size_t)SIXEL_PALETTE_MAX * (size_t)context->depth);
×
234
        if (new_palette_float != NULL && float_depth > 0) {
×
235
            memset(new_palette_float, 0x00,
×
236
                   (size_t)SIXEL_PALETTE_MAX
237
                       * (size_t)float_depth * sizeof(float));
×
238
        }
239
        memset(context->migration_map, 0x00,
×
240
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
241
    } else {
242
        *context->ncolors = context->reqcolor;
×
243
    }
244

245
    for (y = 0; y < context->height; ++y) {
×
246
        sixel_dither_scanline_params(serpentine, y, context->width,
×
247
                                     &start, &end, &step, &direction);
248
        for (x = start; x != end; x += step) {
×
249
            pos = y * context->width + x;
×
250
            base = (size_t)pos * (size_t)context->depth;
×
251
            source_pixel = data + base;
×
252

253
            for (n = 0; n < context->depth; ++n) {
×
254
                snapshot[n] = source_pixel[n];
×
255
                quantized[n]
256
                    = sixel_dither_float_channel_to_byte(source_pixel[n]);
×
257
            }
258

259
            color_index = context->lookup(quantized,
×
260
                                          context->depth,
261
                                          palette,
262
                                          context->reqcolor,
263
                                          context->indextable,
264
                                          context->complexion);
265

266
            if (context->optimize_palette) {
×
267
                if (context->migration_map[color_index] == 0) {
×
268
                    output_index = *context->ncolors;
×
269
                    for (n = 0; n < context->depth; ++n) {
×
270
                        context->new_palette[output_index * context->depth + n]
×
271
                            = palette[color_index * context->depth + n];
×
272
                    }
273
                    if (palette_float != NULL
×
274
                            && new_palette_float != NULL
×
275
                            && float_depth > 0) {
×
276
                        for (float_index = 0;
×
277
                                float_index < float_depth;
×
278
                                ++float_index) {
×
279
                            new_palette_float[output_index * float_depth
×
280
                                              + float_index]
×
281
                                = palette_float[color_index * float_depth
×
282
                                                + float_index];
×
283
                        }
284
                    }
285
                    ++*context->ncolors;
×
286
                    context->migration_map[color_index] = *context->ncolors;
×
287
                } else {
288
                    output_index = context->migration_map[color_index] - 1;
×
289
                }
290
                context->result[pos] = output_index;
×
291
            } else {
292
                output_index = color_index;
×
293
                context->result[pos] = output_index;
×
294
            }
295

296
            for (n = 0; n < context->depth; ++n) {
×
297
                if (context->optimize_palette) {
×
298
                    palette_value
299
                        = context->new_palette[output_index
×
300
                                               * context->depth + n];
×
301
                } else {
302
                    palette_value
303
                        = palette[color_index * context->depth + n];
×
304
                }
305
                palette_value_float
306
                    = sixel_dither_byte_to_float((unsigned char)palette_value);
×
307
                error = snapshot[n] - palette_value_float;
×
308
                source_pixel[n] = palette_value_float;
×
309
                diffuse_fs_float(data + (size_t)n,
×
310
                                 context->width,
311
                                 context->height,
312
                                 x,
313
                                 y,
314
                                 context->depth,
315
                                 error,
316
                                 direction);
317
            }
318
        }
319
        sixel_dither_pipeline_row_notify(dither, y);
×
320
    }
321

322
    if (context->optimize_palette) {
×
323
        memcpy(context->palette,
×
324
               context->new_palette,
×
325
               (size_t)(*context->ncolors * context->depth));
×
326
        if (palette_float != NULL
×
327
                && new_palette_float != NULL
×
328
                && float_depth > 0) {
×
329
            memcpy(palette_float,
×
330
                   new_palette_float,
331
                   (size_t)(*context->ncolors * float_depth)
×
332
                       * sizeof(float));
333
        }
334
    }
335

336
    status = SIXEL_OK;
×
337
    SIXEL_DITHER_FLOAT32_HIT();
×
338
    return status;
×
339
}
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