png2c.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. #include <assert.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <stdint.h>
  5. #include <stdbool.h>
  6. #include <string.h>
  7. #include <errno.h>
  8. #include <ctype.h>
  9. #define STB_IMAGE_IMPLEMENTATION
  10. #include "./stb_image.h"
  11. #define NOB_IMPLEMENTATION
  12. #define NOB_STRIP_PREFIX
  13. #include "nob.h"
  14. void usage(FILE *out, const char *program_name)
  15. {
  16. fprintf(out, "Usage: %s [OPTIONS] <input/file/path.png>\n", program_name);
  17. fprintf(out, "Options:\n");
  18. fprintf(out, " -o <output/file/path.h>\n");
  19. fprintf(out, " -n <name>\n");
  20. }
  21. void generate_c_code_from_pixels(FILE *out, uint32_t *data, int x, int y, const char *name)
  22. {
  23. size_t name_len = strlen(name);
  24. char *capital_name = malloc(name_len + 1);
  25. assert(capital_name != NULL && "Buy more RAM, I guess");
  26. for (size_t i = 0; i < name_len; ++i) {
  27. capital_name[i] = toupper(name[i]);
  28. }
  29. capital_name[name_len] = '\0';
  30. fprintf(out, "#ifndef %s_H_\n", capital_name);
  31. fprintf(out, "#define %s_H_\n", capital_name);
  32. fprintf(out, "size_t %s_width = %d;\n", name, x);
  33. fprintf(out, "size_t %s_height = %d;\n", name, y);
  34. fprintf(out, "uint32_t %s_pixels[] = {\n", name);
  35. size_t length = (size_t)(x * y);
  36. size_t width = 7;
  37. for (size_t i = 0; i < (length + width - 1)/width; ++i) {
  38. fprintf(out, " ");
  39. for (size_t j = 0; j < width && i*width + j < length; ++j) {
  40. fprintf(out, "0x%08X,", data[i*width + j]);
  41. }
  42. fprintf(out, "\n");
  43. }
  44. fprintf(out, "};\n");
  45. fprintf(out, "#endif // %s_H_\n", capital_name);
  46. //defer:
  47. free(capital_name);
  48. }
  49. bool generate_c_file_from_png(const char *input_file_path, const char *output_file_path, const char *name)
  50. {
  51. bool result = true;
  52. FILE *out = NULL;
  53. uint32_t *data = NULL;
  54. {
  55. int x, y;
  56. data = (uint32_t *)stbi_load(input_file_path, &x, &y, NULL, 4);
  57. if (data == NULL) {
  58. fprintf(stderr, "ERROR: Could not load file `%s`: %s\n", input_file_path, stbi_failure_reason());
  59. return_defer(false);
  60. }
  61. if (output_file_path) {
  62. out = fopen(output_file_path, "wb");
  63. if (out == NULL) {
  64. fprintf(stderr, "ERROR: could not write to file `%s`: %s\n", output_file_path, strerror(errno));
  65. return_defer(false);
  66. }
  67. generate_c_code_from_pixels(out, data, x, y, name);
  68. } else {
  69. generate_c_code_from_pixels(stdout, data, x, y, name);
  70. }
  71. }
  72. defer:
  73. if (out) fclose(out);
  74. if (data) stbi_image_free(data);
  75. return result;
  76. }
  77. int main(int argc, char *argv[])
  78. {
  79. assert(argc > 0);
  80. const char *program_name = shift(argv, argc);
  81. const char *output_file_path = NULL;
  82. const char *input_file_path = NULL;
  83. const char *name = NULL;
  84. while (argc > 0) {
  85. const char *flag = shift(argv, argc);
  86. if (strcmp(flag, "-o") == 0) {
  87. if (argc <= 0) {
  88. usage(stderr, program_name);
  89. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  90. return 1;
  91. }
  92. if (output_file_path != NULL) {
  93. usage(stderr, program_name);
  94. fprintf(stderr, "ERROR: %s was already provided\n", flag);
  95. return 1;
  96. }
  97. output_file_path = shift(argv, argc);
  98. } else if (strcmp(flag, "-n") == 0) {
  99. if (argc <= 0) {
  100. usage(stderr, program_name);
  101. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  102. return 1;
  103. }
  104. if (name != NULL) {
  105. usage(stderr, program_name);
  106. fprintf(stderr, "ERROR: %s was already provided\n", flag);
  107. return 1;
  108. }
  109. name = shift(argv, argc);
  110. } else {
  111. if (input_file_path != NULL) {
  112. usage(stderr, program_name);
  113. fprintf(stderr, "ERROR: input file path was already provided\n");
  114. return 1;
  115. }
  116. input_file_path = flag;
  117. }
  118. }
  119. if (input_file_path == NULL) {
  120. usage(stderr, program_name);
  121. fprintf(stderr, "ERROR: expected input file path\n");
  122. return(1);
  123. }
  124. if (name == NULL) {
  125. name = "png";
  126. } else {
  127. size_t n = strlen(name);
  128. if (n == 0) {
  129. fprintf(stderr, "ERROR: name cannot be empty\n");
  130. return 1;
  131. }
  132. if (isdigit(name[0])) {
  133. fprintf(stderr, "ERROR: name cannot start from a digit\n");
  134. return 1;
  135. }
  136. for (size_t i = 0; i < n; ++i) {
  137. if (!isalnum(name[i]) && name[i] != '_') {
  138. fprintf(stderr, "ERROR: name can only contains alphanumeric characters and underscores\n");
  139. return 1;
  140. }
  141. }
  142. }
  143. if (!generate_c_file_from_png(input_file_path, output_file_path, name)) return 1;
  144. return 0;
  145. }