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

saitoha / libsixel / 19934796867

04 Dec 2025 03:42PM UTC coverage: 43.522% (+2.3%) from 41.258%
19934796867

push

github

saitoha
python: update shared api.py

10714 of 38654 branches covered (27.72%)

14673 of 33714 relevant lines covered (43.52%)

2910517.57 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
 * 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
#include "config.h"
26

27
#if HAVE_MATH_H
28
# include <math.h>
29
#endif  /* HAVE_MATH_H */
30
#include <string.h>
31

32
#include "dither-positional-float32.h"
33
#include "dither-common-pipeline.h"
34
#include "pixelformat.h"
35
#include "lookup-common.h"
36

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

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

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

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

98
    palette_float = NULL;
×
99
    new_palette_float = NULL;
×
100
    float_depth = 0;
×
101
    quantized = NULL;
×
102
    lookup_wants_float = 0;
×
103

104
    if (dither == NULL || context == NULL) {
×
105
        return SIXEL_BAD_ARGUMENT;
106
    }
107
    if (context->pixels_float == NULL || context->scratch == NULL) {
×
108
        return SIXEL_BAD_ARGUMENT;
109
    }
110
    if (context->palette == NULL || context->result == NULL) {
×
111
        return SIXEL_BAD_ARGUMENT;
112
    }
113

114
    switch (context->method_for_diffuse) {
×
115
    case SIXEL_DIFFUSE_A_DITHER:
116
        f_mask = mask_a;
117
        break;
118
    case SIXEL_DIFFUSE_X_DITHER:
×
119
    default:
120
        f_mask = mask_x;
×
121
        break;
×
122
    }
123

124
    serpentine = (context->method_for_scan == SIXEL_SCAN_SERPENTINE);
×
125
    jitter_scale = 32.0f / 255.0f;
×
126
    palette_float = context->palette_float;
×
127
    new_palette_float = context->new_palette_float;
×
128
    float_depth = context->float_depth;
×
129
    quantized = context->scratch;
×
130
    fast_lut = context->lut;
×
131
    use_fast_lut = (fast_lut != NULL);
×
132
    lookup_wants_float = (context->lookup_source_is_float != 0);
×
133
    use_palette_float_lookup = 0;
×
134
    if (context->prefer_palette_float_lookup != 0
×
135
            && palette_float != NULL
×
136
            && float_depth >= context->depth) {
×
137
        use_palette_float_lookup = 1;
×
138
    }
139
    need_float_pixel = lookup_wants_float || use_palette_float_lookup;
×
140

141
    if (context->optimize_palette) {
×
142
        int x;
×
143

144
        *context->ncolors = 0;
×
145
        memset(context->new_palette, 0x00,
×
146
               (size_t)SIXEL_PALETTE_MAX * (size_t)context->depth);
×
147
        if (new_palette_float != NULL && float_depth > 0) {
×
148
            memset(new_palette_float, 0x00,
×
149
                   (size_t)SIXEL_PALETTE_MAX
150
                       * (size_t)float_depth * sizeof(float));
×
151
        }
152
        memset(context->migration_map, 0x00,
×
153
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
154
        for (y = 0; y < context->height; ++y) {
×
155
            absolute_y = context->band_origin + y;
×
156
            int start;
×
157
            int end;
×
158
            int step;
×
159
            int direction;
×
160

161
            sixel_dither_scanline_params(serpentine, absolute_y,
×
162
                                         context->width,
163
                                         &start, &end, &step, &direction);
164
            (void)direction;
×
165
            for (x = start; x != end; x += step) {
×
166
                int pos;
×
167
                int d;
×
168
                int color_index;
×
169

170
                pos = y * context->width + x;
×
171
                for (d = 0; d < context->depth; ++d) {
×
172
                    float val;
×
173

174
                    val = context->pixels_float[pos * context->depth + d]
×
175
                        + f_mask(x, y, d) * jitter_scale;
×
176
                    val = sixel_pixelformat_float_channel_clamp(
×
177
                        context->pixelformat,
178
                        d,
179
                        val);
180
                    if (need_float_pixel) {
×
181
                        lookup_pixel_float[d] = val;
×
182
                    }
183
                    if (!lookup_wants_float && !use_palette_float_lookup) {
×
184
                        quantized[d]
×
185
                            = sixel_pixelformat_float_channel_to_byte(
×
186
                                  context->pixelformat,
187
                                  d,
188
                                  val);
189
                    }
190
                }
191
                if (lookup_wants_float) {
×
192
                    lookup_pixel = (unsigned char const *)(void const *)
×
193
                        lookup_pixel_float;
194
                    if (use_fast_lut) {
×
195
                        color_index = sixel_lut_map_pixel(fast_lut,
×
196
                                                         lookup_pixel);
197
                    } else {
198
                        color_index = context->lookup(lookup_pixel,
×
199
                                                      context->depth,
200
                                                      context->palette,
×
201
                                                      context->reqcolor,
202
                                                      context->indextable,
203
                                                      context->complexion);
204
                    }
205
                } else if (use_palette_float_lookup) {
×
206
                    color_index = sixel_dither_lookup_palette_float32(
×
207
                        lookup_pixel_float,
208
                        context->depth,
209
                        palette_float,
210
                        context->reqcolor,
211
                        context->complexion);
212
                } else {
213
                    lookup_pixel = quantized;
×
214
                    if (use_fast_lut) {
×
215
                        color_index = sixel_lut_map_pixel(fast_lut,
×
216
                                                         lookup_pixel);
217
                    } else {
218
                        color_index = context->lookup(lookup_pixel,
×
219
                                                      context->depth,
220
                                                      context->palette,
×
221
                                                      context->reqcolor,
222
                                                      context->indextable,
223
                                                      context->complexion);
224
                    }
225
                }
226
                if (context->migration_map[color_index] == 0) {
×
227
                    if (absolute_y >= context->output_start) {
×
228
                        context->result[pos] = *context->ncolors;
×
229
                    }
230
                    for (d = 0; d < context->depth; ++d) {
×
231
                        context->new_palette[*context->ncolors
×
232
                                             * context->depth + d]
×
233
                            = context->palette[color_index
×
234
                                               * context->depth + d];
×
235
                    }
236
                    if (palette_float != NULL
×
237
                            && new_palette_float != NULL
×
238
                            && float_depth > 0) {
×
239
                        for (float_index = 0;
×
240
                                float_index < float_depth;
×
241
                                ++float_index) {
×
242
                            new_palette_float[*context->ncolors
×
243
                                               * float_depth
×
244
                                               + float_index]
×
245
                                = palette_float[color_index * float_depth
×
246
                                                + float_index];
×
247
                        }
248
                    }
249
                    ++*context->ncolors;
×
250
                    context->migration_map[color_index] = *context->ncolors;
×
251
                } else {
252
                    if (absolute_y >= context->output_start) {
×
253
                        context->result[pos] =
×
254
                            context->migration_map[color_index] - 1;
×
255
                    }
256
                }
257
            }
258
            if (absolute_y >= context->output_start) {
×
259
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
260
            }
261
        }
262
        memcpy(context->palette, context->new_palette,
×
263
               (size_t)(*context->ncolors * context->depth));
×
264
        if (palette_float != NULL
×
265
                && new_palette_float != NULL
×
266
                && float_depth > 0) {
×
267
            memcpy(palette_float,
×
268
                   new_palette_float,
269
                   (size_t)(*context->ncolors * float_depth)
×
270
                       * sizeof(float));
271
        }
272
    } else {
273
        int x;
274

275
        for (y = 0; y < context->height; ++y) {
×
276
            absolute_y = context->band_origin + y;
×
277
            int start;
×
278
            int end;
×
279
            int step;
×
280
            int direction;
×
281

282
            sixel_dither_scanline_params(serpentine, absolute_y,
×
283
                                         context->width,
284
                                         &start, &end, &step, &direction);
285
            (void)direction;
×
286
            for (x = start; x != end; x += step) {
×
287
                int pos;
×
288
                int d;
×
289

290
                pos = y * context->width + x;
×
291
                for (d = 0; d < context->depth; ++d) {
×
292
                    float val;
×
293

294
                    val = context->pixels_float[pos * context->depth + d]
×
295
                        + f_mask(x, y, d) * jitter_scale;
×
296
                    val = sixel_pixelformat_float_channel_clamp(
×
297
                        context->pixelformat,
298
                        d,
299
                        val);
300
                    if (need_float_pixel) {
×
301
                        lookup_pixel_float[d] = val;
×
302
                    }
303
                    if (!lookup_wants_float && !use_palette_float_lookup) {
×
304
                        quantized[d]
×
305
                            = sixel_pixelformat_float_channel_to_byte(
×
306
                                  context->pixelformat,
307
                                  d,
308
                                  val);
309
                    }
310
                }
311
                if (absolute_y >= context->output_start) {
×
312
                    if (lookup_wants_float) {
×
313
                        lookup_pixel = (unsigned char const *)(void const *)
×
314
                            lookup_pixel_float;
315
                        context->result[pos] = context->lookup(
×
316
                            lookup_pixel,
317
                            context->depth,
318
                            context->palette,
×
319
                            context->reqcolor,
320
                            context->indextable,
321
                            context->complexion);
322
                    } else if (use_palette_float_lookup) {
×
323
                        context->result[pos] =
×
324
                            sixel_dither_lookup_palette_float32(
×
325
                                lookup_pixel_float,
326
                                context->depth,
327
                                palette_float,
328
                                context->reqcolor,
329
                                context->complexion);
330
                    } else {
331
                        lookup_pixel = quantized;
×
332
                        context->result[pos] = context->lookup(
×
333
                            lookup_pixel,
334
                            context->depth,
335
                            context->palette,
×
336
                            context->reqcolor,
337
                            context->indextable,
338
                            context->complexion);
339
                    }
340
                }
341
            }
342
            if (absolute_y >= context->output_start) {
×
343
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
344
            }
345
        }
346
        *context->ncolors = context->reqcolor;
×
347
    }
348

349
    return SIXEL_OK;
350
}
351

352
/* emacs Local Variables:      */
353
/* emacs mode: c               */
354
/* emacs tab-width: 4          */
355
/* emacs indent-tabs-mode: nil */
356
/* emacs c-basic-offset: 4     */
357
/* emacs End:                  */
358
/* vim: set expandtab ts=4 sts=4 sw=4 : */
359
/* 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