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

saitoha / libsixel / 20466639304

23 Dec 2025 04:53PM UTC coverage: 51.46% (-6.3%) from 57.773%
20466639304

push

github

saitoha
build: fix windows find path in images meson build

14511 of 44933 branches covered (32.29%)

21089 of 40981 relevant lines covered (51.46%)

3915123.44 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_positional_float32(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
positional_mask_a_float32(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
positional_mask_x_float32(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 = positional_mask_a_float32;
117
        break;
118
    case SIXEL_DIFFUSE_X_DITHER:
×
119
    default:
120
        f_mask = positional_mask_x_float32;
×
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_positional_float32(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
                        /*
229
                         * Palette indices never exceed SIXEL_PALETTE_MAX, so
230
                         * the cast to sixel_index_t (unsigned char) is safe.
231
                         */
232
                        context->result[pos]
×
233
                            = (sixel_index_t)(*context->ncolors);
×
234
                    }
235
                    for (d = 0; d < context->depth; ++d) {
×
236
                        context->new_palette[*context->ncolors
×
237
                                             * context->depth + d]
×
238
                            = context->palette[color_index
×
239
                                               * context->depth + d];
×
240
                    }
241
                    if (palette_float != NULL
×
242
                            && new_palette_float != NULL
×
243
                            && float_depth > 0) {
×
244
                        for (float_index = 0;
×
245
                                float_index < float_depth;
×
246
                                ++float_index) {
×
247
                            new_palette_float[*context->ncolors
×
248
                                               * float_depth
×
249
                                               + float_index]
×
250
                                = palette_float[color_index * float_depth
×
251
                                                + float_index];
×
252
                        }
253
                    }
254
                    ++*context->ncolors;
×
255
                    /*
256
                     * Migration map entries are limited to the palette size
257
                     * (<= 256), so storing them as unsigned short is safe.
258
                     */
259
                    context->migration_map[color_index]
×
260
                        = (unsigned short)(*context->ncolors);
×
261
                } else {
262
                    if (absolute_y >= context->output_start) {
×
263
                        context->result[pos]
×
264
                            = (sixel_index_t)(context->migration_map[
×
265
                                  color_index] - 1);
266
                    }
267
                }
268
            }
269
            if (absolute_y >= context->output_start) {
×
270
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
271
            }
272
        }
273
        memcpy(context->palette, context->new_palette,
×
274
               (size_t)(*context->ncolors * context->depth));
×
275
        if (palette_float != NULL
×
276
                && new_palette_float != NULL
×
277
                && float_depth > 0) {
×
278
            memcpy(palette_float,
×
279
                   new_palette_float,
280
                   (size_t)(*context->ncolors * float_depth)
×
281
                       * sizeof(float));
282
        }
283
    } else {
284
        int x;
285

286
        for (y = 0; y < context->height; ++y) {
×
287
            absolute_y = context->band_origin + y;
×
288
            int start;
×
289
            int end;
×
290
            int step;
×
291
            int direction;
×
292

293
            sixel_dither_scanline_params_positional_float32(serpentine, absolute_y,
×
294
                                         context->width,
295
                                         &start, &end, &step, &direction);
296
            (void)direction;
×
297
            for (x = start; x != end; x += step) {
×
298
                int pos;
×
299
                int d;
×
300

301
                pos = y * context->width + x;
×
302
                for (d = 0; d < context->depth; ++d) {
×
303
                    float val;
×
304

305
                    val = context->pixels_float[pos * context->depth + d]
×
306
                        + f_mask(x, y, d) * jitter_scale;
×
307
                    val = sixel_pixelformat_float_channel_clamp(
×
308
                        context->pixelformat,
309
                        d,
310
                        val);
311
                    if (need_float_pixel) {
×
312
                        lookup_pixel_float[d] = val;
×
313
                    }
314
                    if (!lookup_wants_float && !use_palette_float_lookup) {
×
315
                        quantized[d]
×
316
                            = sixel_pixelformat_float_channel_to_byte(
×
317
                                  context->pixelformat,
318
                                  d,
319
                                  val);
320
                    }
321
                }
322
                if (absolute_y >= context->output_start) {
×
323
                    /*
324
                     * Palette indices never exceed SIXEL_PALETTE_MAX, so
325
                     * narrowing to sixel_index_t (unsigned char) is safe.
326
                     */
327
                    if (lookup_wants_float) {
×
328
                        lookup_pixel = (unsigned char const *)(void const *)
×
329
                            lookup_pixel_float;
330
                        context->result[pos] = (sixel_index_t)
×
331
                            context->lookup(
×
332
                                lookup_pixel,
333
                                context->depth,
334
                                context->palette,
×
335
                                context->reqcolor,
336
                                context->indextable,
337
                                context->complexion);
338
                    } else if (use_palette_float_lookup) {
×
339
                        context->result[pos] = (sixel_index_t)
×
340
                            sixel_dither_lookup_palette_float32(
×
341
                                lookup_pixel_float,
342
                                context->depth,
343
                                palette_float,
344
                                context->reqcolor,
345
                                context->complexion);
346
                    } else {
347
                        lookup_pixel = quantized;
×
348
                        context->result[pos] = (sixel_index_t)
×
349
                            context->lookup(
×
350
                                lookup_pixel,
351
                                context->depth,
352
                                context->palette,
×
353
                                context->reqcolor,
354
                                context->indextable,
355
                                context->complexion);
356
                    }
357
                }
358
            }
359
            if (absolute_y >= context->output_start) {
×
360
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
361
            }
362
        }
363
        *context->ncolors = context->reqcolor;
×
364
    }
365

366
    return SIXEL_OK;
367
}
368

369
/* emacs Local Variables:      */
370
/* emacs mode: c               */
371
/* emacs tab-width: 4          */
372
/* emacs indent-tabs-mode: nil */
373
/* emacs c-basic-offset: 4     */
374
/* emacs End:                  */
375
/* vim: set expandtab ts=4 sts=4 sw=4 : */
376
/* 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