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

saitoha / libsixel / 25428468311

06 May 2026 09:54AM UTC coverage: 85.568% (+0.003%) from 85.565%
25428468311

push

github

saitoha
build: sync Makefile.in

125651 of 267416 branches covered (46.99%)

151097 of 176581 relevant lines covered (85.57%)

8925004.37 hits per line

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

84.66
/src/filter-sample.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 of
7
 * this software and associated documentation files (the "Software"), to deal in
8
 * the Software without restriction, including without limitation the rights to
9
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10
 * the Software, and to permit persons to whom the Software is furnished to do so,
11
 * subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in all
14
 * 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, FITNESS
18
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 */
23

24
#if defined(HAVE_CONFIG_H)
25
#include "config.h"
26
#endif
27

28
/* STDC_HEADERS */
29
#include <limits.h>
30
#include <stdint.h>
31
#include <stdlib.h>
32
#include <string.h>
33

34
#include <sixel.h>
35

36
#include "filter-sample.h"
37
#include "filter.h"
38
#include "frame-factory.h"
39
#include "frame.h"
40
#include "pixelformat.h"
41

42
typedef struct sixel_filter_sample_state {
43
    sixel_filter_sample_config_t config;
44
} sixel_filter_sample_state_t;
45

46
static SIXELSTATUS
47
sixel_filter_sample_apply(sixel_filter_t *filter,
48
      sixel_allocator_t *allocator,
49
      sixel_timeline_logger_t *logger);
50

51
static void
52
sixel_filter_sample_dispose(sixel_filter_t *filter);
53

54
static sixel_filter_vtbl_t const sixel_filter_sample_vtbl = {
55
    "sample",
56
    SIXEL_FILTER_KIND_SAMPLE,
57
    sixel_filter_sample_apply,
58
    sixel_filter_sample_dispose,
59
    NULL,
60
    NULL,
61
    NULL
62
};
63

64
static size_t
65
sixel_filter_sample_select_stride(
34,915✔
66
        sixel_filter_sample_config_t const *config,
67
        int width,
68
        int height)
69
{
70
    size_t stride;
18,102✔
71
    size_t base_target;
18,102✔
72
    size_t color_budget;
18,102✔
73
    size_t target;
18,102✔
74
    size_t total;
18,102✔
75

76
    stride = 1u;
34,915✔
77
    base_target = 4096u;
34,915✔
78
    color_budget = 0u;
34,915✔
79
    target = base_target;
34,915✔
80
    total = 0u;
34,915✔
81

82
    if (width <= 0 || height <= 0) {
34,915!
83
        return stride;
84
    }
85

86
    if (config != NULL && config->palette_sample_override != 0) {
34,915!
87
        target = config->palette_sample_target;
24✔
88
    } else {
9✔
89
        if (config != NULL && config->reqcolors > 0) {
34,891!
90
            color_budget = (size_t)config->reqcolors * 64u;
34,871✔
91
            if (color_budget / 64u != (size_t)config->reqcolors) {
34,871!
92
                color_budget = base_target;
93
            }
94
            if (color_budget > target) {
34,759✔
95
                target = color_budget;
33,299✔
96
            }
16,951✔
97
        }
17,929✔
98

99
        if (config != NULL
51,277!
100
                && (config->quality_mode == SIXEL_QUALITY_HIGH
34,891!
101
                    || config->quality_mode == SIXEL_QUALITY_HIGHCOLOR)) {
34,891!
102
            if (target <= SIZE_MAX / 2u) {
×
103
                target *= 2u;
×
104
            } else {
105
                target = SIZE_MAX;
106
            }
107
        } else if (config != NULL
34,891!
108
                && config->quality_mode == SIXEL_QUALITY_FULL) {
34,891!
109
            if (target <= SIZE_MAX / 4u) {
3!
110
                target *= 4u;
3✔
111
            } else {
3✔
112
                target = SIZE_MAX;
113
            }
114
        }
3✔
115
    }
116

117
    total = (size_t)width * (size_t)height;
34,915✔
118
    while (stride < total && total / (stride * stride) > target) {
36,198!
119
        ++stride;
1,283✔
120
    }
121

122
    return stride;
27,173✔
123
}
17,947✔
124

125
static SIXELSTATUS
126
sixel_filter_sample_create_frame(sixel_allocator_t *allocator,
34,915✔
127
                                 sixel_frame_interface_t **frame_out)
128
{
129
    SIXELSTATUS status;
18,102✔
130

131
    status = SIXEL_FALSE;
34,915✔
132

133
    if (allocator == NULL || frame_out == NULL) {
34,915!
134
        return SIXEL_BAD_ARGUMENT;
135
    }
136

137
    status = sixel_frame_create_interface_from_factory(allocator, frame_out);
34,915✔
138
    if (SIXEL_FAILED(status)) {
34,915!
139
        return status;
140
    }
141

142
    if (*frame_out == NULL || (*frame_out)->vtbl == NULL ||
51,314!
143
        (*frame_out)->vtbl->init_pixels == NULL ||
34,915!
144
        (*frame_out)->vtbl->set_timeline == NULL ||
34,915!
145
        (*frame_out)->vtbl->set_transparency == NULL ||
34,915!
146
        (*frame_out)->vtbl->unref == NULL) {
34,915!
147
        return SIXEL_BAD_ARGUMENT;
148
    }
149

150
    return SIXEL_OK;
27,173✔
151
}
17,947✔
152

153
static SIXELSTATUS
154
sixel_filter_sample_copy_frame(
34,915✔
155
        sixel_filter_sample_config_t const *config,
156
        sixel_frame_t *frame,
157
        sixel_allocator_t *allocator,
158
        sixel_frame_t **sample_out,
159
        sixel_timeline_logger_t *logger,
160
        int *sample_width_out,
161
        int *sample_height_out)
162
{
163
    SIXELSTATUS status;
18,102✔
164
    sixel_frame_t *sample;
18,102✔
165
    sixel_frame_interface_t *frame_if;
18,102✔
166
    sixel_frame_interface_t *sample_if;
18,102✔
167
    sixel_frame_vtbl_t const *sample_vtbl;
18,102✔
168
    sixel_frame_pixels_request_t pixels_request;
18,102✔
169
    sixel_frame_timeline_t timeline;
18,102✔
170
    sixel_frame_transparency_t src_transparency;
18,102✔
171
    sixel_frame_transparency_t dst_transparency;
18,102✔
172
    unsigned char *src_pixels;
18,102✔
173
    unsigned char *dst_pixels;
18,102✔
174
    unsigned char const *src_mask;
18,102✔
175
    unsigned char *dst_mask;
18,102✔
176
    size_t stride;
18,102✔
177
    size_t src_pixel_count;
18,102✔
178
    int clip_x;
18,102✔
179
    int clip_y;
18,102✔
180
    int clip_w;
18,102✔
181
    int clip_h;
18,102✔
182
    int src_width;
18,102✔
183
    int src_height;
18,102✔
184
    int src_pixelformat;
18,102✔
185
    int normalized_src_pixelformat;
18,102✔
186
    int width;
18,102✔
187
    int height;
18,102✔
188
    int depth;
18,102✔
189
    int sample_width;
18,102✔
190
    int sample_height;
18,102✔
191
    size_t sample_count;
18,102✔
192
    size_t payload_size;
18,102✔
193
    size_t mask_size;
18,102✔
194
    size_t dst_index;
18,102✔
195
    size_t src_offset;
18,102✔
196
    int x;
18,102✔
197
    int y;
18,102✔
198
    unsigned char *normalized_src_pixels;
18,102✔
199

200
    status = SIXEL_FALSE;
34,915✔
201
    sample = NULL;
34,915✔
202
    frame_if = NULL;
34,915✔
203
    sample_if = NULL;
34,915✔
204
    sample_vtbl = NULL;
34,915✔
205
    memset(&pixels_request, 0, sizeof(pixels_request));
34,915!
206
    memset(&timeline, 0, sizeof(timeline));
34,915✔
207
    memset(&src_transparency, 0, sizeof(src_transparency));
34,915✔
208
    memset(&dst_transparency, 0, sizeof(dst_transparency));
34,915✔
209
    src_pixels = NULL;
34,915✔
210
    dst_pixels = NULL;
34,915✔
211
    src_mask = NULL;
34,915✔
212
    dst_mask = NULL;
34,915✔
213
    stride = 1u;
34,915✔
214
    src_pixel_count = 0u;
34,915✔
215
    clip_x = 0;
34,915✔
216
    clip_y = 0;
34,915✔
217
    clip_w = 0;
34,915✔
218
    clip_h = 0;
34,915✔
219
    src_width = 0;
34,915✔
220
    src_height = 0;
34,915✔
221
    src_pixelformat = SIXEL_PIXELFORMAT_RGB888;
34,915✔
222
    normalized_src_pixelformat = SIXEL_PIXELFORMAT_RGB888;
34,915✔
223
    width = 0;
34,915✔
224
    height = 0;
34,915✔
225
    depth = 0;
34,915✔
226
    sample_width = 0;
34,915✔
227
    sample_height = 0;
34,915✔
228
    sample_count = 0u;
34,915✔
229
    payload_size = 0u;
34,915✔
230
    mask_size = 0u;
34,915✔
231
    dst_index = 0u;
34,915✔
232
    src_offset = 0u;
34,915✔
233
    x = 0;
34,915✔
234
    y = 0;
34,915✔
235
    normalized_src_pixels = NULL;
34,915✔
236

237
    if (frame == NULL || sample_out == NULL) {
34,915!
238
        return SIXEL_BAD_ARGUMENT;
239
    }
240
    frame_if = sixel_frame_as_interface(frame);
34,915✔
241
    src_pixelformat = sixel_frame_get_pixelformat(frame);
34,915✔
242
    if ((src_pixelformat & SIXEL_FORMATTYPE_PALETTE)) {
34,915!
243
        return SIXEL_FEATURE_ERROR;
244
    }
245

246
    src_pixels = sixel_frame_get_pixels(frame);
34,915✔
247
    src_width = sixel_frame_get_width(frame);
34,915✔
248
    src_height = sixel_frame_get_height(frame);
34,915✔
249
    status = frame_if->vtbl->get_transparency(frame_if, &src_transparency);
34,915✔
250
    if (SIXEL_FAILED(status)) {
34,915!
251
        return status;
252
    }
253
    status = frame_if->vtbl->get_timeline(frame_if, &timeline);
34,915✔
254
    if (SIXEL_FAILED(status)) {
34,915!
255
        return status;
256
    }
257
    src_mask = src_transparency.transparent_mask;
34,915✔
258
    src_pixel_count = (size_t)src_width * (size_t)src_height;
34,915✔
259

260
    if (src_pixels == NULL) {
34,915!
261
        return SIXEL_BAD_ARGUMENT;
262
    }
263
    if (src_width > 0 && src_height > 0 &&
34,915!
264
        src_pixel_count / (size_t)src_height != (size_t)src_width) {
34,915!
265
        return SIXEL_RUNTIME_ERROR;
266
    }
267

268
    /*
269
     * Packed grayscale frames use sub-byte storage, but the sampling loop
270
     * below advances with byte-based offsets. Normalize packed inputs first
271
     * so clip/stride calculations cannot read beyond source row boundaries.
272
     */
273
    if (src_pixelformat == SIXEL_PIXELFORMAT_G1 ||
51,314!
274
            src_pixelformat == SIXEL_PIXELFORMAT_G2 ||
34,915!
275
            src_pixelformat == SIXEL_PIXELFORMAT_G4) {
17,947!
276
        normalized_src_pixels = (unsigned char *)sixel_allocator_malloc(
×
277
            allocator, src_pixel_count);
278
        if (normalized_src_pixels == NULL) {
×
279
            return SIXEL_BAD_ALLOCATION;
280
        }
281
        normalized_src_pixelformat = src_pixelformat;
×
282
        status = sixel_helper_normalize_pixelformat(
×
283
            normalized_src_pixels,
284
            &normalized_src_pixelformat,
285
            src_pixels,
286
            src_pixelformat,
287
            src_width,
288
            src_height);
289
        if (SIXEL_FAILED(status)) {
×
290
            sixel_allocator_free(allocator, normalized_src_pixels);
×
291
            return status;
×
292
        }
293
        src_pixels = normalized_src_pixels;
×
294
        src_pixelformat = normalized_src_pixelformat;
×
295
    }
296

297
    depth = sixel_helper_compute_depth(src_pixelformat);
34,915✔
298
    if (depth <= 0) {
34,915!
299
        sixel_allocator_free(allocator, normalized_src_pixels);
×
300
        return SIXEL_BAD_ARGUMENT;
×
301
    }
302

303
    /*
304
     * The logger is currently unused, but it will be wired once planner
305
     * driven progress messages are emitted from the filter layer.
306
     */
307
    (void)logger;
25,689✔
308

309
    if (config != NULL) {
34,915!
310
        clip_x = config->clip_x;
34,915✔
311
        clip_y = config->clip_y;
34,915✔
312
        clip_w = config->clip_width;
34,915✔
313
        clip_h = config->clip_height;
34,915✔
314
    }
17,947✔
315

316
    if (clip_w <= 0 || clip_h <= 0) {
37,089!
317
        clip_x = 0;
27,114✔
318
        clip_y = 0;
27,114✔
319
        clip_w = src_width;
27,114✔
320
        clip_h = src_height;
27,114✔
321
    } else {
17,914✔
322
        if (clip_w + clip_x > src_width) {
81!
323
            if (clip_x > src_width) {
×
324
                clip_w = 0;
325
            } else {
326
                clip_w = src_width - clip_x;
×
327
            }
328
        }
329

330
        if (clip_h + clip_y > src_height) {
78!
331
            if (clip_y > src_height) {
×
332
                clip_h = 0;
333
            } else {
334
                clip_h = src_height - clip_y;
×
335
            }
336
        }
337

338
        if (clip_w <= 0 || clip_h <= 0) {
81!
339
            sixel_allocator_free(allocator, normalized_src_pixels);
×
340
            return SIXEL_BAD_ARGUMENT;
×
341
        }
342
    }
343

344
    width = clip_w;
34,915✔
345
    height = clip_h;
34,915✔
346

347
    stride = sixel_filter_sample_select_stride(config, width, height);
34,915✔
348
    sample_width = (width + (int)stride - 1) / (int)stride;
34,915✔
349
    sample_height = (height + (int)stride - 1) / (int)stride;
34,915✔
350
    if (sample_width <= 0 || sample_height <= 0) {
34,915!
351
        sixel_allocator_free(allocator, normalized_src_pixels);
×
352
        return SIXEL_BAD_ARGUMENT;
×
353
    }
354

355
    if (sample_width_out != NULL) {
34,915!
356
        *sample_width_out = sample_width;
×
357
    }
358
    if (sample_height_out != NULL) {
32,740✔
359
        *sample_height_out = sample_height;
48✔
360
    }
18✔
361

362
    sample_count = (size_t)sample_width * (size_t)sample_height;
34,915✔
363
    if (sample_count != 0u
34,915!
364
            && sample_count / (size_t)sample_height != (size_t)sample_width) {
34,915!
365
        sixel_allocator_free(allocator, normalized_src_pixels);
×
366
        return SIXEL_RUNTIME_ERROR;
×
367
    }
368

369
    payload_size = sample_count * (size_t)depth;
34,915✔
370
    if (sample_count != 0u && payload_size / sample_count != (size_t)depth) {
34,915!
371
        sixel_allocator_free(allocator, normalized_src_pixels);
×
372
        return SIXEL_RUNTIME_ERROR;
×
373
    }
374

375
    status = sixel_filter_sample_create_frame(allocator, &sample_if);
34,915✔
376
    if (SIXEL_FAILED(status)) {
34,915!
377
        sixel_allocator_free(allocator, normalized_src_pixels);
×
378
        return status;
×
379
    }
380
    if (sample_if == NULL || sample_if->vtbl == NULL) {
34,915!
381
        sixel_allocator_free(allocator, normalized_src_pixels);
×
382
        return SIXEL_BAD_ARGUMENT;
×
383
    }
384
    sample_vtbl = sample_if->vtbl;
34,915✔
385
    if (sample_vtbl->init_pixels == NULL ||
51,314!
386
        sample_vtbl->set_timeline == NULL ||
34,915!
387
        sample_vtbl->set_transparency == NULL ||
34,915!
388
        sample_vtbl->unref == NULL) {
34,915!
389
        sixel_allocator_free(allocator, normalized_src_pixels);
×
390
        return SIXEL_BAD_ARGUMENT;
×
391
    }
392
    sample = (sixel_frame_t *)sample_if;
34,915✔
393
    dst_pixels = (unsigned char *)sixel_allocator_malloc(allocator,
52,862✔
394
                                                         payload_size);
17,947✔
395
    if (dst_pixels == NULL) {
34,915!
396
        sample_vtbl->unref(sample_if);
×
397
        sixel_allocator_free(allocator, normalized_src_pixels);
×
398
        return SIXEL_BAD_ALLOCATION;
×
399
    }
400

401
    pixels_request.pixels = dst_pixels;
34,915✔
402
    pixels_request.palette = NULL;
34,915✔
403
    pixels_request.width = sample_width;
34,915✔
404
    pixels_request.height = sample_height;
34,915✔
405
    pixels_request.pixelformat = src_pixelformat;
34,915✔
406
    pixels_request.colorspace = sixel_frame_get_colorspace(frame);
34,915✔
407
    pixels_request.ncolors = (-1);
34,915✔
408
    pixels_request.kind = SIXEL_FRAME_PIXELS_U8;
34,915✔
409

410
    status = sample_vtbl->init_pixels(sample_if, &pixels_request);
34,915✔
411
    if (SIXEL_FAILED(status)) {
34,915!
412
        sixel_allocator_free(allocator, dst_pixels);
×
413
        sample_vtbl->unref(sample_if);
×
414
        sixel_allocator_free(allocator, normalized_src_pixels);
×
415
        return status;
×
416
    }
417

418
    /*
419
     * Preserve timeline metadata so downstream palette/quantize stages can
420
     * apply frame-history logic even when the palette path runs on sampled
421
     * frames.
422
     */
423
    timeline.handoff_shareable = 0;
34,915✔
424
    status = sample_vtbl->set_timeline(sample_if, &timeline);
34,915✔
425
    if (SIXEL_FAILED(status)) {
34,915!
426
        sample_vtbl->unref(sample_if);
×
427
        sixel_allocator_free(allocator, normalized_src_pixels);
×
428
        return status;
×
429
    }
430

431
    dst_transparency.transparent = src_transparency.transparent;
34,915✔
432
    dst_transparency.alpha_zero_is_transparent =
34,915✔
433
        src_transparency.alpha_zero_is_transparent;
34,915✔
434
    if (src_mask != NULL &&
34,915!
435
        src_transparency.transparent_mask_size >= src_pixel_count) {
2,231!
436
        mask_size = sample_count;
2,231✔
437
        dst_mask = (unsigned char *)sixel_allocator_malloc(allocator,
3,340✔
438
                                                           mask_size);
1,109✔
439
        if (dst_mask == NULL) {
2,231!
440
            sample_vtbl->unref(sample_if);
×
441
            sixel_allocator_free(allocator, normalized_src_pixels);
×
442
            return SIXEL_BAD_ALLOCATION;
×
443
        }
444
        dst_transparency.transparent_mask = dst_mask;
2,231✔
445
        dst_transparency.transparent_mask_size = mask_size;
2,231✔
446
    }
1,109✔
447
    status = sample_vtbl->set_transparency(sample_if, &dst_transparency);
34,915✔
448
    if (SIXEL_FAILED(status)) {
34,915!
449
        sixel_allocator_free(allocator, dst_mask);
×
450
        sample_vtbl->unref(sample_if);
×
451
        sixel_allocator_free(allocator, normalized_src_pixels);
×
452
        return status;
×
453
    }
454

455
    dst_index = 0u;
27,173✔
456
    for (y = 0; y < height; y += (int)stride) {
941,797!
457
        for (x = 0; x < width; x += (int)stride) {
46,711,279!
458
            src_offset = ((size_t)(clip_y + y) * (size_t)src_width
69,988,035✔
459
                       + (size_t)(clip_x + x))
45,804,397✔
460
                       * (size_t)depth;
45,804,397✔
461
            memcpy(dst_pixels + dst_index * (size_t)depth,
47,818,029✔
462
                   src_pixels + src_offset,
23,634,391✔
463
                   (size_t)depth);
2,013,632✔
464
            if (dst_mask != NULL) {
45,804,397✔
465
                dst_mask[dst_index] =
7,744,628✔
466
                    src_mask[(size_t)(clip_y + y) * (size_t)src_width
11,488,006✔
467
                             + (size_t)(clip_x + x)];
5,925,878✔
468
            }
3,743,378✔
469
            ++dst_index;
45,804,397✔
470
        }
24,183,638✔
471

472
    }
475,359✔
473

474
    *sample_out = sample;
34,915✔
475
    sixel_allocator_free(allocator, normalized_src_pixels);
34,915✔
476

477
    return SIXEL_OK;
34,915✔
478
}
17,947✔
479

480
SIXELSTATUS
481
sixel_filter_sample_frame(const sixel_filter_sample_config_t *config,
34,867✔
482
                          sixel_frame_t *frame,
483
                          sixel_allocator_t *allocator,
484
                          sixel_frame_t **sample_out,
485
                          sixel_timeline_logger_t *logger)
486
{
487
    SIXELSTATUS status;
18,078✔
488

489
    status = sixel_filter_sample_copy_frame(config, frame, allocator,
52,796✔
490
                                            sample_out, logger, NULL, NULL);
17,929✔
491

492
    return status;
45,217✔
493
}
10,350✔
494

495
static SIXELSTATUS
496
sixel_filter_sample_apply(sixel_filter_t *filter,
48✔
497
                          sixel_allocator_t *allocator,
498
                          sixel_timeline_logger_t *logger)
499
{
500
    SIXELSTATUS status;
24✔
501
    sixel_filter_sample_state_t *state;
24✔
502
    sixel_frame_t *input_frame;
24✔
503
    sixel_frame_t *sample;
24✔
504
    int sample_height;
24✔
505

506
    if (filter == NULL || allocator == NULL) {
48!
507
        return SIXEL_BAD_ARGUMENT;
508
    }
509

510
    state = (sixel_filter_sample_state_t *)filter->userdata;
48✔
511
    if (state == NULL) {
48!
512
        return SIXEL_BAD_ARGUMENT;
513
    }
514

515
    if (filter->input.slot == NULL || filter->output.slot == NULL) {
48!
516
        return SIXEL_BAD_ARGUMENT;
517
    }
518

519
    input_frame = *(filter->input.slot);
48✔
520
    if (input_frame == NULL) {
48!
521
        return SIXEL_BAD_ARGUMENT;
522
    }
523

524
    if (*(filter->output.slot) != NULL) {
48!
525
        sixel_frame_unref(*(filter->output.slot));
×
526
        *(filter->output.slot) = NULL;
×
527
    }
528

529
    sample_height = 0;
48✔
530
    status = sixel_filter_sample_copy_frame(&state->config, input_frame,
66✔
531
                                            allocator, &sample, logger,
18✔
532
                                            NULL, &sample_height);
533
    if (SIXEL_SUCCEEDED(status)) {
48!
534
        *(filter->output.slot) = sample;
48✔
535
        if (sample_height > 0) {
48!
536
            filter->progress.total_units = sample_height;
48✔
537
            filter->progress.completed_units = sample_height;
48✔
538
            sixel_filter_update_progress(filter, sample_height);
48✔
539
        }
18✔
540
    }
18✔
541

542
    return status;
34✔
543
}
18✔
544

545
static void
546
sixel_filter_sample_dispose(sixel_filter_t *filter)
48✔
547
{
548
    sixel_filter_sample_state_t *state;
24✔
549

550
    if (filter == NULL) {
48✔
551
        return;
552
    }
553

554
    state = (sixel_filter_sample_state_t *)filter->userdata;
48✔
555
    if (state != NULL) {
48!
556
        free(state);
48✔
557
    }
18✔
558
}
18!
559

560
SIXELSTATUS
561
sixel_filter_sample_init(sixel_filter_t *filter,
48✔
562
                         const sixel_filter_sample_config_t *config)
563
{
564
    SIXELSTATUS status;
24✔
565
    sixel_filter_sample_state_t *state;
24✔
566

567
    if (filter == NULL || config == NULL) {
48!
568
        return SIXEL_BAD_ARGUMENT;
569
    }
570

571
    state = (sixel_filter_sample_state_t *)malloc(sizeof(*state));
48✔
572
    if (state == NULL) {
48!
573
        return SIXEL_BAD_ALLOCATION;
574
    }
575

576
    state->config = *config;
48✔
577

578
    status = sixel_filter_init_with_vtbl(
48✔
579
        filter,
18✔
580
        &sixel_filter_sample_vtbl,
581
        state);
18✔
582
    if (SIXEL_FAILED(status)) {
48!
583
        free(state);
×
584
    }
585

586
    return status;
34✔
587
}
18✔
588

589
/* emacs Local Variables:      */
590
/* emacs mode: c               */
591
/* emacs tab-width: 4          */
592
/* emacs indent-tabs-mode: nil */
593
/* emacs c-basic-offset: 4     */
594
/* emacs End:                  */
595
/* vim: set expandtab ts=4 sts=4 sw=4 : */
596
/* 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