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_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); } }
static void filter_crop(context_t *cx) { unsigned int x, y, w, h; unsigned int xmin, xmax, ymin, ymax; xmin = w = caca_get_canvas_width(cx->torender); xmax = 0; ymin = h = caca_get_canvas_height(cx->torender); ymax = 0; 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)' ') { if(x < xmin) xmin = x; if(x > xmax) xmax = x; if(y < ymin) ymin = y; if(y > ymax) ymax = y; } } if(xmax < xmin || ymax < ymin) return; caca_set_canvas_boundaries(cx->torender, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1); }
/** \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_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); } }
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; }
/** \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; }
unsigned long int cucul_getchar(cucul_canvas_t *cv, int x, int y) { return caca_get_char(cv, x, y); }
JNIEXPORT jint JNICALL Java_org_zoy_caca_Canvas_getCanvasChar(JNIEnv *env, jclass cls, jlong ptr, jint x, jint y) { return caca_get_char((caca_canvas_t *)ptr, x, y); }