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

saitoha / libsixel / 19918707358

04 Dec 2025 05:12AM UTC coverage: 38.402% (-4.0%) from 42.395%
19918707358

push

github

saitoha
tests: fix meson msys dll lookup

9738 of 38220 branches covered (25.48%)

12841 of 33438 relevant lines covered (38.4%)

782420.02 hits per line

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

0.0
/src/dither-varcoeff-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
/*
26
 * Adaptive diffusion backend operating on RGBFLOAT32 buffers.  The worker
27
 * mirrors the 8bit implementation but keeps intermediate values in float so
28
 * rounding happens only at palette lookups.
29
 */
30

31
#include "config.h"
32

33
#include <stdlib.h>
34
#include <string.h>
35

36
#if HAVE_MATH_H
37
# include <math.h>
38
#endif  /* HAVE_MATH_H */
39

40
#include "dither-varcoeff-float32.h"
41
#include "dither-common-pipeline.h"
42
#include "lookup-common.h"
43
#include "pixelformat.h"
44

45
static void
46
sixel_dither_scanline_params(int serpentine,
×
47
                             int index,
48
                             int limit,
49
                             int *start,
50
                             int *end,
51
                             int *step,
52
                             int *direction)
53
{
54
    if (serpentine && (index & 1)) {
×
55
        *start = limit - 1;
×
56
        *end = -1;
×
57
        *step = -1;
×
58
        *direction = -1;
×
59
    } else {
60
        *start = 0;
61
        *end = limit;
62
        *step = 1;
63
        *direction = 1;
64
    }
65
}
66

67
static const int (*
68
lso2_table(void))[7]
×
69
{
70
#include "lso2.h"
71
    return var_coefs;
×
72
}
73

74
typedef void (*diffuse_varerr_mode_float)(float *data,
75
                                          int width,
76
                                          int height,
77
                                          int x,
78
                                          int y,
79
                                          int depth,
80
                                          float error,
81
                                          int index,
82
                                          int direction,
83
                                          int pixelformat,
84
                                          int channel);
85

86
typedef void (*diffuse_varerr_carry_mode_float)(float *carry_curr,
87
                                                 float *carry_next,
88
                                                 float *carry_far,
89
                                                 int width,
90
                                                 int height,
91
                                                 int depth,
92
                                                 int x,
93
                                                 int y,
94
                                                 float error,
95
                                                 int index,
96
                                                 int direction,
97
                                                 int channel);
98

99
static int
100
sixel_varcoeff_safe_denom(int value)
×
101
{
102
    if (value == 0) {
×
103
        return 1;
×
104
    }
105
    return value;
106
}
107

108
static float
109
diffuse_varerr_term_float(float error, int weight, int denom)
×
110
{
111
    float factor;
×
112

113
    factor = (float)weight / (float)denom;
×
114
    return error * factor;
×
115
}
116

117
static void
118
diffuse_varerr_apply_direct_float(float *target,
×
119
                                  int depth,
120
                                  size_t offset,
121
                                  float delta,
122
                                  int pixelformat,
123
                                  int channel)
124
{
125
    size_t index;
×
126

127
    index = offset * (size_t)depth;
×
128
    target[index] += delta;
×
129
    target[index] = sixel_pixelformat_float_channel_clamp(pixelformat,
×
130
                                                          channel,
131
                                                          target[index]);
132
}
×
133

134
static void
135
diffuse_lso2_float(float *data,
×
136
                    int width,
137
                    int height,
138
                    int x,
139
                    int y,
140
                    int depth,
141
                    float error,
142
                    int index,
143
                    int direction,
144
                    int pixelformat,
145
                    int channel)
146
{
147
    const int (*table)[7];
×
148
    const int *entry;
×
149
    int denom;
×
150
    float term_r;
×
151
    float term_r2;
×
152
    float term_dl;
×
153
    float term_d;
×
154
    float term_dr;
×
155
    float term_d2;
×
156
    size_t offset;
×
157

158
    if (error == 0.0f) {
×
159
        return;
160
    }
161
    if (index < 0) {
×
162
        index = 0;
163
    }
164
    if (index > 255) {
×
165
        index = 255;
166
    }
167

168
    table = lso2_table();
×
169
    entry = table[index];
×
170
    denom = sixel_varcoeff_safe_denom(entry[6]);
×
171

172
    term_r = diffuse_varerr_term_float(error, entry[0], denom);
×
173
    term_r2 = diffuse_varerr_term_float(error, entry[1], denom);
×
174
    term_dl = diffuse_varerr_term_float(error, entry[2], denom);
×
175
    term_d = diffuse_varerr_term_float(error, entry[3], denom);
×
176
    term_dr = diffuse_varerr_term_float(error, entry[4], denom);
×
177
    term_d2 = diffuse_varerr_term_float(error, entry[5], denom);
×
178

179
    if (direction >= 0) {
×
180
        if (x + 1 < width) {
×
181
            offset = (size_t)y * (size_t)width + (size_t)(x + 1);
×
182
            diffuse_varerr_apply_direct_float(data,
×
183
                                              depth,
184
                                              offset,
185
                                              term_r,
186
                                              pixelformat,
187
                                              channel);
188
        }
189
        if (x + 2 < width) {
×
190
            offset = (size_t)y * (size_t)width + (size_t)(x + 2);
×
191
            diffuse_varerr_apply_direct_float(data,
×
192
                                              depth,
193
                                              offset,
194
                                              term_r2,
195
                                              pixelformat,
196
                                              channel);
197
        }
198
        if (y + 1 < height && x - 1 >= 0) {
×
199
            offset = (size_t)(y + 1) * (size_t)width;
×
200
            offset += (size_t)(x - 1);
×
201
            diffuse_varerr_apply_direct_float(data,
×
202
                                              depth,
203
                                              offset,
204
                                              term_dl,
205
                                              pixelformat,
206
                                              channel);
207
        }
208
        if (y + 1 < height) {
×
209
            offset = (size_t)(y + 1) * (size_t)width + (size_t)x;
×
210
            diffuse_varerr_apply_direct_float(data,
×
211
                                              depth,
212
                                              offset,
213
                                              term_d,
214
                                              pixelformat,
215
                                              channel);
216
        }
217
        if (y + 1 < height && x + 1 < width) {
×
218
            offset = (size_t)(y + 1) * (size_t)width;
×
219
            offset += (size_t)(x + 1);
×
220
            diffuse_varerr_apply_direct_float(data,
×
221
                                              depth,
222
                                              offset,
223
                                              term_dr,
224
                                              pixelformat,
225
                                              channel);
226
        }
227
        if (y + 2 < height) {
×
228
            offset = (size_t)(y + 2) * (size_t)width + (size_t)x;
×
229
            diffuse_varerr_apply_direct_float(data,
×
230
                                              depth,
231
                                              offset,
232
                                              term_d2,
233
                                              pixelformat,
234
                                              channel);
235
        }
236
    } else {
237
        if (x - 1 >= 0) {
×
238
            offset = (size_t)y * (size_t)width + (size_t)(x - 1);
×
239
            diffuse_varerr_apply_direct_float(data,
×
240
                                              depth,
241
                                              offset,
242
                                              term_r,
243
                                              pixelformat,
244
                                              channel);
245
        }
246
        if (x - 2 >= 0) {
×
247
            offset = (size_t)y * (size_t)width + (size_t)(x - 2);
×
248
            diffuse_varerr_apply_direct_float(data,
×
249
                                              depth,
250
                                              offset,
251
                                              term_r2,
252
                                              pixelformat,
253
                                              channel);
254
        }
255
        if (y + 1 < height && x + 1 < width) {
×
256
            offset = (size_t)(y + 1) * (size_t)width;
×
257
            offset += (size_t)(x + 1);
×
258
            diffuse_varerr_apply_direct_float(data,
×
259
                                              depth,
260
                                              offset,
261
                                              term_dl,
262
                                              pixelformat,
263
                                              channel);
264
        }
265
        if (y + 1 < height) {
×
266
            offset = (size_t)(y + 1) * (size_t)width + (size_t)x;
×
267
            diffuse_varerr_apply_direct_float(data,
×
268
                                              depth,
269
                                              offset,
270
                                              term_d,
271
                                              pixelformat,
272
                                              channel);
273
        }
274
        if (y + 1 < height && x - 1 >= 0) {
×
275
            offset = (size_t)(y + 1) * (size_t)width;
×
276
            offset += (size_t)(x - 1);
×
277
            diffuse_varerr_apply_direct_float(data,
×
278
                                              depth,
279
                                              offset,
280
                                              term_dr,
281
                                              pixelformat,
282
                                              channel);
283
        }
284
        if (y + 2 < height) {
×
285
            offset = (size_t)(y + 2) * (size_t)width + (size_t)x;
×
286
            diffuse_varerr_apply_direct_float(data,
×
287
                                              depth,
288
                                              offset,
289
                                              term_d2,
290
                                              pixelformat,
291
                                              channel);
292
        }
293
    }
294
}
×
295

296
static void
297
diffuse_lso2_carry_float(float *carry_curr,
×
298
                          float *carry_next,
299
                          float *carry_far,
300
                          int width,
301
                          int height,
302
                          int depth,
303
                          int x,
304
                          int y,
305
                          float error,
306
                          int index,
307
                          int direction,
308
                          int channel)
309
{
310
    const int (*table)[7];
×
311
    const int *entry;
×
312
    int denom;
×
313
    float term_r;
×
314
    float term_r2;
×
315
    float term_dl;
×
316
    float term_d;
×
317
    float term_dr;
×
318
    float term_d2;
×
319
    size_t base;
×
320

321
    if (error == 0.0f) {
×
322
        return;
323
    }
324
    if (index < 0) {
×
325
        index = 0;
326
    }
327
    if (index > 255) {
×
328
        index = 255;
329
    }
330

331
    table = lso2_table();
×
332
    entry = table[index];
×
333
    denom = sixel_varcoeff_safe_denom(entry[6]);
×
334

335
    term_r = diffuse_varerr_term_float(error, entry[0], denom);
×
336
    term_r2 = diffuse_varerr_term_float(error, entry[1], denom);
×
337
    term_dl = diffuse_varerr_term_float(error, entry[2], denom);
×
338
    term_d = diffuse_varerr_term_float(error, entry[3], denom);
×
339
    term_dr = diffuse_varerr_term_float(error, entry[4], denom);
×
340
    term_d2 = error - term_r - term_r2 - term_dl - term_d - term_dr;
×
341

342
    if (direction >= 0) {
×
343
        if (x + 1 < width) {
×
344
            base = ((size_t)(x + 1) * (size_t)depth)
×
345
                 + (size_t)channel;
×
346
            carry_curr[base] += term_r;
×
347
        }
348
        if (x + 2 < width) {
×
349
            base = ((size_t)(x + 2) * (size_t)depth)
×
350
                 + (size_t)channel;
×
351
            carry_curr[base] += term_r2;
×
352
        }
353
        if (y + 1 < height && x - 1 >= 0) {
×
354
            base = ((size_t)(x - 1) * (size_t)depth)
×
355
                 + (size_t)channel;
×
356
            carry_next[base] += term_dl;
×
357
        }
358
        if (y + 1 < height) {
×
359
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
360
            carry_next[base] += term_d;
×
361
        }
362
        if (y + 1 < height && x + 1 < width) {
×
363
            base = ((size_t)(x + 1) * (size_t)depth)
×
364
                 + (size_t)channel;
×
365
            carry_next[base] += term_dr;
×
366
        }
367
        if (y + 2 < height) {
×
368
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
369
            carry_far[base] += term_d2;
×
370
        }
371
    } else {
372
        if (x - 1 >= 0) {
×
373
            base = ((size_t)(x - 1) * (size_t)depth)
×
374
                 + (size_t)channel;
×
375
            carry_curr[base] += term_r;
×
376
        }
377
        if (x - 2 >= 0) {
×
378
            base = ((size_t)(x - 2) * (size_t)depth)
×
379
                 + (size_t)channel;
380
            carry_curr[base] += term_r2;
×
381
        }
382
        if (y + 1 < height && x + 1 < width) {
×
383
            base = ((size_t)(x + 1) * (size_t)depth)
×
384
                 + (size_t)channel;
×
385
            carry_next[base] += term_dl;
×
386
        }
387
        if (y + 1 < height) {
×
388
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
389
            carry_next[base] += term_d;
×
390
        }
391
        if (y + 1 < height && x - 1 >= 0) {
×
392
            base = ((size_t)(x - 1) * (size_t)depth)
×
393
                 + (size_t)channel;
×
394
            carry_next[base] += term_dr;
×
395
        }
396
        if (y + 2 < height) {
×
397
            base = ((size_t)x * (size_t)depth) + (size_t)channel;
×
398
            carry_far[base] += term_d2;
×
399
        }
400
    }
401
}
×
402

403
SIXELSTATUS
404
sixel_dither_apply_varcoeff_float32(sixel_dither_t *dither,
×
405
                                    sixel_dither_context_t *context)
406
{
×
407
#if _MSC_VER
408
    enum { max_channels = 4 };
409
#else
410
    const int max_channels = 4;
×
411
#endif
412
    SIXELSTATUS status;
×
413
    float *data;
×
414
    unsigned char *palette;
×
415
    unsigned char *new_palette;
×
416
    float *source_pixel;
×
417
    float corrected[max_channels];
×
418
    float quantized_float;
×
419
    unsigned char quantized[max_channels];
×
420
    float *carry_curr;
×
421
    float *carry_next;
×
422
    float *carry_far;
×
423
    float palette_value_float;
×
424
    unsigned char palette_value;
×
425
    float error;
×
426
    int serpentine;
×
427
    int use_carry;
×
428
    size_t carry_len;
×
429
    int method_for_diffuse;
×
430
    int method_for_carry;
×
431
    int method_for_scan;
×
432
    sixel_lut_t *fast_lut;
×
433
    int use_fast_lut;
×
434
    diffuse_varerr_mode_float varerr_diffuse;
×
435
    diffuse_varerr_carry_mode_float varerr_diffuse_carry;
×
436
    int optimize_palette;
×
437
    int y;
×
438
    int absolute_y;
×
439
    int start;
×
440
    int end;
×
441
    int step;
×
442
    int direction;
×
443
    int x;
×
444
    int pos;
×
445
    size_t base;
×
446
    size_t carry_base;
×
447
    int depth;
×
448
    int reqcolor;
×
449
    int n;
×
450
    int color_index;
×
451
    int output_index;
×
452
    int diff;
×
453
    int table_index;
×
454
    unsigned short *indextable;
×
455
    unsigned short *migration_map;
×
456
    int *ncolors;
×
457
    int (*lookup)(const unsigned char *,
×
458
                  int,
459
                  const unsigned char *,
460
                  int,
461
                  unsigned short *,
462
                  int);
463
    float *palette_float;
×
464
    float *new_palette_float;
×
465
    int float_depth;
×
466
    int float_index;
×
467
    float lookup_pixel_float[max_channels];
×
468
    unsigned char const *lookup_pixel;
×
469
    int lookup_wants_float;
×
470
    int use_palette_float_lookup;
×
471
    int need_float_pixel;
×
472
    int have_palette_float;
×
473
    int have_new_palette_float;
×
474

475
    if (dither == NULL || context == NULL) {
×
476
        return SIXEL_BAD_ARGUMENT;
477
    }
478

479
    status = SIXEL_BAD_ARGUMENT;
×
480
    data = context->pixels_float;
×
481
    palette = context->palette;
×
482
    new_palette = context->new_palette;
×
483
    indextable = context->indextable;
×
484
    migration_map = context->migration_map;
×
485
    ncolors = context->ncolors;
×
486
    depth = context->depth;
×
487
    reqcolor = context->reqcolor;
×
488
    lookup = context->lookup;
×
489
    fast_lut = context->lut;
×
490
    use_fast_lut = (fast_lut != NULL);
×
491
    optimize_palette = context->optimize_palette;
×
492
    method_for_diffuse = context->method_for_diffuse;
×
493
    method_for_carry = context->method_for_carry;
×
494
    method_for_scan = context->method_for_scan;
×
495
    palette_float = context->palette_float;
×
496
    new_palette_float = context->new_palette_float;
×
497
    float_depth = context->float_depth;
×
498
    /*
499
     * Track float palette availability separately for the original palette
500
     * and the palette-optimization buffer so later loops can skip
501
     * byte-to-float round-trips when computing the quantization error.
502
     */
503
    if (palette_float != NULL && float_depth >= depth) {
×
504
        have_palette_float = 1;
505
    } else {
506
        have_palette_float = 0;
×
507
    }
508
    if (new_palette_float != NULL && float_depth >= depth) {
×
509
        have_new_palette_float = 1;
510
    } else {
511
        have_new_palette_float = 0;
×
512
    }
513

514
    if (data == NULL || palette == NULL || context->result == NULL) {
×
515
        return SIXEL_BAD_ARGUMENT;
516
    }
517
    if (lookup == NULL) {
×
518
        return SIXEL_BAD_ARGUMENT;
519
    }
520
    if (optimize_palette) {
×
521
        if (new_palette == NULL || migration_map == NULL || ncolors == NULL) {
×
522
            return SIXEL_BAD_ARGUMENT;
523
        }
524
    } else if (ncolors == NULL) {
×
525
        return SIXEL_BAD_ARGUMENT;
526
    }
527

528
    if (depth <= 0 || depth > max_channels) {
×
529
        return SIXEL_BAD_ARGUMENT;
530
    }
531

532
    switch (method_for_diffuse) {
×
533
    case SIXEL_DIFFUSE_LSO2:
×
534
    default:
535
        varerr_diffuse = diffuse_lso2_float;
×
536
        varerr_diffuse_carry = diffuse_lso2_carry_float;
×
537
        break;
×
538
    }
539

540
    use_carry = (method_for_carry == SIXEL_CARRY_ENABLE);
×
541
    carry_curr = NULL;
×
542
    carry_next = NULL;
×
543
    carry_far = NULL;
×
544
    carry_len = 0;
×
545

546
    if (use_carry) {
×
547
        carry_len = (size_t)context->width * (size_t)depth;
×
548
        carry_curr = (float *)calloc(carry_len, sizeof(float));
×
549
        carry_next = (float *)calloc(carry_len, sizeof(float));
×
550
        carry_far = (float *)calloc(carry_len, sizeof(float));
×
551
        if (carry_curr == NULL || carry_next == NULL || carry_far == NULL) {
×
552
            goto end;
×
553
        }
554
    }
555

556
    serpentine = (method_for_scan == SIXEL_SCAN_SERPENTINE);
×
557
    lookup_wants_float = (context->lookup_source_is_float != 0);
×
558
    use_palette_float_lookup = 0;
×
559
    if (context->prefer_palette_float_lookup != 0
×
560
            && palette_float != NULL
×
561
            && float_depth >= depth) {
×
562
        use_palette_float_lookup = 1;
×
563
    }
564
    need_float_pixel = lookup_wants_float || use_palette_float_lookup;
×
565
    if (optimize_palette) {
×
566
        *ncolors = 0;
×
567
        memset(new_palette, 0x00,
×
568
               (size_t)SIXEL_PALETTE_MAX * (size_t)depth);
×
569
        if (new_palette_float != NULL && float_depth > 0) {
×
570
            memset(new_palette_float, 0x00,
×
571
                   (size_t)SIXEL_PALETTE_MAX
572
                       * (size_t)float_depth * sizeof(float));
×
573
        }
574
        memset(migration_map, 0x00,
×
575
               sizeof(unsigned short) * (size_t)SIXEL_PALETTE_MAX);
576
    }
577

578
    for (y = 0; y < context->height; ++y) {
×
579
        absolute_y = context->band_origin + y;
×
580
        sixel_dither_scanline_params(serpentine,
×
581
                                     absolute_y,
582
                                     context->width,
583
                                     &start,
584
                                     &end,
585
                                     &step,
586
                                     &direction);
587
        for (x = start; x != end; x += step) {
×
588
            pos = y * context->width + x;
×
589
            base = (size_t)pos * (size_t)depth;
×
590
            carry_base = (size_t)x * (size_t)depth;
×
591
            if (use_carry) {
×
592
                for (n = 0; n < depth; ++n) {
×
593
                    float accum;
×
594

595
                    accum = data[base + (size_t)n]
×
596
                           + carry_curr[carry_base + (size_t)n];
×
597
                    carry_curr[carry_base + (size_t)n] = 0.0f;
×
598
                    accum = sixel_pixelformat_float_channel_clamp(
×
599
                        context->pixelformat,
600
                        n,
601
                        accum);
602
                    corrected[n] = accum;
×
603
                }
604
                source_pixel = corrected;
605
            } else {
606
                source_pixel = data + base;
×
607
            }
608

609
            for (n = 0; n < depth; ++n) {
×
610
                quantized_float = source_pixel[n];
×
611
                quantized_float = sixel_pixelformat_float_channel_clamp(
×
612
                    context->pixelformat,
613
                    n,
614
                    quantized_float);
615
                if (source_pixel == data + base) {
×
616
                    source_pixel[n] = quantized_float;
×
617
                }
618
                if (need_float_pixel) {
×
619
                    lookup_pixel_float[n] = quantized_float;
×
620
                }
621
                if (!lookup_wants_float && !use_palette_float_lookup) {
×
622
                    quantized[n] = sixel_pixelformat_float_channel_to_byte(
×
623
                        context->pixelformat,
624
                        n,
625
                        quantized_float);
626
                }
627
            }
628
            if (lookup_wants_float) {
×
629
                lookup_pixel = (unsigned char const *)(void const *)
×
630
                    lookup_pixel_float;
631
                if (use_fast_lut) {
×
632
                    color_index = sixel_lut_map_pixel(fast_lut,
×
633
                                                     lookup_pixel);
634
                } else {
635
                    color_index = lookup(lookup_pixel,
×
636
                                         depth,
637
                                         palette,
638
                                         reqcolor,
639
                                         indextable,
640
                                         context->complexion);
641
                }
642
            } else if (use_palette_float_lookup) {
×
643
                color_index = sixel_dither_lookup_palette_float32(
×
644
                    lookup_pixel_float,
645
                    depth,
646
                    palette_float,
647
                    reqcolor,
648
                    context->complexion);
649
            } else {
650
                lookup_pixel = quantized;
×
651
                if (use_fast_lut) {
×
652
                    color_index = sixel_lut_map_pixel(fast_lut,
×
653
                                                     lookup_pixel);
654
                } else {
655
                    color_index = lookup(lookup_pixel,
×
656
                                         depth,
657
                                         palette,
658
                                         reqcolor,
659
                                         indextable,
660
                                         context->complexion);
661
                }
662
            }
663

664
            if (optimize_palette) {
×
665
                if (migration_map[color_index] == 0) {
×
666
                    output_index = *ncolors;
×
667
                    for (n = 0; n < depth; ++n) {
×
668
                        new_palette[output_index * depth + n]
×
669
                            = palette[color_index * depth + n];
×
670
                    }
671
                    if (palette_float != NULL
×
672
                            && new_palette_float != NULL
×
673
                            && float_depth > 0) {
×
674
                        for (float_index = 0;
×
675
                                float_index < float_depth;
×
676
                                ++float_index) {
×
677
                            new_palette_float[output_index * float_depth
×
678
                                              + float_index]
×
679
                                = palette_float[color_index * float_depth
×
680
                                                + float_index];
×
681
                        }
682
                    }
683
                    ++*ncolors;
×
684
                    migration_map[color_index] = *ncolors;
×
685
                } else {
686
                    output_index = migration_map[color_index] - 1;
×
687
                }
688
                if (absolute_y >= context->output_start) {
×
689
                    context->result[pos] = output_index;
×
690
                }
691
            } else {
692
                output_index = color_index;
×
693
                if (absolute_y >= context->output_start) {
×
694
                    context->result[pos] = output_index;
×
695
                }
696
            }
697
            for (n = 0; n < depth; ++n) {
×
698
                if (n > 0 && (
×
699
                        context->pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32 ||
×
700
                        context->pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32 ||
×
701
                        context->pixelformat == SIXEL_PIXELFORMAT_DIN99DFLOAT32)) {
702
                    break;  /* L only */
703
                }
704
                if (optimize_palette) {
×
705
                    if (have_new_palette_float) {
×
706
                        palette_value_float =
×
707
                            new_palette_float[output_index * float_depth
×
708
                                              + n];
×
709
                    } else {
710
                        palette_value =
×
711
                            new_palette[output_index * depth + n];
×
712
                        palette_value_float
×
713
                            = sixel_pixelformat_byte_to_float(
×
714
                                  context->pixelformat,
715
                                  n,
716
                                  palette_value);
717
                    }
718
                } else {
719
                    if (have_palette_float) {
×
720
                        palette_value_float =
×
721
                            palette_float[color_index * float_depth + n];
×
722
                    } else {
723
                        palette_value =
×
724
                            palette[color_index * depth + n];
×
725
                        palette_value_float
×
726
                            = sixel_pixelformat_byte_to_float(
×
727
                                  context->pixelformat,
728
                                  n,
729
                                  palette_value);
730
                    }
731
                }
732
                error = source_pixel[n] - palette_value_float;
×
733
                if (error < 0.0f) {
×
734
                    diff = (int)(-error * 255.0f + 0.5f);
×
735
                } else {
736
                    diff = (int)(error * 255.0f + 0.5f);
×
737
                }
738
                if (diff > 255) {
×
739
                    diff = 255;
740
                }
741
                table_index = diff;
×
742
                if (use_carry) {
×
743
                    varerr_diffuse_carry(carry_curr,
×
744
                                         carry_next,
745
                                         carry_far,
746
                                         context->width,
747
                                         context->height,
748
                                         depth,
749
                                         x,
750
                                         y,
751
                                         error,
752
                                         table_index,
753
                                         direction,
754
                                         n);
755
                } else {
756
                    varerr_diffuse(data + n,
×
757
                                   context->width,
758
                                   context->height,
759
                                   x,
760
                                   y,
761
                                   depth,
762
                                   error,
763
                                   table_index,
764
                                   direction,
765
                                   context->pixelformat,
766
                                   n);
767
                }
768
            }
769
        }
770

771
        if (use_carry) {
×
772
            float *tmp;
×
773

774
            tmp = carry_curr;
×
775
            carry_curr = carry_next;
×
776
            carry_next = carry_far;
×
777
            carry_far = tmp;
×
778
            if (carry_len > 0) {
×
779
                memset(carry_far, 0x00, carry_len * sizeof(float));
×
780
            }
781
        }
782
        if (absolute_y >= context->output_start) {
×
783
            sixel_dither_pipeline_row_notify(dither, absolute_y);
×
784
        }
785
    }
786

787
    if (optimize_palette) {
×
788
        memcpy(palette, new_palette, (size_t)(*ncolors * depth));
×
789
        if (palette_float != NULL
×
790
                && new_palette_float != NULL
×
791
                && float_depth > 0) {
×
792
            memcpy(palette_float,
×
793
                   new_palette_float,
794
                   (size_t)(*ncolors * float_depth)
×
795
                       * sizeof(float));
796
        }
797
    } else {
798
        *ncolors = reqcolor;
×
799
    }
800

801
    status = SIXEL_OK;
802

803
end:
×
804
    free(carry_curr);
×
805
    free(carry_next);
×
806
    free(carry_far);
×
807
    return status;
×
808
}
809

810
/* emacs Local Variables:      */
811
/* emacs mode: c               */
812
/* emacs tab-width: 4          */
813
/* emacs indent-tabs-mode: nil */
814
/* emacs c-basic-offset: 4     */
815
/* emacs End:                  */
816
/* vim: set expandtab ts=4 sts=4 sw=4 : */
817
/* 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