cat-img.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2016-2018 K. Lange
  5. */
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <getopt.h>
  9. #include <unistd.h>
  10. #include <sys/ioctl.h>
  11. #include <termios.h>
  12. #include <toaru/graphics.h>
  13. #include <toaru/termemu.h>
  14. void get_cell_sizes(int * w, int * h) {
  15. struct winsize wsz;
  16. ioctl(0, TIOCGWINSZ, &wsz);
  17. if (!wsz.ws_col || !wsz.ws_row) {
  18. *w = 0;
  19. *h = 0;
  20. }
  21. *w = wsz.ws_xpixel / wsz.ws_col;
  22. *h = wsz.ws_ypixel / wsz.ws_row;
  23. }
  24. void raw_output(void) {
  25. struct termios new;
  26. tcgetattr(fileno(stdin), &new);
  27. new.c_oflag &= (~ONLCR);
  28. tcsetattr(fileno(stdin), TCSAFLUSH, &new);
  29. }
  30. void unraw_output(void) {
  31. struct termios new;
  32. tcgetattr(fileno(stdin), &new);
  33. new.c_oflag |= ONLCR;
  34. tcsetattr(fileno(stdin), TCSAFLUSH, &new);
  35. }
  36. int usage(char * argv[]) {
  37. printf(
  38. "usage: %s [-?ns] [path]\n"
  39. "\n"
  40. " -n \033[3mdon't print a new line after image\033[0m\n"
  41. " -s \033[3mscale to cell height (up or down)\033[0m\n"
  42. " -w \033[3mscale to terminal width (up or down)\033[0m\n"
  43. " -? \033[3mshow this help text\033[0m\n"
  44. "\n", argv[0]);
  45. return 1;
  46. }
  47. int main (int argc, char * argv[]) {
  48. if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) {
  49. fprintf(stderr, "Can't cat-img to a non-terminal.\n");
  50. exit(1);
  51. }
  52. int opt;
  53. int no_newline = 0;
  54. int scale_to_cell_height = 0;
  55. int scale_to_term_width = 0;
  56. while ((opt = getopt(argc, argv, "?nsw")) != -1) {
  57. switch (opt) {
  58. case '?':
  59. return usage(argv);
  60. case 'n':
  61. no_newline = 1;
  62. break;
  63. case 'w':
  64. scale_to_term_width = 1;
  65. break;
  66. case 's':
  67. scale_to_cell_height = 1;
  68. break;
  69. }
  70. }
  71. if (optind >= argc ) {
  72. return usage(argv);
  73. }
  74. int w, h;
  75. get_cell_sizes(&w, &h);
  76. if (!w || !h) return 1;
  77. while (optind < argc) {
  78. sprite_t * image = calloc(sizeof(sprite_t),1);
  79. load_sprite(image, argv[optind]);
  80. image->alpha = ALPHA_EMBEDDED;
  81. sprite_t * source = image;
  82. if (scale_to_cell_height) {
  83. int new_width = (h * image->width) / image->height;
  84. source = create_sprite(new_width,h,1);
  85. gfx_context_t * g = init_graphics_sprite(source);
  86. draw_fill(g, 0x00000000);
  87. draw_sprite_scaled(g, image, 0, 0, new_width, h);
  88. sprite_free(image);
  89. }
  90. if (scale_to_term_width) {
  91. struct winsize w;
  92. ioctl(0, TIOCGWINSZ, &w);
  93. int new_height = (w.ws_xpixel * image->height) / image->width;
  94. source = create_sprite(w.ws_xpixel, new_height, 1);
  95. gfx_context_t * g = init_graphics_sprite(source);
  96. draw_fill(g, 0x00000000);
  97. draw_sprite_scaled(g, image, 0, 0, w.ws_xpixel, new_height);
  98. sprite_free(image);
  99. }
  100. int width_in_cells = source->width / w;
  101. if (source->width % w) width_in_cells++;
  102. int height_in_cells = source->height / h;
  103. if (source->height % h) height_in_cells++;
  104. raw_output();
  105. printf("\033[?25l");
  106. for (int y = 0; y < height_in_cells; y++) {
  107. for (int x = 0; x < width_in_cells; x++) {
  108. printf("\033Ts");
  109. uint32_t * tmp = malloc(sizeof(uint32_t) * w * h);
  110. for (int yy = 0; yy < h; yy++) {
  111. for (int xx = 0; xx < w; xx++) {
  112. if (x*w + xx >= source->width || y*h + yy >= source->height) {
  113. tmp[yy * w + xx] = rgba(0,0,0,TERM_DEFAULT_OPAC);
  114. } else {
  115. uint32_t data = alpha_blend_rgba(
  116. rgba(0,0,0,TERM_DEFAULT_OPAC),
  117. premultiply(source->bitmap[(x*w+xx)+(y*h+yy)*source->width]));
  118. tmp[yy * w + xx] = data;
  119. }
  120. }
  121. }
  122. fwrite(tmp, sizeof(uint32_t) * w * h, 1, stdout);
  123. free(tmp);
  124. fflush(stdout);
  125. }
  126. if (y != height_in_cells - 1 || !no_newline) {
  127. printf("\r\n");
  128. }
  129. }
  130. sprite_free(source);
  131. printf("\033[?25h");
  132. unraw_output();
  133. fflush(stdout);
  134. optind++;
  135. }
  136. return 0;
  137. }