129 {
130 if (!rgba_data || src_width <= 0 || src_height <= 0) {
131 return NULL;
132 }
133
134
135 int dst_width = GET_OPTION(width);
136 int dst_height = GET_OPTION(height);
137 color_filter_t filter = (color_filter_t)GET_OPTION(color_filter);
138 terminal_color_mode_t color_mode = (terminal_color_mode_t)GET_OPTION(color_mode);
139 palette_type_t palette_type = (palette_type_t)GET_OPTION(palette_type);
141 bool stretch = false;
142
143
144 terminal_capabilities_t caps = {0};
145 caps.color_level = color_mode;
146 caps.capabilities = 0;
147 caps.color_count = (color_mode == TERM_COLOR_NONE) ? 0
148 : (color_mode == TERM_COLOR_16) ? 16
149 : (color_mode == TERM_COLOR_256) ? 256
150 : 16777216;
151 caps.utf8_support = true;
152 caps.detection_reliable = true;
153 caps.render_mode = (render_mode_t)GET_OPTION(render_mode);
154 caps.wants_background = false;
155 caps.palette_type = palette_type;
156 caps.desired_fps = 60;
157 caps.color_filter = filter;
158
159
160 rgb_pixel_t *rgb_pixels = SAFE_MALLOC(src_width * src_height * sizeof(rgb_pixel_t), rgb_pixel_t *);
161 if (!rgb_pixels) {
162 return NULL;
163 }
164
165 bool flip = GET_OPTION(flip_x);
166 for (int y = 0; y < src_height; y++) {
167 for (int x = 0; x < src_width; x++) {
168 int src_x = flip ? (src_width - 1 - x) : x;
169 int src_idx = (y * src_width + src_x) * 4;
170 int dst_idx = y * src_width + x;
171
172 rgb_pixels[dst_idx].r = rgba_data[src_idx + 0];
173 rgb_pixels[dst_idx].g = rgba_data[src_idx + 1];
174 rgb_pixels[dst_idx].b = rgba_data[src_idx + 2];
175
176 }
177 }
178
179
180 if (filter != COLOR_FILTER_NONE && filter != COLOR_FILTER_RAINBOW) {
181
182 uint8_t *rgb24 = (uint8_t *)rgb_pixels;
183 int stride = src_width * 3;
184 float time_seconds = (float)(emscripten_get_now() / 1000.0);
186 }
187
188
189 image_t img = {.w = src_width, .h = src_height, .pixels = rgb_pixels, .alloc_method = IMAGE_ALLOC_SIMD};
190
191
192 const char *palette_chars;
193 switch (palette_type) {
194 case PALETTE_BLOCKS:
195 palette_chars = PALETTE_CHARS_BLOCKS;
196 break;
197 case PALETTE_DIGITAL:
198 palette_chars = PALETTE_CHARS_DIGITAL;
199 break;
200 case PALETTE_MINIMAL:
201 palette_chars = PALETTE_CHARS_MINIMAL;
202 break;
203 case PALETTE_COOL:
204 palette_chars = PALETTE_CHARS_COOL;
205 break;
206 case PALETTE_CUSTOM:
207
208 palette_chars = GET_OPTION(palette_custom);
209 if (!palette_chars || palette_chars[0] == '\0') {
210 palette_chars = PALETTE_CHARS_STANDARD;
211 }
212 break;
213 case PALETTE_STANDARD:
214 default:
215 palette_chars = PALETTE_CHARS_STANDARD;
216 break;
217 }
218
219
220 char *ascii_output =
222
223
224 SAFE_FREE(rgb_pixels);
225
226 if (!ascii_output) {
227 log_error("ascii_convert_with_capabilities returned NULL");
228 return NULL;
229 }
230
231
232
233 if (filter == COLOR_FILTER_RAINBOW) {
234 float time_seconds = (float)(emscripten_get_now() / 1000.0);
236 if (rainbow_output) {
237 SAFE_FREE(ascii_output);
238 ascii_output = rainbow_output;
239 }
240 }
241
242
243 bool matrix_rain = GET_OPTION(matrix_rain);
244 if (matrix_rain) {
245
246 if (!g_digital_rain || g_digital_rain->num_columns != dst_width || g_digital_rain->num_rows != dst_height) {
247 if (g_digital_rain) {
249 }
250 if (g_last_rain_output) {
251 SAFE_FREE(g_last_rain_output);
252 g_last_rain_output = NULL;
253 }
255 if (!g_digital_rain) {
256 log_error("Failed to initialize digital rain effect");
257 return ascii_output;
258 }
259 g_last_rain_update_time = emscripten_get_now();
260 }
261
262
264
265
266 double current_time = emscripten_get_now();
267 double elapsed_ms = current_time - g_last_rain_update_time;
268
270
271 float delta_time = (float)(elapsed_ms / 1000.0);
272 g_last_rain_update_time = current_time;
273
274
276 if (rain_output) {
277
278 if (g_last_rain_output) {
279 SAFE_FREE(g_last_rain_output);
280 }
281
282 g_last_rain_output = strdup(rain_output);
283
284 SAFE_FREE(ascii_output);
285 ascii_output = rain_output;
286 }
287 } else if (g_last_rain_output) {
288
289 SAFE_FREE(ascii_output);
290 ascii_output = strdup(g_last_rain_output);
291 }
292 } else {
293
294 if (g_digital_rain) {
296 g_digital_rain = NULL;
297 }
298 if (g_last_rain_output) {
299 SAFE_FREE(g_last_rain_output);
300 g_last_rain_output = NULL;
301 }
302 g_last_rain_update_time = 0.0;
303 }
304
305 return ascii_output;
306}
char * ascii_convert_with_capabilities(image_t *original, const ssize_t width, const ssize_t height, const terminal_capabilities_t *caps, const bool use_aspect_ratio, const bool stretch, const char *palette_chars)
void aspect_ratio(const ssize_t img_w, const ssize_t img_h, const ssize_t width, const ssize_t height, const bool stretch, ssize_t *out_width, ssize_t *out_height)
char * rainbow_replace_ansi_colors(const char *ansi_string, float time_seconds)
int apply_color_filter(uint8_t *pixels, uint32_t width, uint32_t height, uint32_t stride, color_filter_t filter, float time)
void digital_rain_set_color_from_filter(digital_rain_t *rain, color_filter_t filter)
char * digital_rain_apply(digital_rain_t *rain, const char *frame, float delta_time)
digital_rain_t * digital_rain_init(int num_columns, int num_rows)
#define RAIN_UPDATE_INTERVAL_MS