int main(int argc, char *argv[]) { caca_canvas_t *cv; int tests = 0, passed = 0; cv = caca_create_canvas(0, 0); caca_put_char(cv, 0, 0, 'x'); TEST(caca_get_char(cv, 0, 0) != 'x'); caca_rotate_180(cv); caca_set_canvas_size(cv, 1, 1); TEST(caca_get_char(cv, 0, 0) != 'x'); TEST(caca_get_char(cv, 0, 0) == ' '); caca_put_char(cv, 0, 0, 'y'); TEST(caca_get_char(cv, 0, 0) == 'y'); caca_set_canvas_size(cv, 1000, 1000); TEST(caca_get_canvas_width(cv) == 1000); caca_put_char(cv, 999, 999, 'z'); TEST(caca_get_char(cv, 999, 999) == 'z'); caca_free_canvas(cv); fprintf(stderr, "%i tests, %i errors\n", tests, tests - passed); return 0; }
static void filter_rainbow(context_t *cx) { static unsigned char const rainbow[] = { CACA_LIGHTMAGENTA, CACA_LIGHTRED, CACA_YELLOW, CACA_LIGHTGREEN, CACA_LIGHTCYAN, CACA_LIGHTBLUE, }; unsigned int x, y, w, h; w = caca_get_canvas_width(cx->torender); h = caca_get_canvas_height(cx->torender); for(y = 0; y < h; y++) for(x = 0; x < w; x++) { unsigned long int ch = caca_get_char(cx->torender, x, y); if(ch != (unsigned char)' ') { caca_set_color_ansi(cx->torender, rainbow[(x / 2 + y + cx->lines) % 6], CACA_TRANSPARENT); caca_put_char(cx->torender, x, y, ch); } } }
static void filter_america(context_t *cx) { unsigned int x, y, w, h, flag_w, flag_h; unsigned char color; w = caca_get_canvas_width(cx->torender); h = caca_get_canvas_height(cx->torender); flag_w = w * 3 / 7; flag_h = h * 1 / 3; /* flag_w = w; flag_h = h; */ for(y = 0; y < h; y++) for(x = 0; x < w; x++) { unsigned long int ch = caca_get_char(cx->torender, x, y); if(ch == (unsigned char)' ') continue; if((x < flag_w) && (y < flag_h)) // @todo this really needs to be better. color = ((x + y) % 2 && y % 2) ? CACA_WHITE : CACA_BLUE; else color = (y % 2) ? CACA_WHITE : CACA_RED; caca_set_color_ansi(cx->torender, color, CACA_TRANSPARENT); caca_put_char(cx->torender, x, y, ch); } }
/** \brief Print a string. * * Print an UTF-8 string at the given coordinates, using the default * foreground and background values. The coordinates may be outside the * canvas boundaries (eg. a negative Y coordinate) and the string will * be cropped accordingly if it is too long. * * See caca_put_char() for more information on how fullwidth characters * are handled when overwriting each other or at the canvas' boundaries. * * This function returns the number of cells printed by the string. It is * not the number of characters printed, because fullwidth characters * account for two cells. * * This function never fails. * * \param cv A handle to the libcaca canvas. * \param x X coordinate. * \param y Y coordinate. * \param s The string to print. * \return The number of cells printed. */ int caca_put_str(caca_canvas_t *cv, int x, int y, char const *s) { size_t rd; int len = 0; if (y < 0 || y >= (int)cv->height || x >= (int)cv->width) { while (*s) { len += caca_utf32_is_fullwidth(caca_utf8_to_utf32(s, &rd)) ? 2 : 1; s += rd ? rd : 1; } return len; } while (*s) { uint32_t ch = caca_utf8_to_utf32(s, &rd); if (x + len >= -1 && x + len < (int)cv->width) caca_put_char(cv, x + len, y, ch); len += caca_utf32_is_fullwidth(ch) ? 2 : 1; s += rd ? rd : 1; } return len; }
/** \brief flush the figlet context */ int caca_flush_figlet(caca_canvas_t *cv) { caca_charfont_t *ff = cv->ff; int x, y; if (!ff) return -1; //ff->torender = cv; //caca_set_canvas_size(ff->torender, ff->w, ff->h); caca_set_canvas_size(cv, ff->w, ff->h); /* FIXME: do this somewhere else, or record hardblank positions */ for(y = 0; y < ff->h; y++) for(x = 0; x < ff->w; x++) if(caca_get_char(cv, x, y) == 0xa0) { uint32_t attr = caca_get_attr(cv, x, y); caca_put_char(cv, x, y, ' '); caca_put_attr(cv, x, y, attr); } ff->x = ff->y = 0; ff->w = ff->h = 0; //cv = caca_create_canvas(1, 1); /* XXX */ /* from render.c */ ff->lines += caca_get_canvas_height(cv); return 0; }
static void filter_metal(context_t *cx) { static unsigned char const palette[] = { CACA_LIGHTBLUE, CACA_BLUE, CACA_LIGHTGRAY, CACA_DARKGRAY, }; unsigned int x, y, w, h; w = caca_get_canvas_width(cx->torender); h = caca_get_canvas_height(cx->torender); for(y = 0; y < h; y++) for(x = 0; x < w; x++) { unsigned long int ch = caca_get_char(cx->torender, x, y); int i; if(ch == (unsigned char)' ') continue; i = ((cx->lines + y + x / 8) / 2) % 4; caca_set_color_ansi(cx->torender, palette[i], CACA_TRANSPARENT); caca_put_char(cx->torender, x, y, ch); } }
void CacaWrapperGui::drawPixel(Point<int> const &point, Color<unsigned char> const &color) { unsigned char moy = 0; moy += color.getRed(); moy += color.getBlue(); moy += color.getGreen(); moy %= 26; caca_set_color_ansi(_cv, CACA_BLACK, CACA_WHITE); caca_put_char(_cv, point.getX() / MAP_TILE, point.getY() / MAP_TILE, moy + 'A'); }
static int draw_box(caca_canvas_t *cv, int x, int y, int w, int h, uint32_t const *chars) { int i, j, xmax, ymax; int x2 = x + w - 1; int y2 = y + h - 1; if(x > x2) { int tmp = x; x = x2; x2 = tmp; } if(y > y2) { int tmp = y; y = y2; y2 = tmp; } xmax = cv->width - 1; ymax = cv->height - 1; if(x2 < 0 || y2 < 0 || x > xmax || y > ymax) return 0; /* Draw edges */ if(y >= 0) for(i = x < 0 ? 1 : x + 1; i < x2 && i < xmax; i++) caca_put_char(cv, i, y, chars[0]); if(y2 <= ymax) for(i = x < 0 ? 1 : x + 1; i < x2 && i < xmax; i++) caca_put_char(cv, i, y2, chars[0]); if(x >= 0) for(j = y < 0 ? 1 : y + 1; j < y2 && j < ymax; j++) caca_put_char(cv, x, j, chars[1]); if(x2 <= xmax) for(j = y < 0 ? 1 : y + 1; j < y2 && j < ymax; j++) caca_put_char(cv, x2, j, chars[1]); /* Draw corners */ caca_put_char(cv, x, y, chars[2]); caca_put_char(cv, x, y2, chars[3]); caca_put_char(cv, x2, y, chars[4]); caca_put_char(cv, x2, y2, chars[5]); return 0; }
/** \brief Fill a box on the canvas using the given character. * * This function never fails. * * \param cv The handle to the libcaca canvas. * \param x X coordinate of the upper-left corner of the box. * \param y Y coordinate of the upper-left corner of the box. * \param w Width of the box. * \param h Height of the box. * \param ch UTF-32 character to be used to draw the box. * \return This function always returns 0. */ int caca_fill_box(caca_canvas_t *cv, int x, int y, int w, int h, uint32_t ch) { int i, j, xmax, ymax; int x2 = x + w - 1; int y2 = y + h - 1; if(x > x2) { int tmp = x; x = x2; x2 = tmp; } if(y > y2) { int tmp = y; y = y2; y2 = tmp; } xmax = cv->width - 1; ymax = cv->height - 1; if(x2 < 0 || y2 < 0 || x > xmax || y > ymax) return 0; if(x < 0) x = 0; if(y < 0) y = 0; if(x2 > xmax) x2 = xmax; if(y2 > ymax) y2 = ymax; #if 0 /* FIXME: this fails with fullwidth character blits. Also, the dirty * rectangle handling may miss fullwidth cells. */ /* Optimise dirty rectangle handling, part 1 */ cv->dirty_disabled++; #endif for(j = y; j <= y2; j++) for(i = x; i <= x2; i++) caca_put_char(cv, i, j, ch); #if 0 /* Optimise dirty rectangle handling, part 2 */ cv->dirty_disabled--; if(!cv->dirty_disabled) caca_add_dirty_rect(cv, x, y, x2 - x + 1, y2 - y + 1); #endif return 0; }
static int feed_tiny(context_t *cx, uint32_t ch, uint32_t attr) { switch(ch) { case (uint32_t)'\r': return 0; case (uint32_t)'\n': cx->x = 0; cx->y++; return 0; case (uint32_t)'\t': cx->x = (cx->x & ~7) + 8; return 0; } /* Check whether we reached the end of the screen */ if(cx->x && cx->x + 1 > cx->term_width) { cx->x = 0; cx->y++; } /* Check whether the current canvas is large enough */ if(cx->x + 1 > cx->w) { cx->w = cx->x + 1 < cx->term_width ? cx->x + 1 : cx->term_width; if(cx->w > cx->ew) cx->ew = cx->ew + cx->ew / 2; } if(cx->y + 1 > cx->h) { cx->h = cx->y + 1; if(cx->h > cx->eh) cx->eh = cx->eh + cx->eh / 2; } caca_set_attr(cx->cv, attr); caca_set_canvas_size(cx->cv, cx->ew, cx->eh); caca_put_char(cx->cv, cx->x, cx->y, ch); cx->x++; return 0; }
void CacaWrapperGui::drawBuffer(Point<int> const &point, Buffer<unsigned char> const &buffer) { size_t width = buffer.getWidth(); size_t height = buffer.getHeight(); int nbPixBuff = 0; uint32_t moyR = 0; uint32_t moyG = 0; uint32_t moyB = 0; uint16_t color; for (size_t i = 0; i < height; ++i) { for (size_t j = 0; j < width; ++j) { Color<unsigned char> color = buffer.getPixel(j, i); moyR += color.getRed() / (255 / 16); moyB += color.getBlue() / (255 / 16); moyG += color.getGreen() / (255 / 16); nbPixBuff++; } } moyR /= nbPixBuff; moyB /= nbPixBuff; moyG /= nbPixBuff; color = 15; color <<= 4; color += moyR; color <<= 4; color += moyG; color <<= 4; color += moyB; moyG %= 26; caca_set_color_argb(_cv, color, CACA_BLACK); caca_put_char(_cv, point.getX() / MAP_TILE, point.getY() / MAP_TILE, moyG + 'A'); }
int main(int argc, char *argv[]) { caca_canvas_t *cv, *image, *tmp, *sprite; caca_display_t *dp; cv = caca_create_canvas(0, 0); if(cv == NULL) { printf("Can't created canvas\n"); return -1; } dp = caca_create_display(cv); if(dp == NULL) { printf("Can't create display\n"); return -1; } image = caca_create_canvas(70, 6); tmp = caca_create_canvas(70, 6); sprite = caca_create_canvas(0, 0); caca_set_color_ansi(sprite, CACA_LIGHTMAGENTA, CACA_BLACK); caca_import_canvas_from_memory(sprite, pig, strlen(pig), "text"); caca_blit(image, 55, 0, sprite, NULL); caca_set_color_ansi(sprite, CACA_LIGHTGREEN, CACA_BLACK); caca_import_canvas_from_memory(sprite, duck, strlen(duck), "text"); caca_blit(image, 30, 1, sprite, NULL); caca_set_color_ansi(image, CACA_LIGHTCYAN, CACA_BLACK); caca_put_str(image, 1, 1, "hahaha mais vieux porc immonde !! [⽼ ⾗]"); caca_set_color_ansi(image, CACA_LIGHTRED, CACA_BLACK); caca_put_char(image, 38, 1, '|'); caca_set_color_ansi(image, CACA_YELLOW, CACA_BLACK); caca_put_str(image, 4, 2, "\\o\\ \\o| _o/ \\o_ |o/ /o/"); caca_set_color_ansi(image, CACA_WHITE, CACA_LIGHTRED); caca_put_str(image, 7, 3, "▙▘▌▙▘▞▖▞▖▌ ▞▖▌ ▌▌"); caca_put_str(image, 7, 4, "▛▖▌▛▖▚▘▚▘▚▖▚▘▚▖▖▖"); caca_set_color_ansi(image, CACA_BLACK, CACA_LIGHTRED); caca_put_str(image, 4, 3, "▓▒░"); caca_put_str(image, 4, 4, "▓▒░"); caca_put_str(image, 24, 3, "░▒▓"); caca_put_str(image, 24, 4, "░▒▓"); /* Blit the transformed canvas onto the main canvas */ caca_set_color_ansi(cv, CACA_WHITE, CACA_BLUE); caca_put_str(cv, 0, 0, "normal"); caca_blit(cv, 10, 0, image, NULL); caca_put_str(cv, 0, 6, "flip"); caca_blit(tmp, 0, 0, image, NULL); caca_flip(tmp); caca_blit(cv, 10, 6, tmp, NULL); caca_put_str(cv, 0, 12, "flop"); caca_blit(tmp, 0, 0, image, NULL); caca_flop(tmp); caca_blit(cv, 10, 12, tmp, NULL); caca_put_str(cv, 0, 18, "rotate"); caca_blit(tmp, 0, 0, image, NULL); caca_rotate_180(tmp); caca_blit(cv, 10, 18, tmp, NULL); caca_refresh_display(dp); caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1); caca_free_display(dp); caca_free_canvas(tmp); caca_free_canvas(sprite); caca_free_canvas(image); caca_free_canvas(cv); return 0; }
int cucul_putchar(cucul_canvas_t *cv, int x, int y, unsigned long int ch) { return caca_put_char(cv, x, y, ch); }
/** \brief paste a character using the current figfont */ int caca_put_figchar(caca_canvas_t *cv, uint32_t ch) { caca_charfont_t *ff = cv->ff; int c, w, h, x, y, overlap, extra, xleft, xright; if (!ff) return -1; switch(ch) { case (uint32_t)'\r': return 0; case (uint32_t)'\n': ff->x = 0; ff->y += ff->height; return 0; /* FIXME: handle '\t' */ } /* Look whether our glyph is available */ for(c = 0; c < ff->glyphs; c++) if(ff->lookup[c * 2] == ch) break; if(c == ff->glyphs) return 0; w = ff->lookup[c * 2 + 1]; h = ff->height; caca_set_canvas_handle(ff->fontcv, 0, c * ff->height); caca_blit(ff->charcv, 0, 0, ff->fontcv, NULL); /* Check whether we reached the end of the screen */ if(ff->x && ff->x + w > ff->term_width) { ff->x = 0; ff->y += h; } /* Compute how much the next character will overlap */ switch(ff->hmode) { case H_SMUSH: case H_KERN: case H_OVERLAP: extra = (ff->hmode == H_OVERLAP); overlap = w; for(y = 0; y < h; y++) { /* Compute how much spaces we can eat from the new glyph */ for(xright = 0; xright < overlap; xright++) if(caca_get_char(ff->charcv, xright, y) != ' ') break; /* Compute how much spaces we can eat from the previous glyph */ for(xleft = 0; xright + xleft < overlap && xleft < ff->x; xleft++) if(caca_get_char(cv, ff->x - 1 - xleft, ff->y + y) != ' ') break; /* Handle overlapping */ if(ff->hmode == H_OVERLAP && xleft < ff->x) xleft++; /* Handle smushing */ if(ff->hmode == H_SMUSH) { if(xleft < ff->x && hsmush(caca_get_char(cv, ff->x - 1 - xleft, ff->y + y), caca_get_char(ff->charcv, xright, y), ff->hsmushrule)) xleft++; } if(xleft + xright < overlap) overlap = xleft + xright; } break; case H_NONE: overlap = 0; break; default: return -1; } /* Check whether the current canvas is large enough */ if(ff->x + w - overlap > ff->w) ff->w = ff->x + w - overlap < ff->term_width ? ff->x + w - overlap : ff->term_width; if(ff->y + h > ff->h) ff->h = ff->y + h; #if 0 /* deactivated for libcaca insertion */ if(attr) caca_set_attr(cv, attr); #endif caca_set_canvas_size(cv, ff->w, ff->h); /* Render our char (FIXME: create a rect-aware caca_blit_canvas?) */ for(y = 0; y < h; y++) for(x = 0; x < w; x++) { uint32_t ch1, ch2; uint32_t tmpat = caca_get_attr(ff->fontcv, x, y + c * ff->height); ch2 = caca_get_char(ff->charcv, x, y); if(ch2 == ' ') continue; ch1 = caca_get_char(cv, ff->x + x - overlap, ff->y + y); if(ch1 == ' ' || ff->hmode != H_SMUSH) caca_put_char(cv, ff->x + x - overlap, ff->y + y, ch2); else caca_put_char(cv, ff->x + x - overlap, ff->y + y, hsmush(ch1, ch2, ff->hsmushrule)); caca_put_attr(cv, ff->x + x, ff->y + y, tmpat); } /* Advance cursor */ ff->x += w - overlap; return 0; }
JNIEXPORT void JNICALL Java_org_zoy_caca_Canvas_putCanvasChar(JNIEnv *env, jclass cls, jlong ptr, jint x, jint y, jint ch) { caca_put_char((caca_canvas_t *)ptr, x, y, ch); }
int main(void) { caca_canvas_t *cv; caca_display_t *dp; caca_event_t ev; // Create canvas and display cv = caca_create_canvas(100,80); if(!cv) return 1; dp = caca_create_display_with_driver(cv, "ncurses"); if(!dp) return 1; caca_set_display_title(dp, "WPC 66"); caca_set_color_ansi(cv, CACA_WHITE, CACA_BLACK); // Tree stump caca_fill_box (cv, 47, 50, 6, 4, '|'); // Tree body caca_draw_thin_triangle (cv,50,10,10,50,90,50); // Pot caca_fill_triangle(cv, 35, 53, 40, 60, 40, 53, '@'); caca_fill_box(cv, 40, 53, 19, 8, '@'); caca_fill_triangle(cv, 59, 60, 64, 53, 59, 53, '@'); // Balls int balls[] = {50, 25, 35, 35, 25, 43, 58, 32, 68, 41, 50, 46}; for (int i = 0; i <= 10; i += 2) caca_draw_thin_ellipse(cv, balls[i], balls[i+1], 2, 2); // Sparkly stuff int sparks[] = {54, 20, 42, 30, 40, 45, 46, 38, 60, 43, 75, 48}; for (int i = 0; i <= 10; i += 2) { caca_put_char(cv, sparks[i], sparks[i+1], '*'); caca_put_char(cv, sparks[i]-1, sparks[i+1], '<'); caca_put_char(cv, sparks[i]+1, sparks[i+1], '>'); caca_put_char(cv, sparks[i], sparks[i+1]-1, '^'); caca_put_char(cv, sparks[i], sparks[i+1]+1, 'v'); } // Guirlandes caca_draw_thin_line(cv, 32, 44, 70, 35); caca_draw_thin_line(cv, 17, 49, 30, 46); caca_draw_thin_line(cv, 60, 47, 80, 43); caca_draw_thin_line(cv, 43, 35, 52, 33); caca_draw_thin_line(cv, 55, 28, 60, 27); caca_draw_thin_line(cv, 40, 25, 45, 24); // Star outline caca_fill_triangle(cv, 50, 16, 40, 10, 60, 10, ' '); int star_x[] = {50, 45, 40, 45, 40, 45, 50, 55, 60, 55, 60, 55, 50}; int star_y[] = { 4, 7, 7, 10, 13, 13, 16, 13, 13, 10, 7, 7, 4}; caca_draw_thin_polyline(cv, star_x, star_y, 12); // Inside of star int star[] = {50,8,50,9,50,10,50,11,50,12,49,9,48,9,51,9,52,9,49,10,51,10,49,11,48,11,51,11,52,11}; for (int i = 0; i <= 29; i += 2) caca_put_char(cv, star[i], star[i+1], '*'); // Display and wait for key press caca_refresh_display(dp); caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, -1); caca_free_display(dp); return 0; }
int main(int argc, char *argv[]) { caca_canvas_t *cv, *caca, *line; caca_display_t *dp; unsigned int i; cv = caca_create_canvas(0, 0); if(cv == NULL) { printf("Can't created canvas\n"); return -1; } dp = caca_create_display(cv); if(dp == NULL) { printf("Can't create display\n"); return -1; } caca = caca_create_canvas(6, 10); line = caca_create_canvas(2, 1); /* Line of x's */ for(i = 0; i < 10; i++) { caca_set_color_ansi(caca, CACA_WHITE, CACA_BLUE); caca_put_str(caca, 0, i, CACA); caca_set_color_ansi(caca, CACA_WHITE, CACA_RED); caca_put_char(caca, i - 2, i, 'x'); } caca_blit(cv, 1, 1, caca, NULL); /* Line of ホ's */ for(i = 0; i < 10; i++) { caca_set_color_ansi(caca, CACA_WHITE, CACA_BLUE); caca_put_str(caca, 0, i, CACA); caca_set_color_ansi(caca, CACA_WHITE, CACA_GREEN); caca_put_str(caca, i - 2, i, "ホ"); } caca_blit(cv, 15, 1, caca, NULL); /* Line of canvas */ caca_set_color_ansi(line, CACA_WHITE, CACA_MAGENTA); caca_put_str(line, 0, 0, "ほ"); for(i = 0; i < 10; i++) { caca_set_color_ansi(caca, CACA_WHITE, CACA_BLUE); caca_put_str(caca, 0, i, CACA); caca_blit(caca, i - 2, i, line, NULL); } caca_blit(cv, 29, 1, caca, NULL); caca_refresh_display(dp); caca_get_event(dp, CACA_EVENT_KEY_PRESS, NULL, -1); caca_free_display(dp); caca_free_canvas(line); caca_free_canvas(caca); caca_free_canvas(cv); return 0; }
void langton(enum action action, caca_canvas_t *cv) { static char gradient[] = { ' ', ' ', '.', '.', ':', ':', 'x', 'x', 'X', 'X', '&', '&', 'W', 'W', '@', '@', }; static int steps[][2] = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } }; static uint8_t *screen; static int width, height; static int ax[ANTS], ay[ANTS], dir[ANTS]; int i, a, x, y; switch(action) { case PREPARE: width = caca_get_canvas_width(cv); height = caca_get_canvas_height(cv); for(i = 0; i < ANTS; i++) { ax[i] = caca_rand(0, width); ay[i] = caca_rand(0, height); dir[i] = caca_rand(0, 4); } break; case INIT: screen = malloc(width * height); memset(screen, 0, width * height); break; case UPDATE: for(i = 0; i < ITER; i++) { for(x = 0; x < width * height; x++) { uint8_t p = screen[x]; if((p & 0x0f) > 1) screen[x] = p - 1; } for(a = 0; a < ANTS; a++) { uint8_t p = screen[ax[a] + width * ay[a]]; if(p & 0x0f) { dir[a] = (dir[a] + 1) % 4; screen[ax[a] + width * ay[a]] = a << 4; } else { dir[a] = (dir[a] + 3) % 4; screen[ax[a] + width * ay[a]] = (a << 4) | 0x0f; } ax[a] = (width + ax[a] + steps[dir[a]][0]) % width; ay[a] = (height + ay[a] + steps[dir[a]][1]) % height; } } break; case RENDER: for(y = 0; y < height; y++) { for(x = 0; x < width; x++) { uint8_t p = screen[x + width * y]; if(p & 0x0f) caca_set_color_ansi(cv, CACA_WHITE, p >> 4); else caca_set_color_ansi(cv, CACA_BLACK, CACA_BLACK); caca_put_char(cv, x, y, gradient[p & 0x0f]); } } break; case FREE: free(screen); break; }
static caca_charfont_t * open_charfont(char const *path) { char buf[2048]; char hardblank[10]; caca_charfont_t *ff; char *data = NULL; caca_file_t *f; #if !defined __KERNEL__ && (defined HAVE_SNPRINTF || defined HAVE_SPRINTF_S) int const pathlen = 2048; char *altpath = NULL; #endif int i, j, size, comment_lines; ff = malloc(sizeof(caca_charfont_t)); if(!ff) { seterrno(ENOMEM); return NULL; } /* Open font: if not found, try .tlf, then .flf */ f = caca_file_open(path, "r"); #if !defined __KERNEL__ && (defined HAVE_SNPRINTF || defined HAVE_SPRINTF_S) if(!f) altpath = malloc(pathlen); if(!f) { #if defined HAVE_SPRINTF_S sprintf_s(altpath, pathlen - 1, "%s.tlf", path); #else snprintf(altpath, pathlen - 1, "%s.tlf", path); #endif altpath[pathlen - 1] = '\0'; f = caca_file_open(altpath, "r"); } if(!f) { #if defined HAVE_SPRINTF_S sprintf_s(altpath, pathlen - 1, "%s.flf", path); #else snprintf(altpath, pathlen - 1, "%s.flf", path); #endif altpath[pathlen - 1] = '\0'; f = caca_file_open(altpath, "r"); } if (altpath) free(altpath); #endif if(!f) { free(ff); seterrno(ENOENT); return NULL; } /* Read header */ ff->print_direction = 0; ff->full_layout = 0; ff->codetag_count = 0; caca_file_gets(f, buf, 2048); if(sscanf(buf, "%*[ft]lf2a%6s %u %u %u %i %u %u %u %u\n", hardblank, &ff->height, &ff->baseline, &ff->max_length, &ff->old_layout, &comment_lines, &ff->print_direction, &ff->full_layout, &ff->codetag_count) < 6) { debug("figfont error: `%s' has invalid header: %s", path, buf); caca_file_close(f); free(ff); seterrno(EINVAL); return NULL; } if(ff->old_layout < -1 || ff->old_layout > 63 || ff->full_layout > 32767 || ((ff->full_layout & 0x80) && (ff->full_layout & 0x3f) == 0 && ff->old_layout)) { debug("figfont error: `%s' has invalid layout %i/%u", path, ff->old_layout, ff->full_layout); caca_file_close(f); free(ff); seterrno(EINVAL); return NULL; } ff->hardblank = caca_utf8_to_utf32(hardblank, NULL); /* Skip comment lines */ for(i = 0; i < comment_lines; i++) caca_file_gets(f, buf, 2048); /* Read mandatory characters (32-127, 196, 214, 220, 228, 246, 252, 223) * then read additional characters. */ ff->glyphs = 0; ff->lookup = NULL; for(i = 0, size = 0; !caca_file_eof(f); ff->glyphs++) { if((ff->glyphs % 2048) == 0) ff->lookup = realloc(ff->lookup, (ff->glyphs + 2048) * 2 * sizeof(int)); if(ff->glyphs < STD_GLYPHS) { ff->lookup[ff->glyphs * 2] = 32 + ff->glyphs; } else if(ff->glyphs < EXT_GLYPHS) { static int const tab[7] = { 196, 214, 220, 228, 246, 252, 223 }; ff->lookup[ff->glyphs * 2] = tab[ff->glyphs - STD_GLYPHS]; } else { unsigned int tmp; if(caca_file_gets(f, buf, 2048) == NULL) break; /* Ignore blank lines, as in jacky.flf */ if(buf[0] == '\n' || buf[0] == '\r') continue; /* Ignore negative indices for now, as in ivrit.flf */ if(buf[0] == '-') { for(j = 0; j < ff->height; j++) caca_file_gets(f, buf, 2048); continue; } if(!buf[0] || buf[0] < '0' || buf[0] > '9') { debug("figfont error: glyph #%u in `%s'", ff->glyphs, path); free(data); free(ff->lookup); free(ff); seterrno(EINVAL); return NULL; } sscanf(buf, buf[1] == 'x' ? "%x" : "%u", &tmp); ff->lookup[ff->glyphs * 2] = tmp; } ff->lookup[ff->glyphs * 2 + 1] = 0; for(j = 0; j < ff->height; j++) { if(i + 2048 >= size) data = realloc(data, size += 2048); caca_file_gets(f, data + i, 2048); i = (uintptr_t)strchr(data + i, 0) - (uintptr_t)data; } } caca_file_close(f); if(ff->glyphs < EXT_GLYPHS) { debug("figfont error: only %u glyphs in `%s', expected at least %u", ff->glyphs, path, EXT_GLYPHS); free(data); free(ff->lookup); free(ff); seterrno(EINVAL); return NULL; } /* Remaining initialisation */ ff->charcv = NULL; ff->left = NULL; ff->right = NULL; /* Import buffer into canvas */ ff->fontcv = caca_create_canvas(0, 0); caca_import_canvas_from_memory(ff->fontcv, data, i, "utf8"); free(data); /* Remove EOL characters. For now we ignore hardblanks, don’t do any * smushing, nor any kind of error checking. */ for(j = 0; j < ff->height * ff->glyphs; j++) { uint32_t ch, oldch = 0; for(i = ff->max_length; i--;) { ch = caca_get_char(ff->fontcv, i, j); /* Replace hardblanks with U+00A0 NO-BREAK SPACE */ if(ch == ff->hardblank) caca_put_char(ff->fontcv, i, j, ch = 0xa0); if(oldch && ch != oldch) { if(!ff->lookup[j / ff->height * 2 + 1]) ff->lookup[j / ff->height * 2 + 1] = i + 1; } else if(oldch && ch == oldch) caca_put_char(ff->fontcv, i, j, ' '); else if(ch != ' ') { oldch = ch; caca_put_char(ff->fontcv, i, j, ' '); } } } return ff; }
int main(int argc, char *argv[]) { caca_canvas_t *cv; caca_dither_t *dither; void *buffer; char *file, *format; char const * const * exports, * const * p; size_t len; int x, y; exports = caca_get_export_list(); if(argc < 2 || argc > 3) { fprintf(stderr, "%s: wrong argument count\n", argv[0]); fprintf(stderr, "usage: %s [file] <format>\n", argv[0]); fprintf(stderr, "where <format> is one of:\n"); for(p = exports; *p; p += 2) fprintf(stderr, " \"%s\" (%s)\n", *p, *(p + 1)); exit(-1); } if(argc == 2) { file = NULL; format = argv[1]; } else { file = argv[1]; format = argv[2]; } for(p = exports; *p; p += 2) if(!strcasecmp(format, *p)) break; if(!*p) { fprintf(stderr, "%s: unknown format `%s'\n", argv[0], format); fprintf(stderr, "please use one of:\n"); for(p = exports; *p; p += 2) fprintf(stderr, " \"%s\" (%s)\n", *p, *(p + 1)); exit(-1); } if(file) { cv = caca_create_canvas(0, 0); if(caca_import_canvas_from_file(cv, file, "") < 0) { fprintf(stderr, "%s: `%s' has unknown format\n", argv[0], file); exit(-1); } } else { cv = caca_create_canvas(WIDTH, HEIGHT); for(y = 0; y < 256; y++) { for(x = 0; x < 256; x++) { uint32_t r = x; uint32_t g = (255 - y + x) / 2; uint32_t b = y * (255 - x) / 256; pixels[y * 256 + x] = (r << 16) | (g << 8) | (b << 0); } } dither = caca_create_dither(32, 256, 256, 4 * 256, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x0); if(!strcmp(format, "ansi") || !strcmp(format, "utf8")) caca_set_dither_charset(dither, "shades"); caca_dither_bitmap(cv, 0, 0, caca_get_canvas_width(cv), caca_get_canvas_height(cv), dither, pixels); caca_free_dither(dither); caca_set_color_ansi(cv, CACA_WHITE, CACA_BLACK); caca_draw_thin_box(cv, 0, 0, WIDTH - 1, HEIGHT - 1); caca_set_color_ansi(cv, CACA_BLACK, CACA_WHITE); caca_fill_ellipse(cv, WIDTH / 2, HEIGHT / 2, WIDTH / 4, HEIGHT / 4, ' '); caca_set_color_ansi(cv, CACA_LIGHTGRAY, CACA_BLACK); caca_put_str(cv, WIDTH / 2 - 12, HEIGHT / 2 - 6, " lightgray on black "); caca_set_color_ansi(cv, CACA_DEFAULT, CACA_TRANSPARENT); caca_put_str(cv, WIDTH / 2 - 12, HEIGHT / 2 - 5, " default on transparent "); caca_set_color_ansi(cv, CACA_BLACK, CACA_WHITE); caca_put_str(cv, WIDTH / 2 - 12, HEIGHT / 2 - 4, " black on white "); caca_set_color_ansi(cv, CACA_BLACK, CACA_WHITE); caca_put_str(cv, WIDTH / 2 - 8, HEIGHT / 2 - 3, "[<><><><> <>--<>]"); caca_put_str(cv, WIDTH / 2 - 8, HEIGHT / 2 - 2, "[ドラゴン ボーレ]"); caca_put_str(cv, WIDTH / 2 - 7, HEIGHT / 2 + 2, "äβç ░▒▓█▓▒░ ΔЗҒ"); caca_put_str(cv, WIDTH / 2 - 5, HEIGHT / 2 + 4, "(\") \\o/ <&>"); caca_set_attr(cv, CACA_BOLD); caca_put_str(cv, WIDTH / 2 - 16, HEIGHT / 2 + 3, "Bold"); caca_set_attr(cv, CACA_BLINK); caca_put_str(cv, WIDTH / 2 - 9, HEIGHT / 2 + 3, "Blink"); caca_set_attr(cv, CACA_ITALICS); caca_put_str(cv, WIDTH / 2 - 1, HEIGHT / 2 + 3, "Italics"); caca_set_attr(cv, CACA_UNDERLINE); caca_put_str(cv, WIDTH / 2 + 8, HEIGHT / 2 + 3, "Underline"); caca_set_attr(cv, 0); caca_set_color_ansi(cv, CACA_WHITE, CACA_LIGHTBLUE); caca_put_str(cv, WIDTH / 2 - 7, HEIGHT / 2, " LIBCACA "); for(x = 0; x < 16; x++) { caca_set_color_argb(cv, 0xff00 | x, 0xf00f | (x << 4)); caca_put_char(cv, WIDTH / 2 - 7 + x, HEIGHT / 2 + 6, '#'); } } buffer = caca_export_canvas_to_memory(cv, format, &len); fwrite(buffer, len, 1, stdout); free(buffer); caca_free_canvas(cv); return 0; }
int main(int argc, char *argv[]) { textentry entries[TEXT_ENTRIES]; caca_canvas_t *cv; caca_display_t *dp; unsigned int i, e = 0, running = 1; cv = caca_create_canvas(0, 0); if(cv == NULL) { printf("Can't create canvas\n"); return -1; } dp = caca_create_display(cv); if(dp == NULL) { printf("Can't create display\n"); return -1; } caca_set_cursor(dp, 1); caca_set_color_ansi(cv, CACA_WHITE, CACA_BLUE); caca_put_str(cv, 1, 1, "Text entries - press tab to cycle"); for(i = 0; i < TEXT_ENTRIES; i++) { entries[i].buffer[0] = 0; entries[i].size = 0; entries[i].cursor = 0; entries[i].changed = 1; caca_printf(cv, 3, 3 * i + 4, "[entry %i]", i + 1); } /* Put Unicode crap in the last text entry */ entries[TEXT_ENTRIES - 1].buffer[0] = 'A'; entries[TEXT_ENTRIES - 1].buffer[1] = 'b'; entries[TEXT_ENTRIES - 1].buffer[2] = caca_utf8_to_utf32("Ç", NULL); entries[TEXT_ENTRIES - 1].buffer[3] = caca_utf8_to_utf32("đ", NULL); entries[TEXT_ENTRIES - 1].buffer[4] = caca_utf8_to_utf32("ボ", NULL); entries[TEXT_ENTRIES - 1].buffer[5] = CACA_MAGIC_FULLWIDTH; entries[TEXT_ENTRIES - 1].buffer[6] = caca_utf8_to_utf32("♥", NULL); entries[TEXT_ENTRIES - 1].size = 7; while(running) { caca_event_t ev; for(i = 0; i < TEXT_ENTRIES; i++) { unsigned int j, start, size; if(!entries[i].changed) continue; caca_set_color_ansi(cv, CACA_BLACK, CACA_LIGHTGRAY); caca_fill_box(cv, 2, 3 * i + 5, BUFFER_SIZE + 1, 1, ' '); start = 0; size = entries[i].size; for(j = 0; j < size; j++) { caca_put_char(cv, 2 + j, 3 * i + 5, entries[i].buffer[start + j]); } entries[i].changed = 0; } /* Put the cursor on the active textentry */ caca_gotoxy(cv, 2 + entries[e].cursor, 3 * e + 5); caca_refresh_display(dp); if(caca_get_event(dp, CACA_EVENT_KEY_PRESS, &ev, -1) == 0) continue; switch(caca_get_event_key_ch(&ev)) { case CACA_KEY_ESCAPE: running = 0; break; case CACA_KEY_TAB: case CACA_KEY_RETURN: e = (e + 1) % TEXT_ENTRIES; break; case CACA_KEY_HOME: entries[e].cursor = 0; break; case CACA_KEY_END: entries[e].cursor = entries[e].size; break; case CACA_KEY_LEFT: if(entries[e].cursor) entries[e].cursor--; break; case CACA_KEY_RIGHT: if(entries[e].cursor < entries[e].size) entries[e].cursor++; break; case CACA_KEY_DELETE: if(entries[e].cursor < entries[e].size) { memmove(entries[e].buffer + entries[e].cursor, entries[e].buffer + entries[e].cursor + 1, (entries[e].size - entries[e].cursor + 1) * 4); entries[e].size--; entries[e].changed = 1; } break; case CACA_KEY_BACKSPACE: if(entries[e].cursor) { memmove(entries[e].buffer + entries[e].cursor - 1, entries[e].buffer + entries[e].cursor, (entries[e].size - entries[e].cursor) * 4); entries[e].size--; entries[e].cursor--; entries[e].changed = 1; } break; default: if(entries[e].size < BUFFER_SIZE) { memmove(entries[e].buffer + entries[e].cursor + 1, entries[e].buffer + entries[e].cursor, (entries[e].size - entries[e].cursor) * 4); entries[e].buffer[entries[e].cursor] = caca_get_event_key_utf32(&ev); entries[e].size++; entries[e].cursor++; entries[e].changed = 1; } break; } } caca_free_display(dp); caca_free_canvas(cv); return 0; }