png2pnm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. /*
  2. * png2pnm.c --- conversion from PNG-file to PGM/PPM-file
  3. * copyright (C) 1999-2019 by Willem van Schaik <willem at schaik dot com>
  4. *
  5. * This software is released under the MIT license. For conditions of
  6. * distribution and use, see the LICENSE file part of this package.
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <fcntl.h>
  11. #ifndef BOOL
  12. #define BOOL unsigned char
  13. #endif
  14. #ifndef TRUE
  15. #define TRUE (BOOL) 1
  16. #endif
  17. #ifndef FALSE
  18. #define FALSE (BOOL) 0
  19. #endif
  20. /* make png2pnm verbose so we can find problems (needs to be before png.h) */
  21. #ifndef PNG_DEBUG
  22. #define PNG_DEBUG 0
  23. #endif
  24. #include "png.h"
  25. /* function prototypes */
  26. int main (int argc, char *argv[]);
  27. void usage ();
  28. BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
  29. BOOL raw, BOOL alpha);
  30. /*
  31. * main
  32. */
  33. int main (int argc, char *argv[])
  34. {
  35. FILE *fp_rd = stdin;
  36. FILE *fp_wr = stdout;
  37. FILE *fp_al = NULL;
  38. BOOL raw = TRUE;
  39. BOOL alpha = FALSE;
  40. int argi;
  41. for (argi = 1; argi < argc; argi++)
  42. {
  43. if (argv[argi][0] == '-')
  44. {
  45. switch (argv[argi][1])
  46. {
  47. case 'n':
  48. raw = FALSE;
  49. break;
  50. case 'r':
  51. raw = TRUE;
  52. break;
  53. case 'a':
  54. alpha = TRUE;
  55. argi++;
  56. if ((fp_al = fopen (argv[argi], "wb")) == NULL)
  57. {
  58. fprintf (stderr, "PNM2PNG\n");
  59. fprintf (stderr, "Error: cannot create alpha-channel file %s\n",
  60. argv[argi]);
  61. exit (1);
  62. }
  63. break;
  64. case 'h':
  65. case '?':
  66. usage ();
  67. exit (0);
  68. break;
  69. default:
  70. fprintf (stderr, "PNG2PNM\n");
  71. fprintf (stderr, "Error: unknown option %s\n", argv[argi]);
  72. usage ();
  73. exit (1);
  74. break;
  75. } /* end switch */
  76. }
  77. else if (fp_rd == stdin)
  78. {
  79. if ((fp_rd = fopen (argv[argi], "rb")) == NULL)
  80. {
  81. fprintf (stderr, "PNG2PNM\n");
  82. fprintf (stderr, "Error: file %s does not exist\n", argv[argi]);
  83. exit (1);
  84. }
  85. }
  86. else if (fp_wr == stdout)
  87. {
  88. if ((fp_wr = fopen (argv[argi], "wb")) == NULL)
  89. {
  90. fprintf (stderr, "PNG2PNM\n");
  91. fprintf (stderr, "Error: cannot create file %s\n", argv[argi]);
  92. exit (1);
  93. }
  94. }
  95. else
  96. {
  97. fprintf (stderr, "PNG2PNM\n");
  98. fprintf (stderr, "Error: too many parameters\n");
  99. usage ();
  100. exit (1);
  101. }
  102. } /* end for */
  103. #if defined(O_BINARY) && (O_BINARY != 0)
  104. /* set stdin/stdout if required to binary */
  105. if (fp_rd == stdin)
  106. setmode (fileno (stdin), O_BINARY);
  107. if ((raw) && (fp_wr == stdout))
  108. setmode (fileno (stdout), O_BINARY);
  109. #endif
  110. /* call the conversion program itself */
  111. if (png2pnm (fp_rd, fp_wr, fp_al, raw, alpha) == FALSE)
  112. {
  113. fprintf (stderr, "PNG2PNM\n");
  114. fprintf (stderr, "Error: unsuccessful conversion of PNG-image\n");
  115. exit (1);
  116. }
  117. /* close input file */
  118. fclose (fp_rd);
  119. /* close output file */
  120. fclose (fp_wr);
  121. /* close alpha file */
  122. if (alpha)
  123. fclose (fp_al);
  124. return 0;
  125. }
  126. /*
  127. * usage
  128. */
  129. void usage ()
  130. {
  131. fprintf (stderr, "PNG2PNM\n");
  132. fprintf (stderr, " by Willem van Schaik, 1999\n");
  133. fprintf (stderr, "Usage: png2pnm [options] <file>.png [<file>.pnm]\n");
  134. fprintf (stderr, " or: ... | png2pnm [options]\n");
  135. fprintf (stderr, "Options:\n");
  136. fprintf (stderr,
  137. " -r[aw] write pnm-file in binary format (P4/P5/P6) (default)\n");
  138. fprintf (stderr, " -n[oraw] write pnm-file in ascii format (P1/P2/P3)\n");
  139. fprintf (stderr,
  140. " -a[lpha] <file>.pgm write PNG alpha channel as pgm-file\n");
  141. fprintf (stderr, " -h | -? print this help-information\n");
  142. }
  143. /*
  144. * png2pnm
  145. */
  146. BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file,
  147. BOOL raw, BOOL alpha)
  148. {
  149. png_struct *png_ptr = NULL;
  150. png_info *info_ptr = NULL;
  151. png_byte buf[8];
  152. png_byte *png_pixels = NULL;
  153. png_byte **row_pointers = NULL;
  154. png_byte *pix_ptr = NULL;
  155. png_uint_32 row_bytes;
  156. png_uint_32 width;
  157. png_uint_32 height;
  158. int bit_depth;
  159. int channels;
  160. int color_type;
  161. int alpha_present;
  162. int row, col;
  163. int ret;
  164. int i;
  165. long dep_16;
  166. /* read and check signature in PNG file */
  167. ret = fread (buf, 1, 8, png_file);
  168. if (ret != 8)
  169. return FALSE;
  170. ret = png_sig_cmp (buf, 0, 8);
  171. if (ret != 0)
  172. return FALSE;
  173. /* create png and info structures */
  174. png_ptr = png_create_read_struct (png_get_libpng_ver(NULL),
  175. NULL, NULL, NULL);
  176. if (!png_ptr)
  177. return FALSE; /* out of memory */
  178. info_ptr = png_create_info_struct (png_ptr);
  179. if (!info_ptr)
  180. {
  181. png_destroy_read_struct (&png_ptr, NULL, NULL);
  182. return FALSE; /* out of memory */
  183. }
  184. if (setjmp (png_jmpbuf (png_ptr)))
  185. {
  186. png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  187. return FALSE;
  188. }
  189. /* set up the input control for C streams */
  190. png_init_io (png_ptr, png_file);
  191. png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */
  192. /* read the file information */
  193. png_read_info (png_ptr, info_ptr);
  194. /* get size and bit-depth of the PNG-image */
  195. png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
  196. NULL, NULL, NULL);
  197. /* set-up the transformations */
  198. /* transform paletted images into full-color rgb */
  199. if (color_type == PNG_COLOR_TYPE_PALETTE)
  200. png_set_expand (png_ptr);
  201. /* expand images to bit-depth 8 (only applicable for grayscale images) */
  202. if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
  203. png_set_expand (png_ptr);
  204. /* transform transparency maps into full alpha-channel */
  205. if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
  206. png_set_expand (png_ptr);
  207. #ifdef NJET
  208. /* downgrade 16-bit images to 8-bit */
  209. if (bit_depth == 16)
  210. png_set_strip_16 (png_ptr);
  211. /* transform grayscale images into full-color */
  212. if (color_type == PNG_COLOR_TYPE_GRAY ||
  213. color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  214. png_set_gray_to_rgb (png_ptr);
  215. /* only if file has a file gamma, we do a correction */
  216. if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
  217. png_set_gamma (png_ptr, (double) 2.2, file_gamma);
  218. #endif
  219. /* all transformations have been registered; now update info_ptr data,
  220. * get rowbytes and channels, and allocate image memory */
  221. png_read_update_info (png_ptr, info_ptr);
  222. /* get the new color-type and bit-depth (after expansion/stripping) */
  223. png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
  224. NULL, NULL, NULL);
  225. /* check for 16-bit files */
  226. if (bit_depth == 16)
  227. {
  228. raw = FALSE;
  229. #if defined(O_BINARY) && (O_BINARY != 0)
  230. setmode (fileno (pnm_file), O_BINARY);
  231. #endif
  232. }
  233. /* calculate new number of channels and store alpha-presence */
  234. if (color_type == PNG_COLOR_TYPE_GRAY)
  235. channels = 1;
  236. else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
  237. channels = 2;
  238. else if (color_type == PNG_COLOR_TYPE_RGB)
  239. channels = 3;
  240. else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
  241. channels = 4;
  242. else
  243. channels = 0; /* should never happen */
  244. alpha_present = (channels - 1) % 2;
  245. /* check if alpha is expected to be present in file */
  246. if (alpha && !alpha_present)
  247. {
  248. fprintf (stderr, "PNG2PNM\n");
  249. fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n");
  250. exit (1);
  251. }
  252. /* row_bytes is the width x number of channels x (bit-depth / 8) */
  253. row_bytes = png_get_rowbytes (png_ptr, info_ptr);
  254. if ((row_bytes == 0) ||
  255. ((size_t) height > (size_t) (-1) / (size_t) row_bytes))
  256. {
  257. /* too big */
  258. png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  259. return FALSE;
  260. }
  261. if ((png_pixels = (png_byte *)
  262. malloc ((size_t) row_bytes * (size_t) height)) == NULL)
  263. {
  264. png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  265. return FALSE;
  266. }
  267. if ((row_pointers = (png_byte **)
  268. malloc ((size_t) height * sizeof (png_byte *))) == NULL)
  269. {
  270. png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  271. free (png_pixels);
  272. return FALSE;
  273. }
  274. /* set the individual row_pointers to point at the correct offsets */
  275. for (i = 0; i < ((int) height); i++)
  276. row_pointers[i] = png_pixels + i * row_bytes;
  277. /* now we can go ahead and just read the whole image */
  278. png_read_image (png_ptr, row_pointers);
  279. /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
  280. png_read_end (png_ptr, info_ptr);
  281. /* clean up after the read, and free any memory allocated - REQUIRED */
  282. png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
  283. /* write header of PNM file */
  284. if ((color_type == PNG_COLOR_TYPE_GRAY) ||
  285. (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
  286. {
  287. fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
  288. fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
  289. fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  290. }
  291. else if ((color_type == PNG_COLOR_TYPE_RGB) ||
  292. (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
  293. {
  294. fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
  295. fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
  296. fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  297. }
  298. /* write header of PGM file with alpha channel */
  299. if ((alpha) &&
  300. ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
  301. (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
  302. {
  303. fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
  304. fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
  305. fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  306. }
  307. /* write data to PNM file */
  308. pix_ptr = png_pixels;
  309. for (row = 0; row < (int) height; row++)
  310. {
  311. for (col = 0; col < (int) width; col++)
  312. {
  313. for (i = 0; i < (channels - alpha_present); i++)
  314. {
  315. if (raw)
  316. {
  317. fputc ((int) *pix_ptr++, pnm_file);
  318. }
  319. else
  320. {
  321. if (bit_depth == 16)
  322. {
  323. dep_16 = (long) *pix_ptr++;
  324. fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
  325. }
  326. else
  327. {
  328. fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
  329. }
  330. }
  331. }
  332. if (alpha_present)
  333. {
  334. if (!alpha)
  335. {
  336. pix_ptr++; /* alpha */
  337. if (bit_depth == 16)
  338. pix_ptr++;
  339. }
  340. else /* output alpha-channel as pgm file */
  341. {
  342. if (raw)
  343. {
  344. fputc ((int) *pix_ptr++, alpha_file);
  345. }
  346. else
  347. {
  348. if (bit_depth == 16)
  349. {
  350. dep_16 = (long) *pix_ptr++;
  351. fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
  352. }
  353. else
  354. {
  355. fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
  356. }
  357. }
  358. }
  359. } /* end if alpha_present */
  360. if (!raw)
  361. if (col % 4 == 3)
  362. fprintf (pnm_file, "\n");
  363. } /* end for col */
  364. if (!raw)
  365. if (col % 4 != 0)
  366. fprintf (pnm_file, "\n");
  367. } /* end for row */
  368. if (row_pointers != NULL)
  369. free (row_pointers);
  370. if (png_pixels != NULL)
  371. free (png_pixels);
  372. return TRUE;
  373. } /* end of source */