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

saitoha / libsixel / 19490171609

19 Nov 2025 04:48AM UTC coverage: 39.633% (-2.0%) from 41.622%
19490171609

push

github

saitoha
feat: add new pixelformat SIXEL_PIXELFORMAT_LINEARRGBFLOAT32/SIXEL_PIXELFORMAT_OKLABFLOAT32

8885 of 32084 branches covered (27.69%)

77 of 868 new or added lines in 14 files covered. (8.87%)

197 existing lines in 20 files now uncovered.

11758 of 29667 relevant lines covered (39.63%)

669587.84 hits per line

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

0.0
/src/dither-positional-float32.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
12
 * all 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
#if HAVE_MATH_H
26
# include <math.h>
27
#endif  /* HAVE_MATH_H */
28
#include <string.h>
29

30
#include "dither-positional-float32.h"
31
#include "dither-common-pipeline.h"
32
#include "pixelformat.h"
33

34
static void
35
sixel_dither_scanline_params(int serpentine,
×
36
                             int index,
37
                             int limit,
38
                             int *start,
39
                             int *end,
40
                             int *step,
41
                             int *direction)
42
{
43
    if (serpentine && (index & 1)) {
×
44
        *start = limit - 1;
×
45
        *end = -1;
×
46
        *step = -1;
×
47
        *direction = -1;
×
48
    } else {
49
        *start = 0;
×
50
        *end = limit;
×
51
        *step = 1;
×
52
        *direction = 1;
×
53
    }
54
}
×
55

56
static float
57
mask_a(int x, int y, int c)
×
58
{
59
    return ((((x + c * 67) + y * 236) * 119) & 255) / 128.0f - 1.0f;
×
60
}
61

62
static float
63
mask_x(int x, int y, int c)
×
64
{
65
    return ((((x + c * 29) ^ (y * 149)) * 1234) & 511) / 256.0f - 1.0f;
×
66
}
67

68
SIXELSTATUS
69
sixel_dither_apply_positional_float32(sixel_dither_t *dither,
×
70
                                      sixel_dither_context_t *context)
UNCOV
71
{
×
72
#if _MSC_VER
73
    enum { max_channels = 4 };
74
#else
NEW
75
    const int max_channels = 4;
×
76
#endif
77
    int serpentine;
78
    int y;
79
    float (*f_mask)(int x, int y, int c);
80
    float jitter_scale;
81
    float *palette_float;
82
    float *new_palette_float;
83
    int float_depth;
84
    int float_index;
85
    unsigned char *quantized;
NEW
86
    float lookup_pixel_float[max_channels];
×
87
    unsigned char const *lookup_pixel;
88
    int lookup_wants_float;
89
    int use_palette_float_lookup;
90
    int need_float_pixel;
91

92
    palette_float = NULL;
×
93
    new_palette_float = NULL;
×
94
    float_depth = 0;
×
NEW
95
    quantized = NULL;
×
NEW
96
    lookup_wants_float = 0;
×
97

98
    if (dither == NULL || context == NULL) {
×
99
        return SIXEL_BAD_ARGUMENT;
×
100
    }
101
    if (context->pixels_float == NULL || context->scratch == NULL) {
×
102
        return SIXEL_BAD_ARGUMENT;
×
103
    }
104
    if (context->palette == NULL || context->result == NULL) {
×
105
        return SIXEL_BAD_ARGUMENT;
×
106
    }
107

108
    switch (context->method_for_diffuse) {
×
UNCOV
109
    case SIXEL_DIFFUSE_A_DITHER:
×
110
        f_mask = mask_a;
×
111
        break;
×
112
    case SIXEL_DIFFUSE_X_DITHER:
×
113
    default:
114
        f_mask = mask_x;
×
115
        break;
×
116
    }
117

118
    serpentine = (context->method_for_scan == SIXEL_SCAN_SERPENTINE);
×
119
    jitter_scale = 32.0f / 255.0f;
×
120
    palette_float = context->palette_float;
×
121
    new_palette_float = context->new_palette_float;
×
122
    float_depth = context->float_depth;
×
NEW
123
    quantized = context->scratch;
×
NEW
124
    lookup_wants_float = (context->lookup_source_is_float != 0);
×
NEW
125
    use_palette_float_lookup = 0;
×
NEW
126
    if (context->prefer_palette_float_lookup != 0
×
NEW
127
            && palette_float != NULL
×
NEW
128
            && float_depth >= context->depth) {
×
NEW
129
        use_palette_float_lookup = 1;
×
130
    }
NEW
131
    need_float_pixel = lookup_wants_float || use_palette_float_lookup;
×
132

133
    if (context->optimize_palette) {
×
134
        int x;
135

136
        *context->ncolors = 0;
×
137
        memset(context->new_palette, 0x00,
×
UNCOV
138
               (size_t)SIXEL_PALETTE_MAX * (size_t)context->depth);
×
139
        if (new_palette_float != NULL && float_depth > 0) {
×
140
            memset(new_palette_float, 0x00,
×
141
                   (size_t)SIXEL_PALETTE_MAX
UNCOV
142
                       * (size_t)float_depth * sizeof(float));
×
143
        }
144
        memset(context->migration_map, 0x00,
×
145
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
146
        for (y = 0; y < context->height; ++y) {
×
147
            int start;
148
            int end;
149
            int step;
150
            int direction;
151

152
            sixel_dither_scanline_params(serpentine, y, context->width,
×
153
                                         &start, &end, &step, &direction);
154
            (void)direction;
155
            for (x = start; x != end; x += step) {
×
156
                int pos;
157
                int d;
158
                int color_index;
159

160
                pos = y * context->width + x;
×
161
                for (d = 0; d < context->depth; ++d) {
×
162
                    float val;
163

164
                    val = context->pixels_float[pos * context->depth + d]
×
165
                        + f_mask(x, y, d) * jitter_scale;
×
NEW
166
                    val = sixel_pixelformat_float_channel_clamp(
×
167
                        context->pixelformat,
168
                        d,
169
                        val);
NEW
170
                    if (need_float_pixel) {
×
NEW
171
                        lookup_pixel_float[d] = val;
×
172
                    }
NEW
173
                    if (!lookup_wants_float && !use_palette_float_lookup) {
×
NEW
174
                        quantized[d]
×
NEW
175
                            = sixel_pixelformat_float_channel_to_byte(
×
176
                                  context->pixelformat,
177
                                  d,
178
                                  val);
179
                    }
180
                }
NEW
181
                if (lookup_wants_float) {
×
NEW
182
                    lookup_pixel = (unsigned char const *)(void const *)
×
183
                        lookup_pixel_float;
NEW
184
                    color_index = context->lookup(lookup_pixel,
×
185
                                                  context->depth,
NEW
186
                                                  context->palette,
×
187
                                                  context->reqcolor,
188
                                                  context->indextable,
189
                                                  context->complexion);
NEW
190
                } else if (use_palette_float_lookup) {
×
NEW
191
                    color_index = sixel_dither_lookup_palette_float32(
×
192
                        lookup_pixel_float,
193
                        context->depth,
194
                        palette_float,
195
                        context->reqcolor,
196
                        context->complexion);
197
                } else {
NEW
198
                    lookup_pixel = quantized;
×
NEW
199
                    color_index = context->lookup(lookup_pixel,
×
200
                                                  context->depth,
NEW
201
                                                  context->palette,
×
202
                                                  context->reqcolor,
203
                                                  context->indextable,
204
                                                  context->complexion);
205
                }
206
                if (context->migration_map[color_index] == 0) {
×
UNCOV
207
                    context->result[pos] = *context->ncolors;
×
208
                    for (d = 0; d < context->depth; ++d) {
×
209
                        context->new_palette[*context->ncolors
×
210
                                             * context->depth + d]
×
211
                            = context->palette[color_index
×
212
                                               * context->depth + d];
×
213
                    }
214
                    if (palette_float != NULL
×
215
                            && new_palette_float != NULL
×
216
                            && float_depth > 0) {
×
217
                        for (float_index = 0;
×
218
                                float_index < float_depth;
×
219
                                ++float_index) {
×
220
                            new_palette_float[*context->ncolors
×
221
                                               * float_depth
×
222
                                               + float_index]
×
223
                                = palette_float[color_index * float_depth
×
224
                                                + float_index];
×
225
                        }
226
                    }
227
                    ++*context->ncolors;
×
228
                    context->migration_map[color_index] = *context->ncolors;
×
229
                } else {
230
                    context->result[pos] =
×
231
                        context->migration_map[color_index] - 1;
×
232
                }
233
            }
234
            sixel_dither_pipeline_row_notify(dither, y);
×
235
        }
236
        memcpy(context->palette, context->new_palette,
×
UNCOV
237
               (size_t)(*context->ncolors * context->depth));
×
238
        if (palette_float != NULL
×
239
                && new_palette_float != NULL
×
240
                && float_depth > 0) {
×
241
            memcpy(palette_float,
×
242
                   new_palette_float,
UNCOV
243
                   (size_t)(*context->ncolors * float_depth)
×
244
                       * sizeof(float));
245
        }
246
    } else {
247
        int x;
248

249
        for (y = 0; y < context->height; ++y) {
×
250
            int start;
251
            int end;
252
            int step;
253
            int direction;
254

255
            sixel_dither_scanline_params(serpentine, y, context->width,
×
256
                                         &start, &end, &step, &direction);
257
            (void)direction;
258
            for (x = start; x != end; x += step) {
×
259
                int pos;
260
                int d;
261

262
                pos = y * context->width + x;
×
263
                for (d = 0; d < context->depth; ++d) {
×
264
                    float val;
265

266
                    val = context->pixels_float[pos * context->depth + d]
×
267
                        + f_mask(x, y, d) * jitter_scale;
×
NEW
268
                    val = sixel_pixelformat_float_channel_clamp(
×
269
                        context->pixelformat,
270
                        d,
271
                        val);
NEW
272
                    if (need_float_pixel) {
×
NEW
273
                        lookup_pixel_float[d] = val;
×
274
                    }
NEW
275
                    if (!lookup_wants_float && !use_palette_float_lookup) {
×
NEW
276
                        quantized[d]
×
NEW
277
                            = sixel_pixelformat_float_channel_to_byte(
×
278
                                  context->pixelformat,
279
                                  d,
280
                                  val);
281
                    }
282
                }
NEW
283
                if (lookup_wants_float) {
×
NEW
284
                    lookup_pixel = (unsigned char const *)(void const *)
×
285
                        lookup_pixel_float;
NEW
286
                    context->result[pos] = context->lookup(
×
287
                        lookup_pixel,
288
                        context->depth,
NEW
289
                        context->palette,
×
290
                        context->reqcolor,
291
                        context->indextable,
292
                        context->complexion);
NEW
293
                } else if (use_palette_float_lookup) {
×
NEW
294
                    context->result[pos] =
×
NEW
295
                        sixel_dither_lookup_palette_float32(
×
296
                            lookup_pixel_float,
297
                            context->depth,
298
                            palette_float,
299
                            context->reqcolor,
300
                            context->complexion);
301
                } else {
NEW
302
                    lookup_pixel = quantized;
×
NEW
303
                    context->result[pos] = context->lookup(
×
304
                        lookup_pixel,
305
                        context->depth,
NEW
306
                        context->palette,
×
307
                        context->reqcolor,
308
                        context->indextable,
309
                        context->complexion);
310
                }
311
            }
UNCOV
312
            sixel_dither_pipeline_row_notify(dither, y);
×
313
        }
314
        *context->ncolors = context->reqcolor;
×
315
    }
316

317
    return SIXEL_OK;
×
318
}
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