You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.1 KiB
C
104 lines
3.1 KiB
C
#include "internal.h"
|
|
#ifdef USE_LIBSIXEL
|
|
#include <sixel/sixel.h>
|
|
|
|
typedef struct libsixel_closure {
|
|
char* buf;
|
|
int size;
|
|
} libsixel_closure;
|
|
|
|
static int
|
|
libsixel_writer(char* data, int size, void* priv){
|
|
libsixel_closure* closure = priv;
|
|
char* tmp = realloc(closure->buf, closure->size + size + 1);
|
|
if(tmp == NULL){
|
|
return -1;
|
|
}
|
|
closure->buf = tmp;
|
|
memcpy(closure->buf + closure->size, data, size);
|
|
closure->size += size;
|
|
closure->buf[closure->size] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
// libsixel wants to mutate its input, and can't accept arbitrary linesizes.
|
|
// create a space of 4 * leny * lenx, and copy in the source.
|
|
static void*
|
|
dup_for_libsixel(const void* data, int linesize, int leny, int lenx){
|
|
char* cpy = malloc(leny * lenx * 4);
|
|
if(cpy){
|
|
for(int y = 0 ; y < leny ; ++y){
|
|
memcpy(cpy + y * lenx * 4, (const char*)data + linesize * y, lenx * 4);
|
|
}
|
|
}
|
|
return cpy;
|
|
}
|
|
|
|
static int
|
|
libsixel_blit_inner(ncplane* nc, int linesize, const void* data,
|
|
int begy, int begx, int leny, int lenx,
|
|
const blitterargs* bargs){
|
|
int colors = bargs->pixel.colorregs > 256 ? 256 : bargs->pixel.colorregs;
|
|
(void)begy;
|
|
(void)begx;
|
|
void* cpy = dup_for_libsixel(data, linesize, leny, lenx);
|
|
if(cpy == NULL){
|
|
return -1;
|
|
}
|
|
libsixel_closure closure = { .buf = NULL, .size = 0, };
|
|
sixel_dither_t* dither = NULL;
|
|
sixel_output_t* output;
|
|
// FIXME provide bargs->pixels.colorregs
|
|
SIXELSTATUS status = sixel_dither_new(&dither, colors, NULL);
|
|
if(SIXEL_FAILED(status)){
|
|
free(cpy);
|
|
return -1;
|
|
}
|
|
status = sixel_dither_initialize(dither, cpy, lenx, leny, SIXEL_PIXELFORMAT_RGBA8888, SIXEL_LARGE_AUTO, SIXEL_REP_AUTO, SIXEL_QUALITY_AUTO);
|
|
if(SIXEL_FAILED(status)){
|
|
sixel_dither_destroy(dither);
|
|
free(cpy);
|
|
return -1;
|
|
}
|
|
if(SIXEL_OK != sixel_output_new(&output, libsixel_writer, &closure, NULL)){
|
|
sixel_dither_destroy(dither);
|
|
free(cpy);
|
|
return -1;
|
|
}
|
|
if(SIXEL_OK != sixel_encode(cpy, lenx, leny, 0, dither, output)){
|
|
sixel_output_destroy(output);
|
|
sixel_dither_destroy(dither);
|
|
free(closure.buf);
|
|
free(cpy);
|
|
return -1;
|
|
}
|
|
sixel_dither_destroy(dither);
|
|
sixel_output_destroy(output);
|
|
free(cpy);
|
|
unsigned cols = lenx / bargs->pixel.celldimx + !!(lenx % bargs->pixel.celldimx);
|
|
unsigned rows = leny / bargs->pixel.celldimy + !!(leny % bargs->pixel.celldimx);
|
|
if(closure.buf == NULL){
|
|
return -1;
|
|
}
|
|
if(plane_blit_sixel(nc, closure.buf, closure.size, rows, cols, bargs->pixel.sprixelid) < 0){
|
|
free(closure.buf);
|
|
return -1;
|
|
}
|
|
free(closure.buf);
|
|
return 1;
|
|
}
|
|
|
|
// sixel blitting implemented via libsixel. this gives superior output than our
|
|
// sixel blitter, with less overhead. it's better to use when available. if it
|
|
// fails, we fall back to our own.
|
|
int libsixel_blit(ncplane* nc, int linesize, const void* data,
|
|
int begy, int begx, int leny, int lenx,
|
|
const blitterargs* bargs){
|
|
int r = libsixel_blit_inner(nc, linesize, data, begy, begx, leny, lenx, bargs);
|
|
if(r < 0){
|
|
r = sixel_blit(nc, linesize, data, begy, begx, leny, lenx, bargs);
|
|
}
|
|
return r;
|
|
}
|
|
#endif
|