Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

533 lines
13 KiB

  1. /*
  2. * pnm2png.c --- conversion from PBM/PGM/PPM-file to PNG-file
  3. * copyright (C) 1999 by Willem van Schaik <willem@schaik.com>
  4. *
  5. * version 1.0 - 1999.10.15 - First version.
  6. *
  7. * Permission to use, copy, modify, and distribute this software and
  8. * its documentation for any purpose and without fee is hereby granted,
  9. * provided that the above copyright notice appear in all copies and
  10. * that both that copyright notice and this permission notice appear in
  11. * supporting documentation. This software is provided "as is" without
  12. * express or implied warranty.
  13. */
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #ifdef __TURBOC__
  17. #include <mem.h>
  18. #include <fcntl.h>
  19. #endif
  20. #ifndef BOOL
  21. #define BOOL unsigned char
  22. #endif
  23. #ifndef TRUE
  24. #define TRUE (BOOL) 1
  25. #endif
  26. #ifndef FALSE
  27. #define FALSE (BOOL) 0
  28. #endif
  29. #define STDIN 0
  30. #define STDOUT 1
  31. #define STDERR 2
  32. /* to make pnm2png verbose so we can find problems (needs to be before png.h) */
  33. #ifndef PNG_DEBUG
  34. #define PNG_DEBUG 0
  35. #endif
  36. #include "png.h"
  37. /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */
  38. #ifndef png_jmpbuf
  39. # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
  40. #endif
  41. /* function prototypes */
  42. int main (int argc, char *argv[]);
  43. void usage ();
  44. BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha);
  45. void get_token(FILE *pnm_file, char *token);
  46. png_uint_32 get_data (FILE *pnm_file, int depth);
  47. png_uint_32 get_value (FILE *pnm_file, int depth);
  48. /*
  49. * main
  50. */
  51. int main(int argc, char *argv[])
  52. {
  53. FILE *fp_rd = stdin;
  54. FILE *fp_al = NULL;
  55. FILE *fp_wr = stdout;
  56. BOOL interlace = FALSE;
  57. BOOL alpha = FALSE;
  58. int argi;
  59. for (argi = 1; argi < argc; argi++)
  60. {
  61. if (argv[argi][0] == '-')
  62. {
  63. switch (argv[argi][1])
  64. {
  65. case 'i':
  66. interlace = TRUE;
  67. break;
  68. case 'a':
  69. alpha = TRUE;
  70. argi++;
  71. if ((fp_al = fopen (argv[argi], "rb")) == NULL)
  72. {
  73. fprintf (stderr, "PNM2PNG\n");
  74. fprintf (stderr, "Error: alpha-channel file %s does not exist\n",
  75. argv[argi]);
  76. exit (1);
  77. }
  78. break;
  79. case 'h':
  80. case '?':
  81. usage();
  82. exit(0);
  83. break;
  84. default:
  85. fprintf (stderr, "PNM2PNG\n");
  86. fprintf (stderr, "Error: unknown option %s\n", argv[argi]);
  87. usage();
  88. exit(1);
  89. break;
  90. } /* end switch */
  91. }
  92. else if (fp_rd == stdin)
  93. {
  94. if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
  95. {
  96. fprintf (stderr, "PNM2PNG\n");
  97. fprintf (stderr, "Error: file %s does not exist\n", argv[argi]);
  98. exit (1);
  99. }
  100. }
  101. else if (fp_wr == stdout)
  102. {
  103. if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
  104. {
  105. fprintf (stderr, "PNM2PNG\n");
  106. fprintf (stderr, "Error: can not create PNG-file %s\n", argv[argi]);
  107. exit (1);
  108. }
  109. }
  110. else
  111. {
  112. fprintf (stderr, "PNM2PNG\n");
  113. fprintf (stderr, "Error: too many parameters\n");
  114. usage();
  115. exit (1);
  116. }
  117. } /* end for */
  118. #ifdef __TURBOC__
  119. /* set stdin/stdout to binary, we're reading the PNM always! in binary format */
  120. if (fp_rd == stdin)
  121. {
  122. setmode (STDIN, O_BINARY);
  123. }
  124. if (fp_wr == stdout)
  125. {
  126. setmode (STDOUT, O_BINARY);
  127. }
  128. #endif
  129. /* call the conversion program itself */
  130. if (pnm2png (fp_rd, fp_wr, fp_al, interlace, alpha) == FALSE)
  131. {
  132. fprintf (stderr, "PNM2PNG\n");
  133. fprintf (stderr, "Error: unsuccessful converting to PNG-image\n");
  134. exit (1);
  135. }
  136. /* close input file */
  137. fclose (fp_rd);
  138. /* close output file */
  139. fclose (fp_wr);
  140. /* close alpha file */
  141. if (alpha)
  142. fclose (fp_al);
  143. return 0;
  144. }
  145. /*
  146. * usage
  147. */
  148. void usage()
  149. {
  150. fprintf (stderr, "PNM2PNG\n");
  151. fprintf (stderr, " by Willem van Schaik, 1999\n");
  152. #ifdef __TURBOC__
  153. fprintf (stderr, " for Turbo-C and Borland-C compilers\n");
  154. #else
  155. fprintf (stderr, " for Linux (and Unix) compilers\n");
  156. #endif
  157. fprintf (stderr, "Usage: pnm2png [options] <file>.<pnm> [<file>.png]\n");
  158. fprintf (stderr, " or: ... | pnm2png [options]\n");
  159. fprintf (stderr, "Options:\n");
  160. fprintf (stderr, " -i[nterlace] write png-file with interlacing on\n");
  161. fprintf (stderr, " -a[lpha] <file>.pgm read PNG alpha channel as pgm-file\n");
  162. fprintf (stderr, " -h | -? print this help-information\n");
  163. }
  164. /*
  165. * pnm2png
  166. */
  167. BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha)
  168. {
  169. png_struct *png_ptr = NULL;
  170. png_info *info_ptr = NULL;
  171. png_byte *png_pixels = NULL;
  172. png_byte **row_pointers = NULL;
  173. png_byte *pix_ptr = NULL;
  174. png_uint_32 row_bytes;
  175. char type_token[16];
  176. char width_token[16];
  177. char height_token[16];
  178. char maxval_token[16];
  179. int color_type;
  180. png_uint_32 width, alpha_width;
  181. png_uint_32 height, alpha_height;
  182. png_uint_32 maxval;
  183. int bit_depth = 0;
  184. int channels;
  185. int alpha_depth = 0;
  186. int alpha_present;
  187. int row, col;
  188. BOOL raw, alpha_raw = FALSE;
  189. png_uint_32 tmp16;
  190. int i;
  191. /* read header of PNM file */
  192. get_token(pnm_file, type_token);
  193. if (type_token[0] != 'P')
  194. {
  195. return FALSE;
  196. }
  197. else if ((type_token[1] == '1') || (type_token[1] == '4'))
  198. {
  199. raw = (type_token[1] == '4');
  200. color_type = PNG_COLOR_TYPE_GRAY;
  201. bit_depth = 1;
  202. }
  203. else if ((type_token[1] == '2') || (type_token[1] == '5'))
  204. {
  205. raw = (type_token[1] == '5');
  206. color_type = PNG_COLOR_TYPE_GRAY;
  207. get_token(pnm_file, width_token);
  208. sscanf (width_token, "%lu", &width);
  209. get_token(pnm_file, height_token);
  210. sscanf (height_token, "%lu", &height);
  211. get_token(pnm_file, maxval_token);
  212. sscanf (maxval_token, "%lu", &maxval);
  213. if (maxval <= 1)
  214. bit_depth = 1;
  215. else if (maxval <= 3)
  216. bit_depth = 2;
  217. else if (maxval <= 15)
  218. bit_depth = 4;
  219. else if (maxval <= 255)
  220. bit_depth = 8;
  221. else /* if (maxval <= 65535) */
  222. bit_depth = 16;
  223. }
  224. else if ((type_token[1] == '3') || (type_token[1] == '6'))
  225. {
  226. raw = (type_token[1] == '6');
  227. color_type = PNG_COLOR_TYPE_RGB;
  228. get_token(pnm_file, width_token);
  229. sscanf (width_token, "%lu", &width);
  230. get_token(pnm_file, height_token);
  231. sscanf (height_token, "%lu", &height);
  232. get_token(pnm_file, maxval_token);
  233. sscanf (maxval_token, "%lu", &maxval);
  234. if (maxval <= 1)
  235. bit_depth = 1;
  236. else if (maxval <= 3)
  237. bit_depth = 2;
  238. else if (maxval <= 15)
  239. bit_depth = 4;
  240. else if (maxval <= 255)
  241. bit_depth = 8;
  242. else /* if (maxval <= 65535) */
  243. bit_depth = 16;
  244. }
  245. else
  246. {
  247. return FALSE;
  248. }
  249. /* read header of PGM file with alpha channel */
  250. if (alpha)
  251. {
  252. if (color_type == PNG_COLOR_TYPE_GRAY)
  253. color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
  254. if (color_type == PNG_COLOR_TYPE_RGB)
  255. color_type = PNG_COLOR_TYPE_RGB_ALPHA;
  256. get_token(alpha_file, type_token);
  257. if (type_token[0] != 'P')
  258. {
  259. return FALSE;
  260. }
  261. else if ((type_token[1] == '2') || (type_token[1] == '5'))
  262. {
  263. alpha_raw = (type_token[1] == '5');
  264. get_token(alpha_file, width_token);
  265. sscanf (width_token, "%lu", &alpha_width);
  266. if (alpha_width != width)
  267. return FALSE;
  268. get_token(alpha_file, height_token);
  269. sscanf (height_token, "%lu", &alpha_height);
  270. if (alpha_height != height)
  271. return FALSE;
  272. get_token(alpha_file, maxval_token);
  273. sscanf (maxval_token, "%lu", &maxval);
  274. if (maxval <= 1)
  275. alpha_depth = 1;
  276. else if (maxval <= 3)
  277. alpha_depth = 2;
  278. else if (maxval <= 15)
  279. alpha_depth = 4;
  280. else if (maxval <= 255)
  281. alpha_depth = 8;
  282. else /* if (maxval <= 65535) */
  283. alpha_depth = 16;
  284. if (alpha_depth != bit_depth)
  285. return FALSE;
  286. }
  287. else
  288. {
  289. return FALSE;
  290. }
  291. } /* end if alpha */
  292. /* calculate the number of channels and store alpha-presence */
  293. if (color_type == PNG_COLOR_TYPE_GRAY)
  294. channels = 1;
  295. else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  296. channels = 2;
  297. else if (color_type == PNG_COLOR_TYPE_RGB)
  298. channels = 3;
  299. else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  300. channels = 4;
  301. else
  302. channels = 0; /* should not happen */
  303. alpha_present = (channels - 1) % 2;
  304. /* row_bytes is the width x number of channels x (bit-depth / 8) */
  305. row_bytes = width * channels * ((bit_depth <= 8) ? 1 : 2);
  306. if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL)
  307. return FALSE;
  308. /* read data from PNM file */
  309. pix_ptr = png_pixels;
  310. for (row = 0; row < height; row++)
  311. {
  312. for (col = 0; col < width; col++)
  313. {
  314. for (i = 0; i < (channels - alpha_present); i++)
  315. {
  316. if (raw)
  317. *pix_ptr++ = get_data (pnm_file, bit_depth);
  318. else
  319. if (bit_depth <= 8)
  320. *pix_ptr++ = get_value (pnm_file, bit_depth);
  321. else
  322. {
  323. tmp16 = get_value (pnm_file, bit_depth);
  324. *pix_ptr = (png_byte) ((tmp16 >> 8) & 0xFF);
  325. pix_ptr++;
  326. *pix_ptr = (png_byte) (tmp16 & 0xFF);
  327. pix_ptr++;
  328. }
  329. }
  330. if (alpha) /* read alpha-channel from pgm file */
  331. {
  332. if (alpha_raw)
  333. *pix_ptr++ = get_data (alpha_file, alpha_depth);
  334. else
  335. if (alpha_depth <= 8)
  336. *pix_ptr++ = get_value (alpha_file, bit_depth);
  337. else
  338. {
  339. tmp16 = get_value (alpha_file, bit_depth);
  340. *pix_ptr++ = (png_byte) ((tmp16 >> 8) & 0xFF);
  341. *pix_ptr++ = (png_byte) (tmp16 & 0xFF);
  342. }
  343. } /* if alpha */
  344. } /* end for col */
  345. } /* end for row */
  346. /* prepare the standard PNG structures */
  347. png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  348. if (!png_ptr)
  349. {
  350. return FALSE;
  351. }
  352. info_ptr = png_create_info_struct (png_ptr);
  353. if (!info_ptr)
  354. {
  355. png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
  356. return FALSE;
  357. }
  358. /* setjmp() must be called in every function that calls a PNG-reading libpng function */
  359. if (setjmp (png_jmpbuf(png_ptr)))
  360. {
  361. png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
  362. return FALSE;
  363. }
  364. /* initialize the png structure */
  365. png_init_io (png_ptr, png_file);
  366. /* we're going to write more or less the same PNG as the input file */
  367. png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type,
  368. (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7,
  369. PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  370. /* write the file header information */
  371. png_write_info (png_ptr, info_ptr);
  372. /* if needed we will allocate memory for an new array of row-pointers */
  373. if (row_pointers == (unsigned char**) NULL)
  374. {
  375. if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
  376. {
  377. png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
  378. return FALSE;
  379. }
  380. }
  381. /* set the individual row_pointers to point at the correct offsets */
  382. for (i = 0; i < (height); i++)
  383. row_pointers[i] = png_pixels + i * row_bytes;
  384. /* write out the entire image data in one call */
  385. png_write_image (png_ptr, row_pointers);
  386. /* write the additional chuncks to the PNG file (not really needed) */
  387. png_write_end (png_ptr, info_ptr);
  388. /* clean up after the write, and free any memory allocated */
  389. png_destroy_write_struct (&png_ptr, (png_infopp) NULL);
  390. if (row_pointers != (unsigned char**) NULL)
  391. free (row_pointers);
  392. if (png_pixels != (unsigned char*) NULL)
  393. free (png_pixels);
  394. return TRUE;
  395. } /* end of pnm2png */
  396. /*
  397. * get_token() - gets the first string after whitespace
  398. */
  399. void get_token(FILE *pnm_file, char *token)
  400. {
  401. int i = 0;
  402. /* remove white-space */
  403. do
  404. {
  405. token[i] = (unsigned char) fgetc (pnm_file);
  406. }
  407. while ((token[i] == '\n') || (token[i] == '\r') || (token[i] == ' '));
  408. /* read string */
  409. do
  410. {
  411. i++;
  412. token[i] = (unsigned char) fgetc (pnm_file);
  413. }
  414. while ((token[i] != '\n') && (token[i] != '\r') && (token[i] != ' '));
  415. token[i] = '\0';
  416. return;
  417. }
  418. /*
  419. * get_data() - takes first byte and converts into next pixel value,
  420. * taking as much bits as defined by bit-depth and
  421. * using the bit-depth to fill up a byte (0Ah -> AAh)
  422. */
  423. png_uint_32 get_data (FILE *pnm_file, int depth)
  424. {
  425. static int bits_left = 0;
  426. static int old_value = 0;
  427. static int mask = 0;
  428. int i;
  429. png_uint_32 ret_value;
  430. if (mask == 0)
  431. for (i = 0; i < depth; i++)
  432. mask = (mask >> 1) | 0x80;
  433. if (bits_left <= 0)
  434. {
  435. old_value = fgetc (pnm_file);
  436. bits_left = 8;
  437. }
  438. ret_value = old_value & mask;
  439. for (i = 1; i < (8 / depth); i++)
  440. ret_value = ret_value || (ret_value >> depth);
  441. old_value = (old_value << depth) & 0xFF;
  442. bits_left -= depth;
  443. return ret_value;
  444. }
  445. /*
  446. * get_value() - takes first (numeric) string and converts into number,
  447. * using the bit-depth to fill up a byte (0Ah -> AAh)
  448. */
  449. png_uint_32 get_value (FILE *pnm_file, int depth)
  450. {
  451. static png_uint_32 mask = 0;
  452. png_byte token[16];
  453. png_uint_32 ret_value;
  454. int i = 0;
  455. if (mask == 0)
  456. for (i = 0; i < depth; i++)
  457. mask = (mask << 1) | 0x01;
  458. get_token (pnm_file, (char *) token);
  459. sscanf ((const char *) token, "%lu", &ret_value);
  460. ret_value &= mask;
  461. if (depth < 8)
  462. for (i = 0; i < (8 / depth); i++)
  463. ret_value = (ret_value << depth) || ret_value;
  464. return ret_value;
  465. }
  466. /* end of source */