Notcurses 3.0.13
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
sixel.h
Go to the documentation of this file.
1#ifndef NOTCURSES_LIB_SIXEL
2#define NOTCURSES_LIB_SIXEL
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8#include <ctype.h>
9#include <stdlib.h>
10#include "logging.h"
11
12uint32_t* ncsixel_as_rgba(const char *sx, unsigned leny, unsigned lenx){
13 if(!leny || !lenx){
14 logerror("null sixel geometry");
15 return NULL;
16 }
17#define MAXCOLORS 65535
18 // cast is necessary for c++ callers
19 uint32_t* rgba = (uint32_t*)calloc(leny * lenx, sizeof(*rgba));
20 if(rgba == NULL){
21 return NULL;
22 }
23 // cast is necessary for c++ callers
24 uint32_t* colors = (uint32_t*)calloc(MAXCOLORS, sizeof(*colors));
25 if(colors == NULL){
26 free(rgba);
27 return NULL;
28 }
29 // first we skip the header. it ends in either a color declaration, or a
30 // transparent line (the only possible colorless line).
31 while(*sx != '#' && *sx != '-'){
32 if(!*sx){
33 logerror("expected octothorpe/hyphen, got eol");
34 return NULL;
35 }
36 ++sx;
37 }
38 // now we build the color table (form: #Pc;Pu;Px;Py;Pz). data starts with
39 // a color spec lacking a semicolon.
40 enum {
41 STATE_WANT_HASH,
42 STATE_WANT_COLOR,
43 STATE_WANT_COLORSEMI,
44 STATE_WANT_COLORSPACE,
45 STATE_WANT_DATA,
46 } state = STATE_WANT_HASH;
47 unsigned color = 0;
48 unsigned x = 0;
49 unsigned y = 0;
50 unsigned rle = 1;
51 while(*sx){
52//fprintf(stderr, "SX: %u 0x%02x %c\n", *sx, *sx, *sx);
53 if(*sx == '\e'){
54 break;
55 }
56 if(state == STATE_WANT_HASH){
57 if(*sx == '-'){
58 x = 0;
59 y += 6;
60 }else if('#' == *sx){
61 state = STATE_WANT_COLOR;
62 }else{
63 logerror("expected octothorpe, got %u", *sx);
64 goto err;
65 }
66 }else if(state == STATE_WANT_COLOR){
67 if(!isdigit(*sx)){
68 logerror("expected digit, got %u", *sx);
69 goto err;
70 }
71 color = 0;
72 do{
73//fprintf(stderr, "SX: %u 0x%02x %c\n", *sx, *sx, *sx);
74 color *= 10;
75 color += *sx - '0';
76 ++sx;
77 }while(isdigit(*sx));
78//std::cerr << "Got color " << color << std::endl;
79 --sx;
80 state = STATE_WANT_COLORSEMI;
81 }else if(state == STATE_WANT_COLORSEMI){
82 // if we get a semicolon, we're a colorspec, otherwise data
83 if(*sx == ';'){
84 state = STATE_WANT_COLORSPACE;
85 }else{
86 state = STATE_WANT_DATA;
87 rle = 1;
88 }
89 }else if(state == STATE_WANT_COLORSPACE){
90 if('2' != *(sx++)){
91 logerror("expected '2', got %u", *sx);
92 goto err;
93 }
94//fprintf(stderr, "SX: %u 0x%02x %c\n", *sx, *sx, *sx);
95 if(';' != *(sx++)){
96 logerror("expected semicolon, got %u", *sx);
97 goto err;
98 }
99//fprintf(stderr, "SX: %u 0x%02x %c\n", *sx, *sx, *sx);
100 int r = 0;
101 do{
102 r *= 10;
103 r += *sx - '0';
104 ++sx;
105 }while(isdigit(*sx));
106 if(';' != *(sx++)){
107 logerror("expected semicolon, got %u", *sx);
108 goto err;
109 }
110//fprintf(stderr, "SX: %u 0x%02x %c\n", *sx, *sx, *sx);
111 r = r * 255 / 100;
112 int g = 0;
113 do{
114 g *= 10;
115 g += *sx - '0';
116 ++sx;
117 }while(isdigit(*sx));
118 if(';' != *(sx++)){
119 logerror("expected semicolon, got %u", *sx);
120 goto err;
121 }
122//fprintf(stderr, "SX: %u 0x%02x %c\n", *sx, *sx, *sx);
123 g = g * 255 / 100;
124 int b = 0;
125 do{
126 b *= 10;
127 b += *sx - '0';
128 ++sx;
129 }while(isdigit(*sx));
130 b = b * 255 / 100;
131 ncpixel_set_a(&colors[color], 0xff);
132 ncpixel_set_rgb8(&colors[color], r, g, b);
133//fprintf(stderr, "Got color %d: 0x%08x %u %u %u\n", color, colors[color], r, g, b);
134 if(color >= MAXCOLORS){
135 goto err;
136 }
137 state = STATE_WANT_HASH;
138 --sx;
139 }
140 // read until we hit next colorspec
141 if(state == STATE_WANT_DATA){
142//fprintf(stderr, "Character %c\n", *sx);
143 if(*sx == '#'){
144 state = STATE_WANT_HASH;
145 --sx;
146 }else if(*sx == '!'){ // RLE
147 ++sx;
148 rle = 0;
149 do{
150 rle *= 10;
151 rle += *sx - '0';
152 ++sx;
153 }while(isdigit(*sx));
154 if(0 == rle){
155 rle = 1;
156 }
157 --sx;
158 }else if(*sx == '$'){
159 x = 0;
160 state = STATE_WANT_DATA;
161 }else if(*sx == '-'){
162 x = 0;
163 y += 6;
164 state = STATE_WANT_DATA;
165 }else{
166//fprintf(stderr, "RLE: %d pos: %d x %d\n", rle, y, x);
167 if(y + 6 > (leny + 5) / 6 * 6){
168 logerror("too many rows %d + 6 > %d", y, (leny + 5) / 6 * 6);
169 goto err;
170 }
171 if(x + rle > lenx){
172 logerror("invalid rle %d + %d > %d", x, rle, lenx);
173 goto err;
174 }
175 for(unsigned xpos = x ; xpos < x + rle ; ++xpos){
176 for(unsigned ypos = y ; ypos < y + 6 ; ++ypos){
177 if((*sx - 63) & (1u << (ypos - y))){
178 // ought be an empty pixel
179//std::cerr << *s << " BMAP[" << ypos << "][" << xpos << "] = " << std::hex << colors[color] << std::dec << std::endl;
180 rgba[ypos * lenx + xpos] = colors[color];
181 }
182 }
183 }
184 x += rle;
185 rle = 1;
186 }
187 }
188 ++sx;
189 }
190 free(colors);
191 return rgba;
192
193err:
194 free(rgba);
195 free(colors);
196 return NULL;
197#undef MAXCOLORS
198}
199
200#ifdef __cplusplus
201}
202#endif
203
204#endif
free(duplicated)
int r
Definition fbuf.h:226
#define logerror(fmt,...)
Definition logging.h:32
int y
Definition notcurses.h:1905
int int x
Definition notcurses.h:1905
#define MAXCOLORS
uint32_t * ncsixel_as_rgba(const char *sx, unsigned leny, unsigned lenx)
Definition sixel.h:12
return NULL
Definition termdesc.h:229