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

saitoha / libsixel / 19541344273

20 Nov 2025 03:02PM UTC coverage: 40.773% (-0.4%) from 41.21%
19541344273

push

github

saitoha
feat: initial prototyping for parallel dithering

9711 of 33880 branches covered (28.66%)

55 of 483 new or added lines in 10 files covered. (11.39%)

12 existing lines in 4 files now uncovered.

12720 of 31197 relevant lines covered (40.77%)

656879.66 hits per line

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

0.0
/src/dither-positional-8bit.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
#include <string.h>
28

29
#include "dither-positional-8bit.h"
30
#include "dither-common-pipeline.h"
31

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

54
static float mask_a(int x, int y, int c);
55
static float mask_x(int x, int y, int c);
56

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

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

69
SIXELSTATUS
70
sixel_dither_apply_positional_8bit(sixel_dither_t *dither,
×
71
                                   sixel_dither_context_t *context)
72
{
73
    int serpentine;
74
    int y;
75
    int absolute_y;
76
    float *palette_float;
77
    float *new_palette_float;
78
    int float_depth;
79
    int float_index;
80
    float (*f_mask)(int x, int y, int c);
81

82
    palette_float = NULL;
×
83
    new_palette_float = NULL;
×
84
    float_depth = 0;
×
85

86
    if (dither == NULL || context == NULL) {
×
87
        return SIXEL_BAD_ARGUMENT;
×
88
    }
89
    if (context->pixels == NULL || context->palette == NULL) {
×
90
        return SIXEL_BAD_ARGUMENT;
×
91
    }
92
    if (context->result == NULL || context->scratch == NULL) {
×
93
        return SIXEL_BAD_ARGUMENT;
×
94
    }
95

96
    switch (context->method_for_diffuse) {
×
97
    case SIXEL_DIFFUSE_A_DITHER:
×
98
        f_mask = mask_a;
×
99
        break;
×
100
    case SIXEL_DIFFUSE_X_DITHER:
×
101
    default:
102
        f_mask = mask_x;
×
103
        break;
×
104
    }
105

106
    serpentine = (context->method_for_scan == SIXEL_SCAN_SERPENTINE);
×
107
    palette_float = context->palette_float;
×
108
    new_palette_float = context->new_palette_float;
×
109
    float_depth = context->float_depth;
×
110

111
    if (context->optimize_palette) {
×
112
        int x;
113

114
        *context->ncolors = 0;
×
115
        memset(context->new_palette, 0x00,
×
116
               (size_t)SIXEL_PALETTE_MAX * (size_t)context->depth);
×
117
        if (new_palette_float != NULL && float_depth > 0) {
×
118
            memset(new_palette_float, 0x00,
×
119
                   (size_t)SIXEL_PALETTE_MAX
120
                       * (size_t)float_depth * sizeof(float));
×
121
        }
122
        memset(context->migration_map, 0x00,
×
123
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
124
        for (y = 0; y < context->height; ++y) {
×
NEW
125
            absolute_y = context->band_origin + y;
×
126
            int start;
127
            int end;
128
            int step;
129
            int direction;
130

NEW
131
            sixel_dither_scanline_params(serpentine, absolute_y,
×
132
                                         context->width,
133
                                         &start, &end, &step, &direction);
134
            (void)direction;
135
            for (x = start; x != end; x += step) {
×
136
                int pos;
137
                int d;
138
                int color_index;
139

140
                pos = y * context->width + x;
×
141
                for (d = 0; d < context->depth; ++d) {
×
142
                    int val;
143

144
                    val = context->pixels[pos * context->depth + d]
×
145
                        + (int)(f_mask(x, y, d) * 32.0f);
×
146
                    context->scratch[d] = val < 0 ? 0
×
147
                                       : val > 255 ? 255 : val;
×
148
                }
149
                color_index = context->lookup(context->scratch,
×
150
                                              context->depth,
151
                                              context->palette,
×
152
                                              context->reqcolor,
153
                                              context->indextable,
154
                                              context->complexion);
155
                if (context->migration_map[color_index] == 0) {
×
NEW
156
                    if (absolute_y >= context->output_start) {
×
NEW
157
                        context->result[pos] = *context->ncolors;
×
158
                    }
159
                    for (d = 0; d < context->depth; ++d) {
×
160
                        context->new_palette[*context->ncolors
×
161
                                             * context->depth + d]
×
162
                            = context->palette[color_index
×
163
                                               * context->depth + d];
×
164
                    }
165
                    if (palette_float != NULL
×
166
                            && new_palette_float != NULL
×
167
                            && float_depth > 0) {
×
168
                        for (float_index = 0;
×
169
                                float_index < float_depth;
×
170
                                ++float_index) {
×
171
                            new_palette_float[*context->ncolors
×
172
                                               * float_depth
×
173
                                               + float_index]
×
174
                                = palette_float[color_index * float_depth
×
175
                                                + float_index];
×
176
                        }
177
                    }
178
                    ++*context->ncolors;
×
179
                    context->migration_map[color_index] = *context->ncolors;
×
180
                } else {
NEW
181
                    if (absolute_y >= context->output_start) {
×
NEW
182
                        context->result[pos] =
×
NEW
183
                            context->migration_map[color_index] - 1;
×
184
                    }
185
                }
186
            }
NEW
187
            if (absolute_y >= context->output_start) {
×
NEW
188
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
189
            }
190
        }
191
        memcpy(context->palette, context->new_palette,
×
192
               (size_t)(*context->ncolors * context->depth));
×
193
        if (palette_float != NULL
×
194
                && new_palette_float != NULL
×
195
                && float_depth > 0) {
×
196
            memcpy(palette_float,
×
197
                   new_palette_float,
198
                   (size_t)(*context->ncolors * float_depth)
×
199
                       * sizeof(float));
200
        }
201
    } else {
202
        int x;
203

204
        for (y = 0; y < context->height; ++y) {
×
NEW
205
            absolute_y = context->band_origin + y;
×
206
            int start;
207
            int end;
208
            int step;
209
            int direction;
210

NEW
211
            sixel_dither_scanline_params(serpentine, absolute_y,
×
212
                                         context->width,
213
                                         &start, &end, &step, &direction);
214
            (void)direction;
215
            for (x = start; x != end; x += step) {
×
216
                int pos;
217
                int d;
218

219
                pos = y * context->width + x;
×
220
                for (d = 0; d < context->depth; ++d) {
×
221
                    int val;
222

223
                    val = context->pixels[pos * context->depth + d]
×
224
                        + (int)(f_mask(x, y, d) * 32.0f);
×
225
                    context->scratch[d] = val < 0 ? 0
×
226
                                       : val > 255 ? 255 : val;
×
227
                }
NEW
228
                if (absolute_y >= context->output_start) {
×
NEW
229
                    context->result[pos] =
×
NEW
230
                        context->lookup(context->scratch,
×
231
                                        context->depth,
NEW
232
                                        context->palette,
×
233
                                        context->reqcolor,
234
                                        context->indextable,
235
                                        context->complexion);
236
                }
237
            }
NEW
238
            if (absolute_y >= context->output_start) {
×
NEW
239
                sixel_dither_pipeline_row_notify(dither, absolute_y);
×
240
            }
241
        }
UNCOV
242
        *context->ncolors = context->reqcolor;
×
243
    }
244

245
    return SIXEL_OK;
×
246
}
247

248
/* emacs Local Variables:      */
249
/* emacs mode: c               */
250
/* emacs tab-width: 4          */
251
/* emacs indent-tabs-mode: nil */
252
/* emacs c-basic-offset: 4     */
253
/* emacs End:                  */
254
/* vim: set expandtab ts=4 sts=4 sw=4 : */
255
/* 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