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

saitoha / libsixel / 19737728848

27 Nov 2025 01:22PM UTC coverage: 40.57% (-0.2%) from 40.724%
19737728848

push

github

saitoha
colorspace: add CIELAB working colorspace support

9749 of 34655 branches covered (28.13%)

4 of 137 new or added lines in 7 files covered. (2.92%)

7 existing lines in 3 files now uncovered.

12924 of 31856 relevant lines covered (40.57%)

653154.9 hits per line

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

2.83
/src/pixelformat.c
1
/*
2
 * SPDX-License-Identifier: MIT
3
 *
4
 * Copyright (c) 2021-2025 libsixel developers. See `AUTHORS`.
5
 * Copyright (c) 2014-2019 Hayaki Saito
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
8
 * this software and associated documentation files (the "Software"), to deal in
9
 * the Software without restriction, including without limitation the rights to
10
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11
 * the Software, and to permit persons to whom the Software is furnished to do so,
12
 * subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
 */
24

25
#include "config.h"
26

27
/* STDC_HEADERS */
28
#include <stdio.h>
29
#include <stdlib.h>
30

31
#if HAVE_MATH_H
32
# include <math.h>
33
#endif  /* HAVE_MATH_H */
34

35
#if HAVE_MEMORY_H
36
# include <memory.h>
37
#endif  /* HAVE_MEMORY_H */
38

39
#include <sixel.h>
40

41
#include "pixelformat.h"
42

43
#define SIXEL_OKLAB_AB_FLOAT_MIN (-0.5f)
44
#define SIXEL_OKLAB_AB_FLOAT_MAX (0.5f)
45
#define SIXEL_CIELAB_AB_FLOAT_MIN (-1.5f)
46
#define SIXEL_CIELAB_AB_FLOAT_MAX (1.5f)
47
#define SIXEL_CIELAB_L_FLOAT_MIN  (0.0f)
48
#define SIXEL_CIELAB_L_FLOAT_MAX  (1.0f)
49

50
/*
51
 * Normalize a float32 channel stored in the 0.0-1.0 range and convert
52
 * the value to an 8-bit sample. Out-of-range or NaN inputs are clamped
53
 * to sane defaults so downstream conversions always receive valid bytes.
54
 */
55
static unsigned char
56
sixel_pixelformat_float_to_byte(float value)
×
57
{
58
#if HAVE_MATH_H
59
    if (!isfinite(value)) {
×
60
        value = 0.0f;
×
61
    }
62
#endif  /* HAVE_MATH_H */
63

64
    if (value <= 0.0f) {
×
65
        return 0;
×
66
    }
67
    if (value >= 1.0f) {
×
68
        return 255;
×
69
    }
70

71
    return (unsigned char)(value * 255.0f + 0.5f);
×
72
}
73

74
static unsigned char
75
sixel_pixelformat_oklab_L_to_byte(float value)
×
76
{
77
#if HAVE_MATH_H
78
    if (!isfinite(value)) {
×
79
        value = 0.0f;
×
80
    }
81
#endif  /* HAVE_MATH_H */
82

83
    if (value <= 0.0f) {
×
84
        return 0;
×
85
    }
86
    if (value >= 1.0f) {
×
87
        return 255;
×
88
    }
89

90
    return (unsigned char)(value * 255.0f + 0.5f);
×
91
}
92

93
static unsigned char
94
sixel_pixelformat_oklab_ab_to_byte(float value)
×
95
{
96
    float encoded;
97

98
#if HAVE_MATH_H
99
    if (!isfinite(value)) {
×
100
        value = 0.0f;
×
101
    }
102
#endif  /* HAVE_MATH_H */
103

104
    encoded = value + 0.5f;
×
105
    if (encoded <= 0.0f) {
×
106
        return 0;
×
107
    }
108
    if (encoded >= 1.0f) {
×
109
        return 255;
×
110
    }
111

112
    return (unsigned char)(encoded * 255.0f + 0.5f);
×
113
}
114

115
static unsigned char
NEW
116
sixel_pixelformat_cielab_L_to_byte(float value)
×
117
{
118
#if HAVE_MATH_H
NEW
119
    if (!isfinite(value)) {
×
NEW
120
        value = 0.0f;
×
121
    }
122
#endif  /* HAVE_MATH_H */
123

NEW
124
    if (value <= 0.0f) {
×
NEW
125
        return 0;
×
126
    }
NEW
127
    if (value >= 1.0f) {
×
NEW
128
        return 255;
×
129
    }
130

NEW
131
    return (unsigned char)(value * 255.0f + 0.5f);
×
132
}
133

134
static unsigned char
NEW
135
sixel_pixelformat_cielab_ab_to_byte(float value)
×
136
{
137
    float encoded;
138

139
#if HAVE_MATH_H
NEW
140
    if (!isfinite(value)) {
×
NEW
141
        value = 0.0f;
×
142
    }
143
#endif  /* HAVE_MATH_H */
144

NEW
145
    encoded = (value / (2.0f * SIXEL_CIELAB_AB_FLOAT_MAX)) + 0.5f;
×
NEW
146
    if (encoded <= 0.0f) {
×
NEW
147
        return 0;
×
148
    }
NEW
149
    if (encoded >= 1.0f) {
×
NEW
150
        return 255;
×
151
    }
152

NEW
153
    return (unsigned char)(encoded * 255.0f + 0.5f);
×
154
}
155

156
static float
157
sixel_pixelformat_float_channel_min_internal(int pixelformat,
×
158
                                             int channel)
159
{
160
    (void)channel;
161
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
162
        if (channel == 0) {
×
163
            return 0.0f;
×
164
        }
165
        return SIXEL_OKLAB_AB_FLOAT_MIN;
×
166
    }
NEW
167
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
NEW
168
        if (channel == 0) {
×
NEW
169
            return SIXEL_CIELAB_L_FLOAT_MIN;
×
170
        }
NEW
171
        return SIXEL_CIELAB_AB_FLOAT_MIN;
×
172
    }
UNCOV
173
    return 0.0f;
×
174
}
175

176
static float
177
sixel_pixelformat_float_channel_max_internal(int pixelformat,
×
178
                                             int channel)
179
{
180
    (void)channel;
181
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
182
        if (channel == 0) {
×
183
            return 1.0f;
×
184
        }
185
        return SIXEL_OKLAB_AB_FLOAT_MAX;
×
186
    }
NEW
187
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
NEW
188
        if (channel == 0) {
×
NEW
189
            return SIXEL_CIELAB_L_FLOAT_MAX;
×
190
        }
NEW
191
        return SIXEL_CIELAB_AB_FLOAT_MAX;
×
192
    }
UNCOV
193
    return 1.0f;
×
194
}
195

196
float
197
sixel_pixelformat_float_channel_clamp(int pixelformat,
×
198
                                      int channel,
199
                                      float value)
200
{
201
    float minimum;
202
    float maximum;
203

204
#if HAVE_MATH_H
205
    if (!isfinite(value)) {
×
206
        value = 0.0f;
×
207
    }
208
#endif  /* HAVE_MATH_H */
209

210
    minimum = sixel_pixelformat_float_channel_min_internal(pixelformat,
×
211
                                                           channel);
212
    maximum = sixel_pixelformat_float_channel_max_internal(pixelformat,
×
213
                                                           channel);
214
    if (value < minimum) {
×
215
        return minimum;
×
216
    }
217
    if (value > maximum) {
×
218
        return maximum;
×
219
    }
220

221
    return value;
×
222
}
223

224
unsigned char
225
sixel_pixelformat_float_channel_to_byte(int pixelformat,
×
226
                                        int channel,
227
                                        float value)
228
{
229
    float clamped;
230

231
    clamped = sixel_pixelformat_float_channel_clamp(pixelformat,
×
232
                                                    channel,
233
                                                    value);
234
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
235
        if (channel == 0) {
×
236
            return sixel_pixelformat_oklab_L_to_byte(clamped);
×
237
        }
238
        return sixel_pixelformat_oklab_ab_to_byte(clamped);
×
239
    }
NEW
240
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
NEW
241
        if (channel == 0) {
×
NEW
242
            return sixel_pixelformat_cielab_L_to_byte(clamped);
×
243
        }
NEW
244
        return sixel_pixelformat_cielab_ab_to_byte(clamped);
×
245
    }
246

247
    (void)channel;
248
    return sixel_pixelformat_float_to_byte(clamped);
×
249
}
250

251
float
252
sixel_pixelformat_byte_to_float(int pixelformat,
×
253
                                int channel,
254
                                unsigned char value)
255
{
256
    float decoded;
257

258
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
259
        if (channel == 0) {
×
260
            return (float)value / 255.0f;
×
261
        }
262
        decoded = (float)value / 255.0f;
×
263
        return decoded - 0.5f;
×
264
    }
NEW
265
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
NEW
266
        if (channel == 0) {
×
NEW
267
            return (float)value / 255.0f;
×
268
        }
NEW
269
        decoded = (float)value / 255.0f;
×
NEW
270
        decoded = (decoded - 0.5f)
×
271
                 * (2.0f * SIXEL_CIELAB_AB_FLOAT_MAX);
NEW
272
        return decoded;
×
273
    }
274

275
    (void)channel;
276
    return (float)value / 255.0f;
×
277
}
278

279
static void
280
get_rgb(unsigned char const *data,
×
281
        int const pixelformat,
282
        int depth,
283
        unsigned char *r,
284
        unsigned char *g,
285
        unsigned char *b)
286
{
287
    unsigned int pixels = 0;
×
288
#if SWAP_BYTES
289
    unsigned int low;
290
    unsigned int high;
291
#endif
292
    int count = 0;
×
293

294
    if (pixelformat == SIXEL_PIXELFORMAT_RGBFLOAT32
×
295
            || pixelformat == SIXEL_PIXELFORMAT_LINEARRGBFLOAT32) {
×
296
        float const *fpixels = (float const *)(void const *)data;
×
297

298
        *r = sixel_pixelformat_float_to_byte(fpixels[0]);
×
299
        *g = sixel_pixelformat_float_to_byte(fpixels[1]);
×
300
        *b = sixel_pixelformat_float_to_byte(fpixels[2]);
×
301
        return;
×
302
    }
303
    if (pixelformat == SIXEL_PIXELFORMAT_OKLABFLOAT32) {
×
304
        float const *fpixels = (float const *)(void const *)data;
×
305

306
        *r = sixel_pixelformat_oklab_L_to_byte(fpixels[0]);
×
307
        *g = sixel_pixelformat_oklab_ab_to_byte(fpixels[1]);
×
308
        *b = sixel_pixelformat_oklab_ab_to_byte(fpixels[2]);
×
309
        return;
×
310
    }
NEW
311
    if (pixelformat == SIXEL_PIXELFORMAT_CIELABFLOAT32) {
×
NEW
312
        float const *fpixels = (float const *)(void const *)data;
×
313

NEW
314
        *r = sixel_pixelformat_cielab_L_to_byte(fpixels[0]);
×
NEW
315
        *g = sixel_pixelformat_cielab_ab_to_byte(fpixels[1]);
×
NEW
316
        *b = sixel_pixelformat_cielab_ab_to_byte(fpixels[2]);
×
NEW
317
        return;
×
318
    }
319

320
    while (count < depth) {
×
321
        pixels = *(data + count) | (pixels << 8);
×
322
        count++;
×
323
    }
324

325
    /* TODO: we should swap bytes (only necessary on LSByte first hardware?) */
326
#if SWAP_BYTES
327
    if (depth == 2) {
328
        low    = pixels & 0xff;
329
        high   = (pixels >> 8) & 0xff;
330
        pixels = (low << 8) | high;
331
    }
332
#endif
333

334
    switch (pixelformat) {
×
335
    case SIXEL_PIXELFORMAT_RGB555:
336
        *r = ((pixels >> 10) & 0x1f) << 3;
×
337
        *g = ((pixels >>  5) & 0x1f) << 3;
×
338
        *b = ((pixels >>  0) & 0x1f) << 3;
×
339
        break;
×
340
    case SIXEL_PIXELFORMAT_RGB565:
341
        *r = ((pixels >> 11) & 0x1f) << 3;
×
342
        *g = ((pixels >>  5) & 0x3f) << 2;
×
343
        *b = ((pixels >>  0) & 0x1f) << 3;
×
344
        break;
×
345
    case SIXEL_PIXELFORMAT_RGB888:
346
        *r = (pixels >> 16) & 0xff;
×
347
        *g = (pixels >>  8) & 0xff;
×
348
        *b = (pixels >>  0) & 0xff;
×
349
        break;
×
350
    case SIXEL_PIXELFORMAT_BGR555:
351
        *r = ((pixels >>  0) & 0x1f) << 3;
×
352
        *g = ((pixels >>  5) & 0x1f) << 3;
×
353
        *b = ((pixels >> 10) & 0x1f) << 3;
×
354
        break;
×
355
    case SIXEL_PIXELFORMAT_BGR565:
356
        *r = ((pixels >>  0) & 0x1f) << 3;
×
357
        *g = ((pixels >>  5) & 0x3f) << 2;
×
358
        *b = ((pixels >> 11) & 0x1f) << 3;
×
359
        break;
×
360
    case SIXEL_PIXELFORMAT_BGR888:
361
        *r = (pixels >>  0) & 0xff;
×
362
        *g = (pixels >>  8) & 0xff;
×
363
        *b = (pixels >> 16) & 0xff;
×
364
        break;
×
365
    case SIXEL_PIXELFORMAT_RGBA8888:
366
        *r = (pixels >> 24) & 0xff;
×
367
        *g = (pixels >> 16) & 0xff;
×
368
        *b = (pixels >>  8) & 0xff;
×
369
        break;
×
370
    case SIXEL_PIXELFORMAT_ARGB8888:
371
        *r = (pixels >> 16) & 0xff;
×
372
        *g = (pixels >>  8) & 0xff;
×
373
        *b = (pixels >>  0) & 0xff;
×
374
        break;
×
375
    case SIXEL_PIXELFORMAT_BGRA8888:
376
        *r = (pixels >>  8) & 0xff;
×
377
        *g = (pixels >> 16) & 0xff;
×
378
        *b = (pixels >> 24) & 0xff;
×
379
        break;
×
380
    case SIXEL_PIXELFORMAT_ABGR8888:
381
        *r = (pixels >>  0) & 0xff;
×
382
        *g = (pixels >>  8) & 0xff;
×
383
        *b = (pixels >> 16) & 0xff;
×
384
        break;
×
385
    case SIXEL_PIXELFORMAT_GA88:
386
        *r = *g = *b = (pixels >> 8) & 0xff;
×
387
        break;
×
388
    case SIXEL_PIXELFORMAT_G8:
389
    case SIXEL_PIXELFORMAT_AG88:
390
        *r = *g = *b = pixels & 0xff;
×
391
        break;
×
392
    default:
393
        *r = *g = *b = 0;
×
394
        break;
×
395
    }
396
}
397

398

399
SIXELAPI int
400
sixel_helper_compute_depth(int pixelformat)
2,012✔
401
{
402
    int depth = (-1);  /* unknown */
2,012✔
403

404
    switch (pixelformat) {
2,012!
405
    case SIXEL_PIXELFORMAT_ARGB8888:
406
    case SIXEL_PIXELFORMAT_RGBA8888:
407
    case SIXEL_PIXELFORMAT_ABGR8888:
408
    case SIXEL_PIXELFORMAT_BGRA8888:
409
        depth = 4;
×
410
        break;
×
411
    case SIXEL_PIXELFORMAT_RGB888:
884✔
412
    case SIXEL_PIXELFORMAT_BGR888:
413
        depth = 3;
1,330✔
414
        break;
1,330✔
415
    case SIXEL_PIXELFORMAT_RGB555:
416
    case SIXEL_PIXELFORMAT_RGB565:
417
    case SIXEL_PIXELFORMAT_BGR555:
418
    case SIXEL_PIXELFORMAT_BGR565:
419
    case SIXEL_PIXELFORMAT_AG88:
420
    case SIXEL_PIXELFORMAT_GA88:
421
        depth = 2;
×
422
        break;
×
423
    case SIXEL_PIXELFORMAT_G1:
152✔
424
    case SIXEL_PIXELFORMAT_G2:
425
    case SIXEL_PIXELFORMAT_G4:
426
    case SIXEL_PIXELFORMAT_G8:
427
    case SIXEL_PIXELFORMAT_PAL1:
428
    case SIXEL_PIXELFORMAT_PAL2:
429
    case SIXEL_PIXELFORMAT_PAL4:
430
    case SIXEL_PIXELFORMAT_PAL8:
431
        depth = 1;
228✔
432
        break;
228✔
433
    case SIXEL_PIXELFORMAT_RGBFLOAT32:
302✔
434
    case SIXEL_PIXELFORMAT_LINEARRGBFLOAT32:
435
    case SIXEL_PIXELFORMAT_OKLABFLOAT32:
436
    case SIXEL_PIXELFORMAT_CIELABFLOAT32:
437
        depth = (int)(sizeof(float) * 3);
454✔
438
        break;
454✔
439
    default:
440
        break;
×
441
    }
442

443
    return depth;
2,012✔
444
}
445

446

447
static void
448
expand_rgb(unsigned char *dst,
×
449
           unsigned char const *src,
450
           int width, int height,
451
           int pixelformat, int depth)
452
{
453
    int x;
454
    int y;
455
    int dst_offset;
456
    int src_offset;
457
    unsigned char r, g, b;
458

459
    for (y = 0; y < height; y++) {
×
460
        for (x = 0; x < width; x++) {
×
461
            src_offset = depth * (y * width + x);
×
462
            dst_offset = 3 * (y * width + x);
×
463
            get_rgb(src + src_offset, pixelformat, depth, &r, &g, &b);
×
464

465
            *(dst + dst_offset + 0) = r;
×
466
            *(dst + dst_offset + 1) = g;
×
467
            *(dst + dst_offset + 2) = b;
×
468
        }
469
    }
470
}
×
471

472

473
static SIXELSTATUS
474
expand_palette(unsigned char *dst, unsigned char const *src,
×
475
               int width, int height, int const pixelformat)
476
{
477
    SIXELSTATUS status = SIXEL_FALSE;
×
478
    int x;
479
    int y;
480
    int i;
481
    int bpp;  /* bit per plane */
482

483
    switch (pixelformat) {
×
484
    case SIXEL_PIXELFORMAT_PAL1:
485
    case SIXEL_PIXELFORMAT_G1:
486
        bpp = 1;
×
487
        break;
×
488
    case SIXEL_PIXELFORMAT_PAL2:
489
    case SIXEL_PIXELFORMAT_G2:
490
        bpp = 2;
×
491
        break;
×
492
    case SIXEL_PIXELFORMAT_PAL4:
493
    case SIXEL_PIXELFORMAT_G4:
494
        bpp = 4;
×
495
        break;
×
496
    case SIXEL_PIXELFORMAT_PAL8:
497
    case SIXEL_PIXELFORMAT_G8:
498
        for (i = 0; i < width * height; ++i, ++src) {
×
499
            *dst++ = *src;
×
500
        }
501
        status = SIXEL_OK;
×
502
        goto end;
×
503
    default:
504
        status = SIXEL_BAD_ARGUMENT;
×
505
        sixel_helper_set_additional_message(
×
506
            "expand_palette: invalid pixelformat.");
507
        goto end;
×
508
    }
509

510
#if HAVE_DEBUG
511
    fprintf(stderr, "expanding PAL%d to PAL8...\n", bpp);
×
512
#endif
513

514
    for (y = 0; y < height; ++y) {
×
515
        for (x = 0; x < width * bpp / 8; ++x) {
×
516
            for (i = 0; i < 8 / bpp; ++i) {
×
517
                *dst++ = *src >> (8 / bpp - 1 - i) * bpp & ((1 << bpp) - 1);
×
518
            }
519
            src++;
×
520
        }
521
        x = width - x * 8 / bpp;
×
522
        if (x > 0) {
×
523
            for (i = 0; i < x; ++i) {
×
524
                *dst++ = *src >> (8 - (i + 1) * bpp) & ((1 << bpp) - 1);
×
525
            }
526
            src++;
×
527
        }
528
    }
529

530
    status = SIXEL_OK;
×
531

532
end:
533
    return status;
×
534
}
535

536

537
SIXELAPI SIXELSTATUS
538
sixel_helper_normalize_pixelformat(
×
539
    unsigned char       /* out */ *dst,             /* destination buffer */
540
    int                 /* out */ *dst_pixelformat, /* converted pixelformat */
541
    unsigned char const /* in */  *src,             /* source pixels */
542
    int                 /* in */  src_pixelformat,  /* format of source image */
543
    int                 /* in */  width,            /* width of source image */
544
    int                 /* in */  height)           /* height of source image */
545
{
546
    SIXELSTATUS status = SIXEL_FALSE;
×
547
    int depth;
548

549
    switch (src_pixelformat) {
×
550
    case SIXEL_PIXELFORMAT_G8:
551
        expand_rgb(dst, src, width, height, src_pixelformat, 1);
×
552
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
553
        break;
×
554
    case SIXEL_PIXELFORMAT_RGB565:
555
    case SIXEL_PIXELFORMAT_RGB555:
556
    case SIXEL_PIXELFORMAT_BGR565:
557
    case SIXEL_PIXELFORMAT_BGR555:
558
    case SIXEL_PIXELFORMAT_GA88:
559
    case SIXEL_PIXELFORMAT_AG88:
560
        expand_rgb(dst, src, width, height, src_pixelformat, 2);
×
561
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
562
        break;
×
563
    case SIXEL_PIXELFORMAT_RGB888:
564
    case SIXEL_PIXELFORMAT_BGR888:
565
        expand_rgb(dst, src, width, height, src_pixelformat, 3);
×
566
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
567
        break;
×
568
    case SIXEL_PIXELFORMAT_RGBFLOAT32:
569
    case SIXEL_PIXELFORMAT_LINEARRGBFLOAT32:
570
    case SIXEL_PIXELFORMAT_OKLABFLOAT32:
571
    case SIXEL_PIXELFORMAT_CIELABFLOAT32:
572
        depth = sixel_helper_compute_depth(src_pixelformat);
×
573
        if (depth <= 0) {
×
574
            status = SIXEL_BAD_ARGUMENT;
×
575
            goto end;
×
576
        }
577
        expand_rgb(dst, src, width, height, src_pixelformat, depth);
×
578
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
579
        break;
×
580
    case SIXEL_PIXELFORMAT_RGBA8888:
581
    case SIXEL_PIXELFORMAT_ARGB8888:
582
    case SIXEL_PIXELFORMAT_BGRA8888:
583
    case SIXEL_PIXELFORMAT_ABGR8888:
584
        expand_rgb(dst, src, width, height, src_pixelformat, 4);
×
585
        *dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
586
        break;
×
587
    case SIXEL_PIXELFORMAT_PAL1:
588
    case SIXEL_PIXELFORMAT_PAL2:
589
    case SIXEL_PIXELFORMAT_PAL4:
590
        *dst_pixelformat = SIXEL_PIXELFORMAT_PAL8;
×
591
        status = expand_palette(dst, src, width, height, src_pixelformat);
×
592
        if (SIXEL_FAILED(status)) {
×
593
            goto end;
×
594
        }
595
        break;
×
596
    case SIXEL_PIXELFORMAT_G1:
597
    case SIXEL_PIXELFORMAT_G2:
598
    case SIXEL_PIXELFORMAT_G4:
599
        *dst_pixelformat = SIXEL_PIXELFORMAT_G8;
×
600
        status = expand_palette(dst, src, width, height, src_pixelformat);
×
601
        if (SIXEL_FAILED(status)) {
×
602
            goto end;
×
603
        }
604
        break;
×
605
    case SIXEL_PIXELFORMAT_PAL8:
606
        memcpy(dst, src, (size_t)(width * height));
×
607
        *dst_pixelformat = src_pixelformat;
×
608
        break;
×
609
    default:
610
        status = SIXEL_BAD_ARGUMENT;
×
611
        goto end;
×
612
    }
613

614
    status = SIXEL_OK;
×
615

616
end:
617
    return status;
×
618
}
619

620

621
#if HAVE_TESTS
622
static int
623
test1(void)
×
624
{
625
    unsigned char dst[3];
626
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
627
    int src_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
628
    unsigned char src[] = { 0x46, 0xf3, 0xe5 };
×
629
    int ret = 0;
×
630

631
    int nret = EXIT_FAILURE;
×
632

633
    ret = sixel_helper_normalize_pixelformat(dst,
×
634
                                             &dst_pixelformat,
635
                                             src,
636
                                             src_pixelformat,
637
                                             1,
638
                                             1);
639
    if (ret != 0) {
×
640
        goto error;
×
641
    }
642
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
643
        goto error;
×
644
    }
645
    if ((dst[0] << 16 | dst[1] << 8 | dst[2]) != (src[0] << 16 | src[1] << 8 | src[2])) {
×
646
        goto error;
×
647
    }
648
    return EXIT_SUCCESS;
×
649

650
error:
651
    perror("test1");
×
652
    return nret;
×
653
}
654

655

656
static int
657
test2(void)
×
658
{
659
    unsigned char dst[3];
660
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
661
    int src_pixelformat = SIXEL_PIXELFORMAT_RGB555;
×
662
    unsigned char src[] = { 0x47, 0x9c };
×
663
    int ret = 0;
×
664

665
    int nret = EXIT_FAILURE;
×
666

667
    ret = sixel_helper_normalize_pixelformat(dst,
×
668
                                             &dst_pixelformat,
669
                                             src,
670
                                             src_pixelformat,
671
                                             1,
672
                                             1);
673
    if (ret != 0) {
×
674
        goto error;
×
675
    }
676
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
677
        goto error;
×
678
    }
679
    if ((dst[0] >> 3 << 10 | dst[1] >> 3 << 5 | dst[2] >> 3) != (src[0] << 8 | src[1])) {
×
680
        goto error;
×
681
    }
682
    return EXIT_SUCCESS;
×
683

684
error:
685
    perror("test2");
×
686
    return nret;
×
687
}
688

689

690
static int
691
test3(void)
×
692
{
693
    unsigned char dst[3];
694
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
695
    int src_pixelformat = SIXEL_PIXELFORMAT_RGB565;
×
696
    unsigned char src[] = { 0x47, 0x9c };
×
697
    int ret = 0;
×
698

699
    int nret = EXIT_FAILURE;
×
700

701
    ret = sixel_helper_normalize_pixelformat(dst,
×
702
                                             &dst_pixelformat,
703
                                             src,
704
                                             src_pixelformat,
705
                                             1,
706
                                             1);
707
    if (ret != 0) {
×
708
        goto error;
×
709
    }
710
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
711
        goto error;
×
712
    }
713
    if ((dst[0] >> 3 << 11 | dst[1] >> 2 << 5 | dst[2] >> 3) != (src[0] << 8 | src[1])) {
×
714
        goto error;
×
715
    }
716
    return EXIT_SUCCESS;
×
717

718
error:
719
    perror("test3");
×
720
    return nret;
×
721
}
722

723

724
static int
725
test4(void)
×
726
{
727
    unsigned char dst[3];
728
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
729
    int src_pixelformat = SIXEL_PIXELFORMAT_BGR888;
×
730
    unsigned char src[] = { 0x46, 0xf3, 0xe5 };
×
731
    int ret = 0;
×
732

733
    int nret = EXIT_FAILURE;
×
734

735
    ret = sixel_helper_normalize_pixelformat(dst,
×
736
                                             &dst_pixelformat,
737
                                             src,
738
                                             src_pixelformat,
739
                                             1,
740
                                             1);
741
    if (ret != 0) {
×
742
        goto error;
×
743
    }
744
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
745
        goto error;
×
746
    }
747
    if ((dst[2] << 16 | dst[1] << 8 | dst[0]) != (src[0] << 16 | src[1] << 8 | src[2])) {
×
748
        goto error;
×
749
    }
750
    return EXIT_SUCCESS;
×
751

752
error:
753
    perror("test4");
×
754
    return nret;
×
755
}
756

757

758
static int
759
test5(void)
×
760
{
761
    unsigned char dst[3];
762
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
763
    int src_pixelformat = SIXEL_PIXELFORMAT_BGR555;
×
764
    unsigned char src[] = { 0x23, 0xc8 };
×
765
    int ret = 0;
×
766

767
    int nret = EXIT_FAILURE;
×
768

769
    ret = sixel_helper_normalize_pixelformat(dst,
×
770
                                             &dst_pixelformat,
771
                                             src,
772
                                             src_pixelformat,
773
                                             1,
774
                                             1);
775
    if (ret != 0) {
×
776
        goto error;
×
777
    }
778
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
779
        goto error;
×
780
    }
781
    if ((dst[2] >> 3 << 10 | dst[1] >> 3 << 5 | dst[0] >> 3) != (src[0] << 8 | src[1])) {
×
782
        goto error;
×
783
    }
784
    return EXIT_SUCCESS;
×
785

786
error:
787
    perror("test5");
×
788
    return nret;
×
789
}
790

791

792
static int
793
test6(void)
×
794
{
795
    unsigned char dst[3];
796
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
797
    int src_pixelformat = SIXEL_PIXELFORMAT_BGR565;
×
798
    unsigned char src[] = { 0x47, 0x88 };
×
799
    int ret = 0;
×
800

801
    int nret = EXIT_FAILURE;
×
802

803
    ret = sixel_helper_normalize_pixelformat(dst,
×
804
                                             &dst_pixelformat,
805
                                             src,
806
                                             src_pixelformat,
807
                                             1,
808
                                             1);
809
    if (ret != 0) {
×
810
        goto error;
×
811
    }
812
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
813
        goto error;
×
814
    }
815
    if ((dst[2] >> 3 << 11 | dst[1] >> 2 << 5 | dst[0] >> 3) != (src[0] << 8 | src[1])) {
×
816
        goto error;
×
817
    }
818
    return EXIT_SUCCESS;
×
819

820
error:
821
    perror("test6");
×
822
    return nret;
×
823
}
824

825

826
static int
827
test7(void)
×
828
{
829
    unsigned char dst[3];
830
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
831
    int src_pixelformat = SIXEL_PIXELFORMAT_AG88;
×
832
    unsigned char src[] = { 0x47, 0x88 };
×
833
    int ret = 0;
×
834

835
    int nret = EXIT_FAILURE;
×
836

837
    ret = sixel_helper_normalize_pixelformat(dst,
×
838
                                             &dst_pixelformat,
839
                                             src,
840
                                             src_pixelformat,
841
                                             1,
842
                                             1);
843
    if (ret != 0) {
×
844
        goto error;
×
845
    }
846
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
847
        goto error;
×
848
    }
849
    if (dst[0] != src[1]) {
×
850
        goto error;
×
851
    }
852
    return EXIT_SUCCESS;
×
853

854
error:
855
    perror("test7");
×
856
    return nret;
×
857
}
858

859

860
static int
861
test8(void)
×
862
{
863
    unsigned char dst[3];
864
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
865
    int src_pixelformat = SIXEL_PIXELFORMAT_GA88;
×
866
    unsigned char src[] = { 0x47, 0x88 };
×
867
    int ret = 0;
×
868

869
    int nret = EXIT_FAILURE;
×
870

871
    ret = sixel_helper_normalize_pixelformat(dst,
×
872
                                             &dst_pixelformat,
873
                                             src,
874
                                             src_pixelformat,
875
                                             1,
876
                                             1);
877
    if (ret != 0) {
×
878
        goto error;
×
879
    }
880
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
881
        goto error;
×
882
    }
883
    if (dst[0] != src[0]) {
×
884
        goto error;
×
885
    }
886
    return EXIT_SUCCESS;
×
887

888
error:
889
    perror("test8");
×
890
    return nret;
×
891
}
892

893

894
static int
895
test9(void)
×
896
{
897
    unsigned char dst[3];
898
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
899
    int src_pixelformat = SIXEL_PIXELFORMAT_RGBA8888;
×
900
    unsigned char src[] = { 0x46, 0xf3, 0xe5, 0xf0 };
×
901
    int ret = 0;
×
902

903
    int nret = EXIT_FAILURE;
×
904

905
    ret = sixel_helper_normalize_pixelformat(dst,
×
906
                                             &dst_pixelformat,
907
                                             src,
908
                                             src_pixelformat,
909
                                             1,
910
                                             1);
911
    if (ret != 0) {
×
912
        goto error;
×
913
    }
914
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
915
        goto error;
×
916
    }
917
    if (dst[0] != src[0]) {
×
918
        goto error;
×
919
    }
920
    if (dst[1] != src[1]) {
×
921
        goto error;
×
922
    }
923
    if (dst[2] != src[2]) {
×
924
        goto error;
×
925
    }
926
    return EXIT_SUCCESS;
×
927

928
error:
929
    perror("test8");
×
930
    return nret;
×
931
}
932

933

934
static int
935
test10(void)
×
936
{
937
    unsigned char dst[3];
938
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
939
    int src_pixelformat = SIXEL_PIXELFORMAT_ARGB8888;
×
940
    unsigned char src[] = { 0x46, 0xf3, 0xe5, 0xf0 };
×
941
    int ret = 0;
×
942

943
    int nret = EXIT_FAILURE;
×
944

945
    ret = sixel_helper_normalize_pixelformat(dst,
×
946
                                             &dst_pixelformat,
947
                                             src,
948
                                             src_pixelformat,
949
                                             1,
950
                                             1);
951
    if (ret != 0) {
×
952
        goto error;
×
953
    }
954
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
955
        goto error;
×
956
    }
957
    if (dst[0] != src[1]) {
×
958
        goto error;
×
959
    }
960
    if (dst[1] != src[2]) {
×
961
        goto error;
×
962
    }
963
    if (dst[2] != src[3]) {
×
964
        goto error;
×
965
    }
966
    return EXIT_SUCCESS;
×
967

968
error:
969
    perror("test8");
×
970
    return nret;
×
971
}
972

973

974
static int
975
test11(void)
×
976
{
977
    unsigned char dst[3];
978
    int dst_pixelformat = SIXEL_PIXELFORMAT_RGB888;
×
979
    int src_pixelformat = SIXEL_PIXELFORMAT_RGBFLOAT32;
×
980
    float srcf[] = { 0.0f, 0.5f, 1.0f };
×
981
    unsigned char const *src = (unsigned char const *)srcf;
×
982
    int ret = 0;
×
983
    int depth;
984

985
    int nret = EXIT_FAILURE;
×
986

987
    ret = sixel_helper_normalize_pixelformat(dst,
×
988
                                             &dst_pixelformat,
989
                                             src,
990
                                             src_pixelformat,
991
                                             1,
992
                                             1);
993
    if (ret != 0) {
×
994
        goto error;
×
995
    }
996
    if (dst_pixelformat != SIXEL_PIXELFORMAT_RGB888) {
×
997
        goto error;
×
998
    }
999
    if (dst[0] != 0 || dst[1] != 128 || dst[2] != 255) {
×
1000
        goto error;
×
1001
    }
1002
    depth = sixel_helper_compute_depth(src_pixelformat);
×
1003
    if (depth != (int)(sizeof(float) * 3)) {
×
1004
        goto error;
×
1005
    }
1006
    return EXIT_SUCCESS;
×
1007

1008
error:
1009
    perror("test11");
×
1010
    return nret;
×
1011
}
1012

1013

1014
SIXELAPI int
1015
sixel_pixelformat_tests_main(void)
×
1016
{
1017
    int nret = EXIT_FAILURE;
×
1018
    size_t i;
1019
    typedef int (* testcase)(void);
1020

1021
    static testcase const testcases[] = {
1022
        test1,
1023
        test2,
1024
        test3,
1025
        test4,
1026
        test5,
1027
        test6,
1028
        test7,
1029
        test8,
1030
        test9,
1031
        test10,
1032
        test11,
1033
    };
1034

1035
    for (i = 0; i < sizeof(testcases) / sizeof(testcase); ++i) {
×
1036
        nret = testcases[i]();
×
1037
        if (nret != EXIT_SUCCESS) {
×
1038
            goto error;
×
1039
        }
1040
    }
1041

1042
    nret = EXIT_SUCCESS;
×
1043

1044
error:
1045
    return nret;
×
1046
}
1047
#endif  /* HAVE_TESTS */
1048

1049
/* emacs Local Variables:      */
1050
/* emacs mode: c               */
1051
/* emacs tab-width: 4          */
1052
/* emacs indent-tabs-mode: nil */
1053
/* emacs c-basic-offset: 4     */
1054
/* emacs End:                  */
1055
/* vim: set expandtab ts=4 sts=4 sw=4 : */
1056
/* 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