ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
ascii_wasm.c File Reference

Go to the source code of this file.

Functions

char * ascii_convert (image_t *original, const ssize_t width, const ssize_t height, const bool color, const bool _aspect_ratio, const bool stretch, const char *palette_chars, const char luminance_palette[256])
 
int build_client_luminance_palette (const char *palette_chars, size_t palette_len, char luminance_mapping[256])
 
EMSCRIPTEN_KEEPALIVE char * convert_frame_to_ascii (uint8_t *rgba_data, int width, int height, int ascii_width, int ascii_height)
 
EMSCRIPTEN_KEEPALIVE void free_ascii_buffer (char *buffer)
 

Function Documentation

◆ ascii_convert()

char * ascii_convert ( image_t *  original,
const ssize_t  width,
const ssize_t  height,
const bool  color,
const bool  _aspect_ratio,
const bool  stretch,
const char *  palette_chars,
const char  luminance_palette[256] 
)
extern

Definition at line 69 of file ascii.c.

71 {
72 if (original == NULL || !palette_chars || !luminance_palette) {
73 log_error("ascii_convert: invalid parameters");
74 return NULL;
75 }
76
77 // Check for empty strings
78 if (palette_chars[0] == '\0' || luminance_palette[0] == '\0') {
79 log_error("ascii_convert: empty palette strings");
80 return NULL;
81 }
82
83 // Start with the target dimensions requested by the user (or detected from
84 // the terminal). These can be modified by aspect_ratio() if stretching is
85 // disabled and one of the dimensions was left to be calculated
86 // automatically.
87 ssize_t resized_width = width;
88 ssize_t resized_height = height;
89
90 // If stretch is enabled, use full dimensions, otherwise calculate aspect ratio
91 if (_aspect_ratio) {
92 // The server now provides images at width*2 x height pixels
93 // The aspect_ratio function will handle terminal character aspect ratio
94 aspect_ratio(original->w, original->h, resized_width, resized_height, stretch, &resized_width, &resized_height);
95 }
96
97 // Calculate padding for centering
98 size_t pad_width = 0;
99 size_t pad_height = 0;
100
101 if (_aspect_ratio) {
102 // Only calculate padding when not stretching
103 ssize_t pad_width_ss = width > resized_width ? (width - resized_width) / 2 : 0;
104 pad_width = (size_t)pad_width_ss;
105
106 ssize_t pad_height_ss = height > resized_height ? (height - resized_height) / 2 : 0;
107 pad_height = (size_t)pad_height_ss;
108 }
109
110 // Resize the captured frame to the aspect-correct dimensions.
111 if (resized_width <= 0 || resized_height <= 0) {
112 log_error("Invalid dimensions for resize: width=%zd, height=%zd", resized_width, resized_height);
113 return NULL;
114 }
115
116 // Validate dimensions fit in image_t's int fields before casting
117 if (resized_width > INT_MAX || resized_height > INT_MAX) {
118 log_error("Dimensions exceed INT_MAX: width=%zd, height=%zd", resized_width, resized_height);
119 return NULL;
120 }
121
122 // Always resize to target dimensions
123 image_t *resized = image_new((size_t)resized_width, (size_t)resized_height);
124 if (!resized) {
125 log_error("Failed to allocate resized image");
126 return NULL;
127 }
128
129 image_clear(resized);
130 image_resize(original, resized);
131
132 char *ascii;
133 if (color) {
134 // Check for half-block mode first (requires NEON)
135 if (GET_OPTION(render_mode) == RENDER_MODE_HALF_BLOCK) {
136#if SIMD_SUPPORT_NEON
137 // Use NEON half-block renderer
138 const uint8_t *rgb_data = (const uint8_t *)resized->pixels;
139 ascii = rgb_to_truecolor_halfblocks_neon(rgb_data, resized->w, resized->h, 0);
140#else
141 log_error("Half-block mode requires NEON support (ARM architecture)");
142 image_destroy(resized);
143 return NULL;
144#endif
145 } else {
146#ifdef SIMD_SUPPORT
147 // Standard color modes (foreground/background)
148 bool use_background = (GET_OPTION(render_mode) == RENDER_MODE_BACKGROUND);
149 ascii = image_print_color_simd(resized, use_background, false, palette_chars);
150#else
151 ascii = image_print_color(resized, palette_chars);
152#endif
153 }
154 } else {
155 // Use grayscale/monochrome conversion with client's palette
156#ifdef SIMD_SUPPORT
157 ascii = image_print_simd(resized, luminance_palette);
158#else
159 ascii = image_print(resized, palette_chars);
160#endif
161 }
162
163 if (!ascii) {
164 log_error("Failed to convert image to ASCII");
165 image_destroy(resized);
166 return NULL;
167 }
168
169 size_t ascii_len = strlen(ascii);
170 if (ascii_len == 0) {
171 log_error("ASCII conversion returned empty string (resized dimensions: %dx%d)", resized->w, resized->h);
172 SAFE_FREE(ascii);
173 image_destroy(resized);
174 return NULL;
175 }
176
177 char *ascii_width_padded = ascii_pad_frame_width(ascii, pad_width);
178 SAFE_FREE(ascii);
179
180 char *ascii_padded = ascii_pad_frame_height(ascii_width_padded, pad_height);
181 SAFE_FREE(ascii_width_padded);
182
183 // Only destroy resized if we allocated it (not when using original directly)
184 image_destroy(resized);
185
186 return ascii_padded;
187}
char * ascii_pad_frame_width(const char *frame, size_t pad_left)
Definition ascii.c:398
char * ascii_pad_frame_height(const char *frame, size_t pad_top)
Definition ascii.c:842
char * image_print_simd(image_t *image, const char *ascii_chars)
Definition ascii_simd.c:260
char * image_print_color_simd(image_t *image, bool use_background_mode, bool use_256color, const char *ascii_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 * image_print(const image_t *p, const char *palette)
char * image_print_color(const image_t *p, const char *palette)
void image_resize(const image_t *s, image_t *d)
void image_clear(image_t *p)
void image_destroy(image_t *p)
Definition video/image.c:85
image_t * image_new(size_t width, size_t height)
Definition video/image.c:36

References ascii_pad_frame_height(), ascii_pad_frame_width(), aspect_ratio(), image_clear(), image_destroy(), image_new(), image_print(), image_print_color(), image_print_color_simd(), image_print_simd(), and image_resize().

Referenced by benchmark_simd_color_conversion_with_source(), and convert_frame_to_ascii().

◆ build_client_luminance_palette()

int build_client_luminance_palette ( const char *  palette_chars,
size_t  palette_len,
char  luminance_mapping[256] 
)
extern

Definition at line 279 of file palette.c.

279 {
280 if (!palette_chars || palette_len == 0 || !luminance_mapping) {
281 SET_ERRNO(ERROR_INVALID_PARAM, "Invalid parameters for client luminance palette");
282 return -1;
283 }
284
285 // Map 256 luminance values to palette indices for this specific client
286 for (int i = 0; i < 256; i++) {
287 // Linear mapping with proper rounding
288 size_t palette_index = (i * (palette_len - 1) + 127) / 255;
289 if (palette_index >= palette_len) {
290 palette_index = palette_len - 1;
291 }
292 luminance_mapping[i] = palette_chars[palette_index];
293 }
294
295 return 0;
296}

Referenced by initialize_client_palette().

◆ convert_frame_to_ascii()

EMSCRIPTEN_KEEPALIVE char * convert_frame_to_ascii ( uint8_t *  rgba_data,
int  width,
int  height,
int  ascii_width,
int  ascii_height 
)

Definition at line 39 of file ascii_wasm.c.

40 {
41 ensure_palette_initialized();
42
43 // Create image_t structure
44 image_t image;
45 image.w = width;
46 image.h = height;
47
48 // Allocate RGB pixel array (3 bytes per pixel)
49 image.pixels = (rgb_pixel_t *)malloc(width * height * sizeof(rgb_pixel_t));
50 if (!image.pixels) {
51 return NULL;
52 }
53
54 // Convert RGBA to RGB (skip alpha channel)
55 for (int i = 0; i < width * height; i++) {
56 image.pixels[i].r = rgba_data[i * 4 + 0];
57 image.pixels[i].g = rgba_data[i * 4 + 1];
58 image.pixels[i].b = rgba_data[i * 4 + 2];
59 // Skip alpha channel (rgba_data[i * 4 + 3])
60 }
61
62 // Call ascii_convert
63 // Parameters: image, target_width, target_height, color, aspect_ratio, stretch, palette, luminance
64 char *result = ascii_convert(&image, ascii_width, ascii_height,
65 false, // color: false for monochrome (simpler for MVP)
66 true, // aspect_ratio: true to maintain aspect
67 false, // stretch: false to preserve aspect ratio
68 WASM_PALETTE, g_luminance_palette);
69
70 // Free the temporary RGB buffer
71 free(image.pixels);
72
73 return result;
74}
char * ascii_convert(image_t *original, const ssize_t width, const ssize_t height, const bool color, const bool _aspect_ratio, const bool stretch, const char *palette_chars, const char luminance_palette[256])
Definition ascii.c:69

References ascii_convert().

◆ free_ascii_buffer()

EMSCRIPTEN_KEEPALIVE void free_ascii_buffer ( char *  buffer)

Definition at line 78 of file ascii_wasm.c.

78 {
79 if (buffer) {
80 free(buffer);
81 }
82}