main.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdint.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <unistd.h>
  8. #include <png.h>
  9. #include <setjmp.h>
  10. static uint32_t charToVal(char c) {
  11. switch(c) {
  12. case '0': return 0;
  13. case '1': return 1;
  14. case '2': return 2;
  15. case '3': return 3;
  16. case '4': return 4;
  17. case '5': return 5;
  18. case '6': return 6;
  19. case '7': return 7;
  20. case '8': return 8;
  21. case '9': return 9;
  22. case 'a': case 'A': return 10;
  23. case 'b': case 'B': return 11;
  24. case 'c': case 'C': return 12;
  25. case 'd': case 'D': return 13;
  26. case 'e': case 'E': return 14;
  27. case 'f': case 'F': return 15;
  28. };
  29. return 0;
  30. }
  31. static uint32_t doubleChar(char c) {
  32. uint32_t v = charToVal(c);
  33. return v & v << 4;
  34. }
  35. /*
  36. Parse color strings:
  37. #rrggbb
  38. #rrggbbaa
  39. #rgb
  40. #rgba
  41. green
  42. */
  43. uint32_t parseColor(char* s) {
  44. uint32_t c = 0x000000ff;
  45. if(!s) return 0xffffffff;
  46. if(s[0] == '#') {
  47. int len = strlen(s+1);
  48. if(len == 3 || len == 4) {
  49. c &= (doubleChar(s[1]) << 24) & (doubleChar(s[2]) << 16) & (doubleChar(s[3]) << 8);
  50. if(len == 4) {
  51. c &= doubleChar(s[4]);
  52. }
  53. }
  54. else if(len == 6 || len == 8) {
  55. c &= (charToVal(s[1]) << 28) &
  56. (charToVal(s[2]) << 24) &
  57. (charToVal(s[3]) << 20) &
  58. (charToVal(s[4]) << 16) &
  59. (charToVal(s[5]) << 12) &
  60. (charToVal(s[6]) << 8);
  61. if(len == 8) {
  62. c &= (charToVal(s[7]) << 4) & charToVal(s[8]);
  63. }
  64. }
  65. return c;
  66. }
  67. // check color strings.
  68. // TODO: some clever lookup
  69. if(0 == strcasecmp(s, "red")) return 0xff0000ff;
  70. if(0 == strcasecmp(s, "green")) return 0xff00ff00;
  71. if(0 == strcasecmp(s, "blue")) return 0xffff0000;
  72. if(0 == strcasecmp(s, "magenta")) return 0xffff00ff;
  73. if(0 == strcasecmp(s, "yellow")) return 0xff00ffff;
  74. if(0 == strcasecmp(s, "cyan")) return 0xffffff00;
  75. if(0 == strcasecmp(s, "black")) return 0xff000000;
  76. if(0 == strcasecmp(s, "white")) return 0xffffffff;
  77. if(0 == strcasecmp(s, "gray")) return 0xff888888;
  78. if(0 == strcasecmp(s, "grey")) return 0xff888888;
  79. if(0 == strcasecmp(s, "silver")) return 0xffbbbbbb;
  80. if(0 == strcasecmp(s, "darkgray")) return 0xff444444;
  81. if(0 == strcasecmp(s, "darkgrey")) return 0xff444444;
  82. if(0 == strcasecmp(s, "darkred")) return 0xff000088;
  83. if(0 == strcasecmp(s, "darkgreen")) return 0xff008800;
  84. if(0 == strcasecmp(s, "darkblue")) return 0xff880000;
  85. if(0 == strcasecmp(s, "navy")) return 0xff440000;
  86. if(0 == strcasecmp(s, "forest")) return 0xff004400;
  87. if(0 == strcasecmp(s, "maroon")) return 0xff000044;
  88. if(0 == strcasecmp(s, "darkyellow")) return 0xff008888;
  89. if(0 == strcasecmp(s, "olive")) return 0xff004444;
  90. return 0xffffffff;
  91. }
  92. int main(int argc, char* argv[]) {
  93. FILE* f;
  94. png_byte sig[8];
  95. png_bytep* rowPtrs;
  96. int i;
  97. png_structp pngPtr;
  98. png_infop infoPtr;
  99. int colorTypes[4] = {
  100. PNG_COLOR_TYPE_GRAY,
  101. PNG_COLOR_TYPE_GRAY_ALPHA,
  102. PNG_COLOR_TYPE_RGB,
  103. PNG_COLOR_TYPE_RGB_ALPHA
  104. };
  105. int ret = 2;
  106. long width = 10000, height = 1;
  107. int channels = 4;
  108. char* path;
  109. int w, h;
  110. char* data;
  111. int mode = 0;
  112. uint32_t color;
  113. if(argc < 2) {
  114. printf("usage: \n");
  115. exit(1);
  116. }
  117. // parse args
  118. for(int an = 1; an < argc; an++) {
  119. char* arg = argv[an];
  120. if(arg[0] == '-') {
  121. arg++;
  122. if(0 == strcasecmp(arg, "o")) {
  123. path = argv[++an];
  124. continue;
  125. }
  126. if(0 == strcasecmp(arg, "c")) {
  127. channels = strtol(argv[++an], NULL, 10);
  128. continue;
  129. }
  130. if(0 == strcasecmp(arg, "w")) {
  131. width = strtol(argv[++an], NULL, 10);
  132. continue;
  133. }
  134. if(0 == strcasecmp(arg, "h")) {
  135. height = strtol(argv[++an], NULL, 10);
  136. continue;
  137. }
  138. if(0 == strcasecmp(arg, "m")) {
  139. mode = strtol(argv[++an], NULL, 10);
  140. continue;
  141. }
  142. // fill color
  143. if(0 == strcasecmp(arg, "f")) {
  144. color = parseColor(argv[++an]);
  145. continue;
  146. }
  147. }
  148. path = argv[an];
  149. }
  150. printf("size: %ld x %ld\n", width, height);
  151. if(channels > 4 || channels < 1) {
  152. return 3;
  153. }
  154. // file stuff
  155. f = fopen(path, "wb");
  156. if(!f) {
  157. fprintf(stderr, "Could not open \"%s\" (writePNG).\n", path);
  158. return 1;
  159. }
  160. /*
  161. if(png_sig_cmp(sig, 0, 8)) {
  162. fprintf(stderr, "\"%s\" is not a valid PNG file.\n", path);
  163. fclose(f);
  164. return NULL;
  165. }
  166. */
  167. // init stuff
  168. pngPtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  169. if (!pngPtr) {
  170. goto CLEANUP1;
  171. }
  172. //png_destroy_write_struct (&pngPtr, (png_infopp)NULL);
  173. infoPtr = png_create_info_struct(pngPtr);
  174. if (!infoPtr) {
  175. goto CLEANUP2;
  176. }
  177. //if(infoPtr != NULL) png_free_data(pngPtr, infoPtr, PNG_FREE_ALL, -1);
  178. // header stuff
  179. if (setjmp(png_jmpbuf(pngPtr))) {
  180. goto CLEANUP3;
  181. }
  182. png_init_io(pngPtr, f);
  183. png_set_user_limits(pngPtr, 0x7fffffff, 0x7fffffff);
  184. if (setjmp(png_jmpbuf(pngPtr))) {
  185. goto CLEANUP3;
  186. }
  187. png_set_IHDR(pngPtr, infoPtr, width, height,
  188. 8, colorTypes[channels - 1], PNG_INTERLACE_NONE,
  189. PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  190. png_write_info(pngPtr, infoPtr);
  191. data = calloc(1, channels * width + 8);
  192. uint32_t* di = (uint32_t*)data;
  193. for(long i = 0; i < (channels * width / 4) + 4; i++) {
  194. di[i] = color;
  195. }
  196. png_bytep rowPtr = data;
  197. // write data
  198. if (setjmp(png_jmpbuf(pngPtr))) {
  199. goto CLEANUP4;
  200. }
  201. for(int i = 0; i < height; i++) {
  202. png_write_row(pngPtr, rowPtr);
  203. }
  204. if (setjmp(png_jmpbuf(pngPtr))) {
  205. goto CLEANUP4;
  206. }
  207. png_write_end(pngPtr, NULL);
  208. // success
  209. ret = 0;
  210. fclose(f);
  211. struct stat st;
  212. stat(path, &st);
  213. printf("file size: %ld bytes\n", st.st_size);
  214. CLEANUP4:
  215. CLEANUP3:
  216. if(infoPtr != NULL) png_free_data(pngPtr, infoPtr, PNG_FREE_ALL, -1);
  217. CLEANUP2:
  218. png_destroy_write_struct (&pngPtr, (png_infopp)NULL);
  219. CLEANUP1:
  220. fclose(f);
  221. return 0;
  222. }