Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

251 řádky
6.0 KiB

  1. /*
  2. * TOIlet The Other Implementation’s letters
  3. * Copyright (c) 2006 Sam Hocevar <sam@hocevar.net>
  4. * All Rights Reserved
  5. *
  6. * This program is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What The Fuck You Want
  9. * To Public License, Version 2, as published by Sam Hocevar. See
  10. * http://sam.zoy.org/wtfpl/COPYING for more details.
  11. */
  12. /*
  13. * This file contains post-processing filter functions.
  14. */
  15. #include "config.h"
  16. #if defined(HAVE_INTTYPES_H)
  17. # include <inttypes.h>
  18. #endif
  19. #include <string.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <caca.h>
  23. #include "toilet.h"
  24. #include "filter.h"
  25. static void filter_crop(context_t *);
  26. static void filter_rainbow(context_t *);
  27. static void filter_metal(context_t *);
  28. static void filter_flip(context_t *);
  29. static void filter_flop(context_t *);
  30. static void filter_180(context_t *);
  31. static void filter_left(context_t *);
  32. static void filter_right(context_t *);
  33. static void filter_border(context_t *);
  34. struct
  35. {
  36. char const *name;
  37. void (*function)(context_t *);
  38. char const *description;
  39. }
  40. const lookup[] =
  41. {
  42. { "crop", filter_crop, "crop unused blanks" },
  43. { "rainbow", filter_rainbow, "add a rainbow colour effect" },
  44. { "metal", filter_metal, "add a metallic colour effect" },
  45. { "flip", filter_flip, "flip horizontally" },
  46. { "flop", filter_flop, "flip vertically" },
  47. { "rotate", filter_180, NULL }, /* backwards compatibility */
  48. { "180", filter_180, "rotate 180 degrees" },
  49. { "left", filter_left, "rotate 90 degrees counterclockwise" },
  50. { "right", filter_right, "rotate 90 degrees clockwise" },
  51. { "border", filter_border, "surround text with a border" },
  52. };
  53. int filter_list(void)
  54. {
  55. unsigned int i;
  56. printf("Available filters:\n");
  57. for(i = 0; i < sizeof(lookup) / sizeof(lookup[0]); i++)
  58. if(lookup[i].description)
  59. printf("\"%s\": %s\n", lookup[i].name, lookup[i].description);
  60. return 0;
  61. }
  62. int filter_add(context_t *cx, char const *filter)
  63. {
  64. unsigned int n;
  65. int i;
  66. for(;;)
  67. {
  68. while(*filter == ':')
  69. filter++;
  70. if(*filter == '\0')
  71. break;
  72. for(i = sizeof(lookup) / sizeof(lookup[0]); i--; )
  73. if(!strncmp(filter, lookup[i].name, strlen(lookup[i].name)))
  74. {
  75. n = strlen(lookup[i].name);
  76. break;
  77. }
  78. if(i == -1 || (filter[n] != ':' && filter[n] != '\0'))
  79. {
  80. fprintf(stderr, "unknown filter near `%s'\n", filter);
  81. return -1;
  82. }
  83. if((cx->nfilters % 16) == 0)
  84. cx->filters = realloc(cx->filters, (cx->nfilters + 16)
  85. * sizeof(lookup[0].function));
  86. cx->filters[cx->nfilters] = lookup[i].function;
  87. cx->nfilters++;
  88. filter += n;
  89. }
  90. return 0;
  91. }
  92. int filter_do(context_t *cx)
  93. {
  94. unsigned int i;
  95. for(i = 0; i < cx->nfilters; i++)
  96. cx->filters[i](cx);
  97. return 0;
  98. }
  99. int filter_end(context_t *cx)
  100. {
  101. free(cx->filters);
  102. return 0;
  103. }
  104. static void filter_crop(context_t *cx)
  105. {
  106. unsigned int x, y, w, h;
  107. unsigned int xmin, xmax, ymin, ymax;
  108. xmin = w = caca_get_canvas_width(cx->torender);
  109. xmax = 0;
  110. ymin = h = caca_get_canvas_height(cx->torender);
  111. ymax = 0;
  112. for(y = 0; y < h; y++)
  113. for(x = 0; x < w; x++)
  114. {
  115. unsigned long int ch = caca_get_char(cx->torender, x, y);
  116. if(ch != (unsigned char)' ')
  117. {
  118. if(x < xmin)
  119. xmin = x;
  120. if(x > xmax)
  121. xmax = x;
  122. if(y < ymin)
  123. ymin = y;
  124. if(y > ymax)
  125. ymax = y;
  126. }
  127. }
  128. if(xmax < xmin || ymax < ymin)
  129. return;
  130. caca_set_canvas_boundaries(cx->torender, xmin, ymin,
  131. xmax - xmin + 1, ymax - ymin + 1);
  132. }
  133. static void filter_metal(context_t *cx)
  134. {
  135. static unsigned char const palette[] =
  136. {
  137. CACA_LIGHTBLUE, CACA_BLUE, CACA_LIGHTGRAY, CACA_DARKGRAY,
  138. };
  139. unsigned int x, y, w, h;
  140. w = caca_get_canvas_width(cx->torender);
  141. h = caca_get_canvas_height(cx->torender);
  142. for(y = 0; y < h; y++)
  143. for(x = 0; x < w; x++)
  144. {
  145. unsigned long int ch = caca_get_char(cx->torender, x, y);
  146. int i;
  147. if(ch == (unsigned char)' ')
  148. continue;
  149. i = ((cx->lines + y + x / 8) / 2) % 4;
  150. caca_set_color_ansi(cx->torender, palette[i], CACA_TRANSPARENT);
  151. caca_put_char(cx->torender, x, y, ch);
  152. }
  153. }
  154. static void filter_rainbow(context_t *cx)
  155. {
  156. static unsigned char const rainbow[] =
  157. {
  158. CACA_LIGHTMAGENTA, CACA_LIGHTRED, CACA_YELLOW,
  159. CACA_LIGHTGREEN, CACA_LIGHTCYAN, CACA_LIGHTBLUE,
  160. };
  161. unsigned int x, y, w, h;
  162. w = caca_get_canvas_width(cx->torender);
  163. h = caca_get_canvas_height(cx->torender);
  164. for(y = 0; y < h; y++)
  165. for(x = 0; x < w; x++)
  166. {
  167. unsigned long int ch = caca_get_char(cx->torender, x, y);
  168. if(ch != (unsigned char)' ')
  169. {
  170. caca_set_color_ansi(cx->torender,
  171. rainbow[(x / 2 + y + cx->lines) % 6],
  172. CACA_TRANSPARENT);
  173. caca_put_char(cx->torender, x, y, ch);
  174. }
  175. }
  176. }
  177. static void filter_flip(context_t *cx)
  178. {
  179. caca_flip(cx->torender);
  180. }
  181. static void filter_flop(context_t *cx)
  182. {
  183. caca_flop(cx->torender);
  184. }
  185. static void filter_180(context_t *cx)
  186. {
  187. caca_rotate_180(cx->torender);
  188. }
  189. static void filter_left(context_t *cx)
  190. {
  191. caca_rotate_left(cx->torender);
  192. }
  193. static void filter_right(context_t *cx)
  194. {
  195. caca_rotate_right(cx->torender);
  196. }
  197. static void filter_border(context_t *cx)
  198. {
  199. int w, h;
  200. w = caca_get_canvas_width(cx->torender);
  201. h = caca_get_canvas_height(cx->torender);
  202. caca_set_canvas_boundaries(cx->torender, -1, -1, w + 2, h + 2);
  203. caca_draw_cp437_box(cx->torender, 0, 0, w + 2, h + 2);
  204. }