PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/pngdefry.c

https://github.com/appurify/pngdefry
C | 1514 lines | 1277 code | 117 blank | 120 comment | 292 complexity | b798eea2465999bddbd867f1a23f2fe0 MD5 | raw file
  1. /* pngdefry.c v1.1 - public domain PNG reading/writing/modification, PNG writing
  2. See "unlicense" statement at the end of this file.
  3. [Jongware], 21-Jan-2012
  4. Attempts to repair -iphone "optimized" PNG images by removing the invalid chunk "CgBI",
  5. swapping pixel order from BGR(A) to RGB(A), and removing pre-multiplied alpha.
  6. Use with care. No guarantees.
  7. This program uses miniz.c (http://code.google.com/p/miniz/) by Rich Geldreich
  8. (Rich Geldreich <richgel99@gmail.com>, last updated May 27, 2011)
  9. Version used is included in the original file package.
  10. No-License Agreement
  11. ====================
  12. This program is hereby put into the public domain, no limitations at all. Do with this code
  13. whatever you want, I don't care. (Well, replacing my name with yours and leaving everything
  14. else unchanged would be pretty lame.)
  15. */
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <strings.h>
  20. #include <sys/types.h>
  21. #include "miniz.c"
  22. /** Global flags, set on the command line **/
  23. int flag_Verbose = 0;
  24. int flag_Process_Anyway = 0;
  25. int flag_List_Chunks = 0;
  26. int flag_Debug = 0;
  27. int flag_UpdateAlpha = 1;
  28. int repack_IDAT_size = 524288; /* 512K -- seems a bit much to me, axually, but have seen this used */
  29. int flag_Rewrite = 0;
  30. char *suffix = NULL;
  31. char *outputPath = NULL;
  32. unsigned char png_magic_bytes[] = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
  33. /** Chunk data comes here **/
  34. struct chunk_t {
  35. unsigned int length;
  36. unsigned int id;
  37. unsigned char *data;
  38. unsigned int crc32;
  39. };
  40. int num_chunks = 0;
  41. int max_chunks = 0;
  42. struct chunk_t *pngChunks = NULL;
  43. /** CRC32 generator for a block of data, thanks to Marc Autret
  44. (he wrote this original code in Javascript for use in InDesign!) **/
  45. unsigned int CRC_256[] = {
  46. 0, 0x77073096, 0xee0e612c, 0x990951ba, 0x76dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0xedb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x9b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
  47. 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
  48. 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  49. 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
  50. 0x76dc4190, 0x1db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x6b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0xf00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x86d3d2d, 0x91646c97, 0xe6635c01,
  51. 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  52. 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
  53. 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
  54. 0xedb88320, 0x9abfb3b6, 0x3b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x4db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0xd6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0xa00ae27, 0x7d079eb1,
  55. 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
  56. 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
  57. 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  58. 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x26d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x5005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0xcb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0xbdbdf21,
  59. 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
  60. 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  61. 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
  62. };
  63. int crc32s (unsigned char *buf, int buf_length)
  64. {
  65. unsigned int c = 0xffffffff;
  66. int i;
  67. for (i=0; i < buf_length; i++ )
  68. c = CRC_256[(c ^ buf[i]) & 0xff] ^ (c >> 8);
  69. return (c ^ 0xffffffff);
  70. };
  71. int get_long (FILE *f)
  72. {
  73. return (fgetc(f)<<24) + (fgetc(f)<<16) + (fgetc(f)<<8) + fgetc(f);
  74. }
  75. int get_short (FILE *f)
  76. {
  77. return (fgetc(f)<<8) + fgetc(f);
  78. }
  79. int read_long (void *src)
  80. {
  81. return (((unsigned char *)src)[0]<<24) + (((unsigned char *)src)[1]<<16) + (((unsigned char *)src)[2]<<8) + ((unsigned char *)src)[3];
  82. }
  83. int init_chunk (FILE *f, unsigned int filelength)
  84. {
  85. struct chunk_t one_chunk;
  86. unsigned char buf[8];
  87. if (fread (buf, 1,4, f) != 4)
  88. {
  89. if (feof(f))
  90. return 0;
  91. if (flag_Debug)
  92. printf (" informational : failed to read chunk length\n");
  93. return -3;
  94. }
  95. one_chunk.length = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
  96. if (one_chunk.length > filelength-4)
  97. {
  98. if (flag_Debug)
  99. printf (" informational : chunk length %u larger than file\n", one_chunk.length);
  100. return -1;
  101. }
  102. one_chunk.data = (unsigned char *)malloc (one_chunk.length+4);
  103. if (one_chunk.data == NULL)
  104. {
  105. if (flag_Debug)
  106. printf (" informational : no memory for chunk length %u\n", one_chunk.length);
  107. return -2;
  108. }
  109. if (fread (one_chunk.data, 1, one_chunk.length+4, f) != one_chunk.length+4)
  110. {
  111. if (flag_Debug)
  112. printf (" informational : failed to read chunk length %u\n", one_chunk.length);
  113. return -3;
  114. }
  115. one_chunk.id = (one_chunk.data[0] << 24) + (one_chunk.data[1] << 16) + (one_chunk.data[2] << 8) + one_chunk.data[3];
  116. if (fread (buf, 1,4, f) != 4)
  117. {
  118. if (flag_Debug)
  119. printf (" informational : failed to read chunk crc32\n");
  120. return -3;
  121. }
  122. one_chunk.crc32 = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
  123. if (num_chunks >= max_chunks)
  124. {
  125. max_chunks += 8;
  126. if (pngChunks == NULL)
  127. pngChunks = (struct chunk_t *)malloc (max_chunks * sizeof(struct chunk_t));
  128. else
  129. pngChunks = (struct chunk_t *)realloc (pngChunks, max_chunks * sizeof(struct chunk_t));
  130. }
  131. pngChunks[num_chunks].id = one_chunk.id;
  132. pngChunks[num_chunks].length = one_chunk.length;
  133. pngChunks[num_chunks].data = one_chunk.data;
  134. pngChunks[num_chunks].crc32 = one_chunk.crc32;
  135. num_chunks++;
  136. return 0;
  137. }
  138. void reset_chunks (void)
  139. {
  140. int i;
  141. for (i=0; i<num_chunks; i++)
  142. {
  143. if (pngChunks[i].length && pngChunks[i].data)
  144. {
  145. free (pngChunks[i].data);
  146. pngChunks[i].data = NULL;
  147. }
  148. }
  149. num_chunks = 0;
  150. }
  151. void demultiplyAlpha (int wide, int high, unsigned char *data)
  152. {
  153. int x,y;
  154. unsigned char *srcPtr;
  155. srcPtr = data;
  156. for (y=0; y<high; y++)
  157. {
  158. /* skip rowfilter -- it's assumed to be 0 here anyway! */
  159. srcPtr++;
  160. for (x=0; x<4*wide; x+=4)
  161. {
  162. if (srcPtr[x+3])
  163. {
  164. srcPtr[x] = (srcPtr[x]*255+(srcPtr[x+3]>>1))/srcPtr[x+3];
  165. srcPtr[x+1] = (srcPtr[x+1]*255+(srcPtr[x+3]>>1))/srcPtr[x+3];
  166. srcPtr[x+2] = (srcPtr[x+2]*255+(srcPtr[x+3]>>1))/srcPtr[x+3];
  167. }
  168. }
  169. srcPtr += 4*wide;
  170. }
  171. }
  172. void removeRowFilters (int wide, int high, unsigned char *data)
  173. {
  174. int x,y, rowfilter;
  175. unsigned char *srcPtr, *upPtr;
  176. srcPtr = data;
  177. for (y=0; y<high; y++)
  178. {
  179. rowfilter = *srcPtr;
  180. /* Need to save original filter for re-applying! */
  181. /* *srcPtr = 0; */
  182. srcPtr++;
  183. switch (rowfilter)
  184. {
  185. case 0: // None
  186. break;
  187. case 1: // Sub
  188. for (x=4; x<4*wide; x++)
  189. {
  190. srcPtr[x] += srcPtr[x-4];
  191. }
  192. break;
  193. case 2: // Up
  194. upPtr = srcPtr - 4*wide - 1;
  195. if (y > 0)
  196. {
  197. for (x=0; x<4*wide; x++)
  198. {
  199. srcPtr[x] += upPtr[x];
  200. }
  201. }
  202. break;
  203. case 3: // Average
  204. upPtr = srcPtr - 4*wide - 1;
  205. if (y == 0)
  206. {
  207. for (x=4; x<4*wide; x++)
  208. {
  209. srcPtr[x] += (srcPtr[x-4]>>1);
  210. }
  211. } else
  212. {
  213. srcPtr[0] += (upPtr[x]>>1);
  214. for (x=4; x<4*wide; x++)
  215. {
  216. srcPtr[x] += ((upPtr[x] + srcPtr[x-4])>>1);
  217. }
  218. }
  219. break;
  220. case 4: // Paeth
  221. upPtr = srcPtr - 4*wide - 1;
  222. {
  223. int p,pa,pb,pc,value;
  224. int leftpix,toppix,topleftpix;
  225. for (x=0; x<4*wide; x++)
  226. {
  227. leftpix = 0;
  228. toppix = 0;
  229. topleftpix = 0;
  230. if (x > 0)
  231. leftpix = srcPtr[x-4];
  232. if (y > 0)
  233. {
  234. toppix = upPtr[x];
  235. if (x >= 4)
  236. topleftpix = upPtr[x-4];
  237. }
  238. p = leftpix + toppix - topleftpix;
  239. pa = p - leftpix; if (pa < 0) pa = -pa;
  240. pb = p - toppix; if (pb < 0) pb = -pb;
  241. pc = p - topleftpix; if (pc < 0) pc = -pc;
  242. if (pa <= pb && pa <= pc)
  243. value = leftpix;
  244. else if (pb <= pc)
  245. value = toppix;
  246. else
  247. value = topleftpix;
  248. srcPtr[x] += value;
  249. }
  250. }
  251. break;
  252. default:
  253. printf ("removerowfilter() : Unknown row filter %d\n", rowfilter);
  254. }
  255. srcPtr += 4*wide;
  256. }
  257. }
  258. void applyRowFilters (int wide, int high, unsigned char *data)
  259. {
  260. int x,y, rowfilter;
  261. unsigned char *srcPtr, *upPtr;
  262. srcPtr = data;
  263. for (y=0; y<high; y++)
  264. {
  265. rowfilter = *srcPtr;
  266. srcPtr++;
  267. switch (rowfilter)
  268. {
  269. case 0: // None
  270. break;
  271. case 1: // Sub
  272. for (x=4*wide-1; x>=4; x--)
  273. {
  274. srcPtr[x] -= srcPtr[x-4];
  275. }
  276. break;
  277. case 2: // Up
  278. if (y > 0)
  279. {
  280. upPtr = srcPtr - 1;
  281. for (x=4*wide-1; x>=0; x--)
  282. {
  283. srcPtr[x] -= upPtr[x];
  284. }
  285. }
  286. break;
  287. case 3: // Average
  288. upPtr = srcPtr - 4*wide - 1;
  289. if (y == 0)
  290. {
  291. for (x=4*wide-1; x>=4; x--)
  292. {
  293. srcPtr[x] -= (srcPtr[x-4]>>1);
  294. }
  295. } else
  296. {
  297. srcPtr[0] -= (upPtr[x]>>1);
  298. for (x=4*wide-1; x>=4; x--)
  299. {
  300. srcPtr[x] -= ((upPtr[x] + srcPtr[x-4])>>1);
  301. }
  302. }
  303. break;
  304. case 4: // Paeth
  305. upPtr = srcPtr - 1;
  306. {
  307. int p,pa,pb,pc,value;
  308. int leftpix,toppix,topleftpix;
  309. for (x=4*wide-1; x>=0; x--)
  310. {
  311. leftpix = 0;
  312. toppix = 0;
  313. topleftpix = 0;
  314. if (x > 0)
  315. leftpix = srcPtr[x-4];
  316. if (y > 0)
  317. {
  318. toppix = upPtr[x];
  319. if (x >= 4)
  320. topleftpix = upPtr[x-4];
  321. }
  322. p = leftpix + toppix - topleftpix;
  323. pa = p - leftpix; if (pa < 0) pa = -pa;
  324. pb = p - toppix; if (pb < 0) pb = -pb;
  325. pc = p - topleftpix; if (pc < 0) pc = -pc;
  326. if (pa <= pb && pa <= pc)
  327. value = leftpix;
  328. else if (pb <= pc)
  329. value = toppix;
  330. else
  331. value = topleftpix;
  332. srcPtr[x] -= value;
  333. }
  334. }
  335. break;
  336. default:
  337. printf ("applyrowfilter : Unknown row filter %d\n", rowfilter);
  338. }
  339. srcPtr += 4*wide;
  340. }
  341. }
  342. int process (char *filename)
  343. {
  344. FILE *f;
  345. unsigned int length;
  346. int i;
  347. unsigned char buf[16];
  348. /* This is what we're looking for */
  349. int isPhoney = 0;
  350. /* Standard IHDR items: */
  351. unsigned int imgwidth, imgheight, bitdepth,colortype, compression, filter, interlace;
  352. /* Derived IHRD items: */
  353. unsigned int bitspp;
  354. unsigned int bytespp;
  355. unsigned int bytespline;
  356. struct chunk_t *ihdr_chunk = NULL;
  357. int idat_first_index = 0;
  358. unsigned char *all_idat = NULL;
  359. unsigned int total_idat_size = 0;
  360. /* Adam7 interlacing information */
  361. int Starting_Row [] = { 0, 0, 4, 0, 2, 0, 1 };
  362. int Starting_Col [] = { 0, 4, 0, 2, 0, 1, 0 };
  363. int Row_Increment [] = { 8, 8, 8, 4, 4, 2, 2 };
  364. int Col_Increment [] = { 8, 8, 4, 4, 2, 2, 1 };
  365. int row_filter_bytes = 0;
  366. /* Needed for unpacking/repacking */
  367. unsigned char *data_out;
  368. int out_length;
  369. unsigned char *data_repack = NULL;
  370. int repack_size, repack_length;
  371. /* New file name comes here */
  372. char *write_file_name = NULL;
  373. FILE *write_file;
  374. int write_block_size;
  375. /* int i,j,b;
  376. int blocklength, blockid;
  377. unsigned int filterbytes;
  378. int isInterlaced = 0; */
  379. int didShowName = 0;
  380. int crc, result;
  381. f = fopen (filename, "rb");
  382. if (!f)
  383. {
  384. printf ("%s : not found or could not be opened\n", filename);
  385. return 0;
  386. }
  387. fseek (f, 0, SEEK_END);
  388. length = ftell (f);
  389. fseek (f, 0, SEEK_SET);
  390. i = 0;
  391. fread (buf,1,8, f); i += 8;
  392. if (memcmp (buf, png_magic_bytes, 8))
  393. {
  394. printf ("%s : not a PNG file\n", filename);
  395. fclose (f);
  396. return 0;
  397. }
  398. result = init_chunk (f, length);
  399. if (result < 0)
  400. {
  401. fclose (f);
  402. switch (result)
  403. {
  404. case -1: printf ("%s : invalid chunk size\n", filename); break;
  405. case -2: printf ("%s : out of memory\n", filename); break;
  406. case -3: printf ("%s : premature end of file\n", filename); break;
  407. }
  408. reset_chunks ();
  409. return 0;
  410. }
  411. isPhoney = 1;
  412. if (pngChunks[0].id != 0x43674249) /* "CgBI" */
  413. {
  414. isPhoney = 0;
  415. printf ("%s : not an -iphone crushed PNG file\n", filename);
  416. if (!flag_Process_Anyway)
  417. {
  418. fclose (f);
  419. reset_chunks ();
  420. return 0;
  421. }
  422. didShowName = 1;
  423. }
  424. do
  425. {
  426. result = init_chunk (f, length);
  427. if (result < 0)
  428. {
  429. fclose (f);
  430. if (didShowName)
  431. printf (" ");
  432. else
  433. {
  434. didShowName = 1;
  435. printf ("%s : ", filename);
  436. }
  437. switch (result)
  438. {
  439. case -1: printf ("invalid chunk size\n"); break;
  440. case -2: printf ("out of memory\n"); break;
  441. case -3: printf ("premature end of file\n"); break;
  442. default: printf ("error code %d\n", result);
  443. }
  444. reset_chunks ();
  445. return 0;
  446. }
  447. if (num_chunks > 0 && pngChunks[num_chunks-1].id == 0x49454E44) /* "IEND" */
  448. break;
  449. } while (!feof(f));
  450. if (pngChunks[num_chunks-1].id != 0x49454E44) /* "IEND" */
  451. {
  452. fclose (f);
  453. if (didShowName)
  454. printf (" ");
  455. else
  456. {
  457. didShowName = 1;
  458. printf ("%s : ", filename);
  459. }
  460. printf ("missing IEND chunk\n");
  461. reset_chunks ();
  462. return 0;
  463. }
  464. if (fgetc (f) != EOF)
  465. {
  466. if (didShowName)
  467. printf (" ");
  468. else
  469. {
  470. didShowName = 1;
  471. printf ("%s : ", filename);
  472. }
  473. printf ("Extra data after IEND, very suspicious! Excluded from conversion\n");
  474. }
  475. fclose (f);
  476. if (flag_List_Chunks)
  477. {
  478. for (i=0; i<num_chunks; i++)
  479. {
  480. if (!didShowName)
  481. {
  482. didShowName = 1;
  483. printf ("%s :\n", filename);
  484. }
  485. printf (" chunk : %c%c%c%c length %6u CRC32 %08X", (pngChunks[i].id >> 24) & 0xff,(pngChunks[i].id >> 16) & 0xff, (pngChunks[i].id >> 8) & 0xff,pngChunks[i].id & 0xff, pngChunks[i].length, pngChunks[i].crc32);
  486. crc = crc32s (pngChunks[i].data, pngChunks[i].length+4);
  487. if (pngChunks[i].crc32 != crc)
  488. printf (" --> CRC32 check invalid! Should be %08X", crc);
  489. printf ("\n");
  490. }
  491. } else
  492. {
  493. for (i=0; i<num_chunks; i++)
  494. {
  495. crc = crc32s (pngChunks[i].data, pngChunks[i].length+4);
  496. if (pngChunks[i].crc32 != crc)
  497. {
  498. if (!didShowName)
  499. {
  500. didShowName = 1;
  501. printf ("%s :\n", filename);
  502. }
  503. printf (" chunk : %c%c%c%c length %6u CRC32 %08X", (pngChunks[i].id >> 24) & 0xff,(pngChunks[i].id >> 16) & 0xff, (pngChunks[i].id >> 8) & 0xff,pngChunks[i].id & 0xff, pngChunks[i].length, pngChunks[i].crc32);
  504. printf (" -> invalid, changed to %08X\n", crc);
  505. pngChunks[i].crc32 = crc;
  506. }
  507. }
  508. }
  509. if (pngChunks[0].id == 0x43674249) /* "CgBI" */
  510. {
  511. if (num_chunks > 0 && pngChunks[1].id == 0x49484452) /* "IHDR" */
  512. ihdr_chunk = &pngChunks[1];
  513. } else
  514. {
  515. if (pngChunks[0].id == 0x49484452) /* "IHDR" */
  516. ihdr_chunk = &pngChunks[0];
  517. }
  518. if (ihdr_chunk == NULL)
  519. {
  520. if (didShowName)
  521. printf (" ");
  522. else
  523. {
  524. didShowName = 1;
  525. printf ("%s : ", filename);
  526. }
  527. printf ("no IHDR chunk found\n");
  528. reset_chunks ();
  529. return 0;
  530. }
  531. if (ihdr_chunk->length != 13)
  532. {
  533. if (didShowName)
  534. printf (" ");
  535. else
  536. {
  537. didShowName = 1;
  538. printf ("%s : ", filename);
  539. }
  540. printf ("IHDR chunk length incorrect\n");
  541. reset_chunks ();
  542. return 0;
  543. }
  544. imgwidth = read_long (&ihdr_chunk->data[4]);
  545. imgheight = read_long (&ihdr_chunk->data[8]);
  546. bitdepth = ihdr_chunk->data[12];
  547. colortype = ihdr_chunk->data[13];
  548. compression = ihdr_chunk->data[14];
  549. filter = ihdr_chunk->data[15];
  550. interlace = ihdr_chunk->data[16];
  551. if (imgwidth == 0 || imgheight == 0 || imgwidth > 2147483647 || imgheight > 2147483647)
  552. {
  553. if (didShowName)
  554. printf (" ");
  555. else
  556. {
  557. didShowName = 1;
  558. printf ("%s : ", filename);
  559. }
  560. printf ("image dimensions invalid\n");
  561. reset_chunks ();
  562. return 0;
  563. }
  564. if (compression != 0)
  565. {
  566. if (didShowName)
  567. printf (" ");
  568. else
  569. {
  570. didShowName = 1;
  571. printf ("%s : ", filename);
  572. }
  573. printf ("unknown compression type %d\n", compression);
  574. reset_chunks ();
  575. return 0;
  576. }
  577. if (filter != 0)
  578. {
  579. if (didShowName)
  580. printf (" ");
  581. else
  582. {
  583. didShowName = 1;
  584. printf ("%s : ", filename);
  585. }
  586. printf ("unknown filter type %d\n", filter);
  587. reset_chunks ();
  588. return 0;
  589. }
  590. if (interlace != 0 && interlace != 1)
  591. {
  592. if (didShowName)
  593. printf (" ");
  594. else
  595. {
  596. didShowName = 1;
  597. printf ("%s : ", filename);
  598. }
  599. printf ("unknown interlace type %d\n", interlace);
  600. reset_chunks ();
  601. return 0;
  602. }
  603. /*** From PNG Specs, http://www.w3.org/TR/PNG-Chunks.html
  604. Color Allowed Interpretation
  605. Type Bit Depths
  606. ------ ---------- ----------------------------------
  607. 0 1,2,4,8,16 Each pixel is a grayscale sample.
  608. 2 8,16 Each pixel is an R,G,B triple.
  609. 3 1,2,4,8 Each pixel is a palette index;
  610. a PLTE chunk must appear.
  611. 4 8,16 Each pixel is a grayscale sample,
  612. followed by an alpha sample.
  613. 6 8,16 Each pixel is an R,G,B triple,
  614. followed by an alpha sample.
  615. ***/
  616. i = 0;
  617. switch (colortype)
  618. {
  619. case 0:
  620. if (bitdepth == 1 ||
  621. bitdepth == 2 ||
  622. bitdepth == 4 ||
  623. bitdepth == 8 ||
  624. bitdepth == 16)
  625. i = 1;
  626. bitspp = bitdepth;
  627. break;
  628. case 2:
  629. if (bitdepth == 8 ||
  630. bitdepth == 16)
  631. i = 1;
  632. bitspp = 3*bitdepth;
  633. break;
  634. case 3:
  635. if (bitdepth == 1 ||
  636. bitdepth == 2 ||
  637. bitdepth == 4 ||
  638. bitdepth == 8)
  639. i = 1;
  640. bitspp = bitdepth;
  641. break;
  642. case 4:
  643. if (bitdepth == 8 ||
  644. bitdepth == 16)
  645. i = 1;
  646. bitspp = 2*bitdepth;
  647. break;
  648. case 6:
  649. if (bitdepth == 8 ||
  650. bitdepth == 16)
  651. i = 1;
  652. bitspp = 4*bitdepth;
  653. break;
  654. default:
  655. if (didShowName)
  656. printf (" ");
  657. else
  658. {
  659. didShowName = 1;
  660. printf ("%s : ", filename);
  661. }
  662. printf ("unknown color type %d\n", colortype);
  663. reset_chunks ();
  664. return 0;
  665. }
  666. if (!i)
  667. {
  668. if (didShowName)
  669. printf (" ");
  670. else
  671. {
  672. didShowName = 1;
  673. printf ("%s : ", filename);
  674. }
  675. printf ("invalid bit depth %d for color type %d\n", bitdepth, colortype);
  676. reset_chunks ();
  677. return 0;
  678. }
  679. bytespline = (imgwidth*bitspp+7)/8;
  680. /* Warning!
  681. This value is only valid for 8/16 bit images! */
  682. bytespp = (bitspp+7)/8;
  683. if (flag_Verbose)
  684. {
  685. if (!didShowName)
  686. {
  687. didShowName = 1;
  688. printf ("%s :\n", filename);
  689. }
  690. printf (" image width : %u\n", imgwidth);
  691. printf (" image height : %u\n", imgheight);
  692. printf (" bit depth : %u\n", bitdepth);
  693. printf (" color type : %u\n", colortype);
  694. printf (" compression : %u\n", compression);
  695. printf (" filter : %u\n", filter);
  696. printf (" interlace : %u\n", interlace);
  697. printf (" bits per pixel : %d\n", bitspp);
  698. printf (" bytes per line : %d\n", bytespline);
  699. }
  700. row_filter_bytes = imgheight;
  701. if (interlace == 1)
  702. {
  703. int w,h,pass;
  704. if (flag_Verbose)
  705. printf (" Adam7 interlacing:\n");
  706. row_filter_bytes = 0;
  707. for (pass=0; pass<7; pass++)
  708. {
  709. /* Formula taken from pngcheck ! */
  710. w = (imgwidth - Starting_Col[pass] + Col_Increment[pass] - 1)/Col_Increment[pass];
  711. h = (imgheight - Starting_Row[pass] + Row_Increment[pass] - 1)/Row_Increment[pass];
  712. if (flag_Verbose)
  713. printf (" pass %d: %d x %d\n", pass, w, h);
  714. row_filter_bytes += h;
  715. }
  716. }
  717. if (flag_Verbose)
  718. {
  719. printf (" row filter bytes : %u\n", row_filter_bytes);
  720. printf (" expected data size : %u bytes\n", bytespline * imgheight + row_filter_bytes);
  721. }
  722. for (i=0; i<num_chunks; i++)
  723. {
  724. if (pngChunks[i].id == 0x49444154) /* "IDAT" */
  725. {
  726. idat_first_index = i;
  727. break;
  728. }
  729. }
  730. if (i == num_chunks)
  731. {
  732. if (didShowName)
  733. printf (" ");
  734. else
  735. {
  736. didShowName = 1;
  737. printf ("%s : ", filename);
  738. }
  739. printf ("no IDAT chunks found\n");
  740. reset_chunks ();
  741. return 0;
  742. }
  743. /** Test for consecutive IDAT chunks */
  744. /* continue where we left off */
  745. while (i < num_chunks)
  746. {
  747. if (pngChunks[i].id != 0x49444154) /* "IDAT" */
  748. break;
  749. total_idat_size += pngChunks[i].length;
  750. i++;
  751. }
  752. /* test the remaining chunks */
  753. while (i < num_chunks)
  754. {
  755. if (pngChunks[i].id == 0x49444154) /* "IDAT" */
  756. break;
  757. i++;
  758. }
  759. if (i != num_chunks)
  760. {
  761. if (didShowName)
  762. printf (" ");
  763. else
  764. {
  765. didShowName = 1;
  766. printf ("%s : ", filename);
  767. }
  768. printf ("IDAT chunks are not consecutive\n");
  769. reset_chunks ();
  770. return 0;
  771. }
  772. if (total_idat_size == 0)
  773. {
  774. if (didShowName)
  775. printf (" ");
  776. else
  777. {
  778. didShowName = 1;
  779. printf ("%s : ", filename);
  780. }
  781. printf ("all IDAT chunks are empty\n");
  782. reset_chunks ();
  783. return 0;
  784. }
  785. /* Only need to re-write the image data for -phone 8 bit RGB and RGBA images */
  786. /* Note To Self: Is that true? What about 16 bit images? What about palette images? */
  787. /* Okay -- checked the above, it appears these two do NOT get fried. */
  788. /* Swap BGR to RGB, BGRA to RGBA */
  789. if (bitdepth == 8 &&
  790. (colortype == 2 || /* Each pixel is an R,G,B triple (8 or 16 bits) */
  791. colortype == 6)) /* Each pixel is an R,G,B triple, followed by an alpha sample (8 or 16 bits) */
  792. {
  793. if (isPhoney && flag_Verbose)
  794. printf (" swapping BGR(A) to RGB(A)\n");
  795. /*** Gather all IDATs into one ***/
  796. if (flag_Debug)
  797. printf (" informational : total idat size: %u\n", total_idat_size);
  798. all_idat = (unsigned char *)malloc (total_idat_size);
  799. if (all_idat == NULL)
  800. {
  801. if (didShowName)
  802. printf (" ");
  803. else
  804. {
  805. didShowName = 1;
  806. printf ("%s : ", filename);
  807. }
  808. printf ("out of memory\n");
  809. reset_chunks ();
  810. return 0;
  811. }
  812. i = idat_first_index;
  813. total_idat_size = 0;
  814. while (i < num_chunks && pngChunks[i].id == 0x49444154) /* "IDAT" */
  815. {
  816. memcpy (all_idat+total_idat_size, pngChunks[i].data+4, pngChunks[i].length);
  817. total_idat_size += pngChunks[i].length;
  818. i++;
  819. }
  820. /*** So far everything appears to check out. Let's try uncompressing the IDAT chunks. ***/
  821. data_out = (unsigned char *)malloc (bytespline * imgheight + row_filter_bytes);
  822. if (data_out == NULL)
  823. {
  824. free (all_idat);
  825. if (didShowName)
  826. printf (" ");
  827. else
  828. {
  829. didShowName = 1;
  830. printf ("%s : ", filename);
  831. }
  832. printf ("out of memory\n");
  833. reset_chunks ();
  834. return 0;
  835. }
  836. if (isPhoney)
  837. out_length = tinfl_decompress_mem_to_mem(data_out, bytespline * imgheight + row_filter_bytes, all_idat, total_idat_size, 0);
  838. else
  839. out_length = tinfl_decompress_mem_to_mem(data_out, bytespline * imgheight + row_filter_bytes, all_idat, total_idat_size, TINFL_FLAG_PARSE_ZLIB_HEADER);
  840. free (all_idat);
  841. all_idat = NULL;
  842. if (out_length <= 0)
  843. {
  844. free (data_out);
  845. if (didShowName)
  846. printf (" ");
  847. else
  848. {
  849. didShowName = 1;
  850. printf ("%s : ", filename);
  851. }
  852. printf ("unspecified decompression error\n");
  853. reset_chunks ();
  854. return 0;
  855. }
  856. if (out_length != imgheight*bytespline + row_filter_bytes)
  857. {
  858. if (didShowName)
  859. printf (" ");
  860. else
  861. {
  862. didShowName = 1;
  863. printf ("%s : ", filename);
  864. }
  865. printf ("decompression error, expected %u but got %u bytes\n", imgheight*bytespline + row_filter_bytes, out_length);
  866. free (data_out);
  867. reset_chunks ();
  868. return 0;
  869. }
  870. if (flag_Verbose)
  871. printf (" uncompressed size : %u bytes\n", bytespline * imgheight + row_filter_bytes);
  872. if (isPhoney || flag_Process_Anyway)
  873. {
  874. if (interlace == 1) /* needs Adam7 unpacking! */
  875. {
  876. int x,y, b, row;
  877. int pass, w,h;
  878. int startat;
  879. /* check if all row filters are okay */
  880. y = 0;
  881. for (pass=0; pass<7; pass++)
  882. {
  883. w = (imgwidth - Starting_Col[pass] + Col_Increment[pass] - 1)/Col_Increment[pass];
  884. h = (imgheight - Starting_Row[pass] + Row_Increment[pass] - 1)/Row_Increment[pass];
  885. row=0;
  886. while (row < h)
  887. {
  888. if (data_out[y] > 4)
  889. {
  890. free (data_out);
  891. if (didShowName)
  892. printf (" ");
  893. else
  894. {
  895. didShowName = 1;
  896. printf ("%s : ", filename);
  897. }
  898. printf ("unknown row filter type (%d)\n", data_out[y]);
  899. reset_chunks ();
  900. return 0;
  901. }
  902. /* skip row filter byte */
  903. y++;
  904. /* skip rest of row */
  905. y += w * bytespp;
  906. row++;
  907. }
  908. }
  909. y = 0;
  910. for (pass=0; pass<7; pass++)
  911. {
  912. /* Formula taken from pngcheck ! */
  913. w = (imgwidth - Starting_Col[pass] + Col_Increment[pass] - 1)/Col_Increment[pass];
  914. h = (imgheight - Starting_Row[pass] + Row_Increment[pass] - 1)/Row_Increment[pass];
  915. startat = y;
  916. row=0;
  917. while (row < h)
  918. {
  919. /* skip row filter byte */
  920. y++;
  921. /* swap all bytes in this row */
  922. x = 0;
  923. while (x < w)
  924. {
  925. b = data_out[y+2];
  926. data_out[y+2] = data_out[y];
  927. data_out[y] = b;
  928. y += bytespp;
  929. x++;
  930. }
  931. row++;
  932. }
  933. if (isPhoney && flag_UpdateAlpha && colortype == 6) // RGBA
  934. {
  935. removeRowFilters (w, h, data_out+startat);
  936. demultiplyAlpha (w, h, data_out+startat);
  937. applyRowFilters (w, h, data_out+startat);
  938. }
  939. }
  940. } else
  941. {
  942. int x,y, b;
  943. /* check row filters */
  944. y = 0;
  945. while (y < bytespline * imgheight + row_filter_bytes)
  946. {
  947. if (data_out[y] > 4)
  948. {
  949. free (data_out);
  950. if (didShowName)
  951. printf (" ");
  952. else
  953. {
  954. didShowName = 1;
  955. printf ("%s : ", filename);
  956. }
  957. printf ("unknown row filter type (%d)\n", data_out[y]);
  958. reset_chunks ();
  959. return 0;
  960. }
  961. /* skip row filter byte */
  962. y++;
  963. /* skip entire row */
  964. y += bytespline;
  965. }
  966. y = 0;
  967. while (y < bytespline * imgheight + row_filter_bytes)
  968. {
  969. /* skip row filter byte */
  970. y++;
  971. /* swap all bytes in this row */
  972. x = 0;
  973. while (x < imgwidth)
  974. {
  975. b = data_out[y+2];
  976. data_out[y+2] = data_out[y];
  977. data_out[y] = b;
  978. y += bytespp;
  979. x++;
  980. }
  981. }
  982. if (isPhoney && flag_UpdateAlpha && colortype == 6) // RGBA
  983. {
  984. removeRowFilters (imgwidth, imgheight, data_out);
  985. demultiplyAlpha (imgwidth, imgheight, data_out);
  986. applyRowFilters (imgwidth, imgheight, data_out);
  987. }
  988. }
  989. }
  990. /* Force VERY conservative repacking size ... */
  991. repack_size = 2*(bytespline * imgheight + row_filter_bytes);
  992. data_repack = (unsigned char *)malloc (repack_size);
  993. if (data_repack == NULL)
  994. {
  995. free (data_out);
  996. if (didShowName)
  997. printf (" ");
  998. else
  999. {
  1000. didShowName = 1;
  1001. printf ("%s : ", filename);
  1002. }
  1003. printf ("out of memory\n");
  1004. reset_chunks ();
  1005. return 0;
  1006. }
  1007. /* ouch -- reserve 4 bytes at the start to put "IDAT" in! */
  1008. /* yeah well, it beats having to re-allocate each block on writing ... */
  1009. repack_length = tdefl_compress_mem_to_mem(data_repack+4, repack_size-4, data_out, out_length, TDEFL_WRITE_ZLIB_HEADER);
  1010. if (repack_length == 0)
  1011. {
  1012. free (data_out);
  1013. free (data_repack);
  1014. if (didShowName)
  1015. printf (" ");
  1016. else
  1017. {
  1018. didShowName = 1;
  1019. printf ("%s : ", filename);
  1020. }
  1021. printf ("unspecified compression error\n");
  1022. reset_chunks ();
  1023. return 0;
  1024. }
  1025. if (flag_Verbose)
  1026. printf (" repacked size: %u bytes\n", repack_length);
  1027. free (data_out);
  1028. }
  1029. if (flag_Rewrite)
  1030. {
  1031. if (outputPath && outputPath[0])
  1032. {
  1033. char *clipOffPath;
  1034. clipOffPath = strrchr (filename, '/');
  1035. if (clipOffPath)
  1036. clipOffPath++;
  1037. else
  1038. clipOffPath = filename;
  1039. if (suffix && suffix[0])
  1040. write_file_name = (char *)malloc (strlen(outputPath)+strlen(clipOffPath)+strlen(suffix)+8);
  1041. else
  1042. write_file_name = (char *)malloc (strlen(outputPath)+strlen(clipOffPath)+8);
  1043. if (write_file_name == NULL)
  1044. {
  1045. if (didShowName)
  1046. printf (" ");
  1047. else
  1048. {
  1049. didShowName = 1;
  1050. printf ("%s : ", filename);
  1051. }
  1052. printf ("failed to allocate memory for output file name ...\n");
  1053. reset_chunks ();
  1054. return 0;
  1055. }
  1056. strcpy (write_file_name, outputPath);
  1057. strcat (write_file_name, "/");
  1058. strcat (write_file_name, clipOffPath);
  1059. } else
  1060. {
  1061. write_file_name = (char *)malloc (strlen(filename)+strlen(suffix)+8);
  1062. if (write_file_name == NULL)
  1063. {
  1064. if (didShowName)
  1065. printf (" ");
  1066. else
  1067. {
  1068. didShowName = 1;
  1069. printf ("%s : ", filename);
  1070. }
  1071. printf ("failed to allocate memory for output file name ...\n");
  1072. reset_chunks ();
  1073. return 0;
  1074. }
  1075. strcpy (write_file_name, filename);
  1076. }
  1077. if (suffix && suffix[0])
  1078. {
  1079. if (!strcasecmp (write_file_name+strlen(write_file_name)-4, ".png"))
  1080. strcpy (write_file_name+strlen(write_file_name)-4, suffix);
  1081. else
  1082. strcat (write_file_name, suffix);
  1083. strcat (write_file_name, ".png");
  1084. }
  1085. if (!didShowName)
  1086. {
  1087. printf ("%s : ", filename);
  1088. }
  1089. printf ("writing to file %s\n", write_file_name);
  1090. write_file = fopen (write_file_name, "wb");
  1091. if (!write_file)
  1092. {
  1093. printf (" failed to create output file!\n");
  1094. reset_chunks ();
  1095. return 0;
  1096. }
  1097. fwrite (png_magic_bytes, 1, 8, write_file);
  1098. i = 0;
  1099. /* need to skip first bogus chunk */
  1100. /* at this point, I expect the first one to be IHDR! */
  1101. if (pngChunks[0].id == 0x43674249) /* "CgBI" */
  1102. i++;
  1103. while (i < num_chunks && pngChunks[i].id != 0x49444154) /* "IDAT" */
  1104. {
  1105. fputc ( (pngChunks[i].length >> 24) & 0xff, write_file);
  1106. fputc ( (pngChunks[i].length >> 16) & 0xff, write_file);
  1107. fputc ( (pngChunks[i].length >> 8) & 0xff, write_file);
  1108. fputc ( (pngChunks[i].length ) & 0xff, write_file);
  1109. fwrite (pngChunks[i].data, pngChunks[i].length+4, 1, write_file);
  1110. fputc ( (pngChunks[i].crc32 >> 24) & 0xff, write_file);
  1111. fputc ( (pngChunks[i].crc32 >> 16) & 0xff, write_file);
  1112. fputc ( (pngChunks[i].crc32 >> 8) & 0xff, write_file);
  1113. fputc ( (pngChunks[i].crc32 ) & 0xff, write_file);
  1114. i++;
  1115. }
  1116. /* Did we repack the data, or do we just need to rewrite the file? */
  1117. if (data_repack)
  1118. {
  1119. write_block_size = 0;
  1120. while (write_block_size < repack_length)
  1121. {
  1122. data_repack[4+write_block_size-4] = 'I';
  1123. data_repack[4+write_block_size-3] = 'D';
  1124. data_repack[4+write_block_size-2] = 'A';
  1125. data_repack[4+write_block_size-1] = 'T';
  1126. if (repack_length-write_block_size > repack_IDAT_size)
  1127. {
  1128. fputc ( (repack_IDAT_size >> 24) & 0xff, write_file);
  1129. fputc ( (repack_IDAT_size >> 16) & 0xff, write_file);
  1130. fputc ( (repack_IDAT_size >> 8) & 0xff, write_file);
  1131. fputc ( (repack_IDAT_size ) & 0xff, write_file);
  1132. fwrite ( data_repack+write_block_size, repack_IDAT_size+4,1, write_file);
  1133. crc = crc32s (data_repack+write_block_size, repack_IDAT_size+4);
  1134. fputc ( (crc >> 24) & 0xff, write_file);
  1135. fputc ( (crc >> 16) & 0xff, write_file);
  1136. fputc ( (crc >> 8) & 0xff, write_file);
  1137. fputc ( (crc ) & 0xff, write_file);
  1138. write_block_size += repack_IDAT_size;
  1139. } else
  1140. {
  1141. fputc ( ((repack_length-write_block_size) >> 24) & 0xff, write_file);
  1142. fputc ( ((repack_length-write_block_size) >> 16) & 0xff, write_file);
  1143. fputc ( ((repack_length-write_block_size) >> 8) & 0xff, write_file);
  1144. fputc ( ((repack_length-write_block_size) ) & 0xff, write_file);
  1145. fwrite ( data_repack+write_block_size, (repack_length-write_block_size)+4,1, write_file);
  1146. crc = crc32s (data_repack+write_block_size, (repack_length-write_block_size)+4);
  1147. fputc ( (crc >> 24) & 0xff, write_file);
  1148. fputc ( (crc >> 16) & 0xff, write_file);
  1149. fputc ( (crc >> 8) & 0xff, write_file);
  1150. fputc ( (crc ) & 0xff, write_file);
  1151. write_block_size = repack_length;
  1152. }
  1153. }
  1154. /* skip original IDAT chunks */
  1155. while (i < num_chunks && pngChunks[i].id == 0x49444154) /* "IDAT" */
  1156. i++;
  1157. free (data_repack);
  1158. } else
  1159. {
  1160. /* image was not repacked */
  1161. /* output original IDAT chunks */
  1162. while (i < num_chunks && pngChunks[i].id == 0x49444154) /* "IDAT" */
  1163. {
  1164. fputc ( (pngChunks[i].length >> 24) & 0xff, write_file);
  1165. fputc ( (pngChunks[i].length >> 16) & 0xff, write_file);
  1166. fputc ( (pngChunks[i].length >> 8) & 0xff, write_file);
  1167. fputc ( (pngChunks[i].length ) & 0xff, write_file);
  1168. fwrite (pngChunks[i].data, pngChunks[i].length+4, 1, write_file);
  1169. fputc ( (pngChunks[i].crc32 >> 24) & 0xff, write_file);
  1170. fputc ( (pngChunks[i].crc32 >> 16) & 0xff, write_file);
  1171. fputc ( (pngChunks[i].crc32 >> 8) & 0xff, write_file);
  1172. fputc ( (pngChunks[i].crc32 ) & 0xff, write_file);
  1173. i++;
  1174. }
  1175. }
  1176. /* output remaining chunks */
  1177. while (i < num_chunks)
  1178. {
  1179. fputc ( (pngChunks[i].length >> 24) & 0xff, write_file);
  1180. fputc ( (pngChunks[i].length >> 16) & 0xff, write_file);
  1181. fputc ( (pngChunks[i].length >> 8) & 0xff, write_file);
  1182. fputc ( (pngChunks[i].length ) & 0xff, write_file);
  1183. fwrite (pngChunks[i].data, pngChunks[i].length+4, 1, write_file);
  1184. fputc ( (pngChunks[i].crc32 >> 24) & 0xff, write_file);
  1185. fputc ( (pngChunks[i].crc32 >> 16) & 0xff, write_file);
  1186. fputc ( (pngChunks[i].crc32 >> 8) & 0xff, write_file);
  1187. fputc ( (pngChunks[i].crc32 ) & 0xff, write_file);
  1188. i++;
  1189. }
  1190. fclose (write_file);
  1191. free (write_file_name);
  1192. reset_chunks ();
  1193. return 1;
  1194. }
  1195. /* We come here if nothing was written */
  1196. /* Just show the name and go away */
  1197. if (!didShowName)
  1198. {
  1199. printf ("%s\n", filename);
  1200. }
  1201. if (data_repack)
  1202. free (data_repack);
  1203. reset_chunks ();
  1204. return 0;
  1205. }
  1206. int main (int argc, char **argv)
  1207. {
  1208. int i, nomoreoptions;
  1209. int seenFiles = 0, processedFiles = 0;
  1210. if (argc == 1)
  1211. {
  1212. printf ("PNGdefry version 1.1 by [Jongware], 21-Jan-2012\n");
  1213. printf ("\n");
  1214. printf ("Removes -iphone specific data chunk, reverses colors from BGRA to RGBA, and de-multiplies alpha\n");
  1215. printf ("\n");
  1216. printf ("usage: pngdefry [-soaplvid] file.png [...]\n");
  1217. printf ("\n");
  1218. printf ("Options:\n");
  1219. printf (" - use this if your first input file starts with an '-'\n");
  1220. printf (" -s(suffix) append suffix to output file name\n");
  1221. printf (" -o(path) write output file(s) to path\n");
  1222. printf (" Note: without -s or -o, NO output will be created.\n");
  1223. printf (" -a do NOT de-multiply alpha\n");
  1224. printf (" -l list all chunks\n");
  1225. printf (" -v verbose processing\n");
  1226. printf (" -i(value) max IDAT chunk size in bytes (minimum: 1024; default: %u)\n", repack_IDAT_size);
  1227. printf (" -p process all files, not just -iphone ones (for debugging purposed only)\n");
  1228. printf (" -d very verbose processing (for debugging purposes only)\n");
  1229. return 0;
  1230. }
  1231. nomoreoptions = 0;
  1232. for (i=1; i<argc; i++)
  1233. {
  1234. if (argv[i][0] != '-')
  1235. break;
  1236. switch (argv[i][1])
  1237. {
  1238. case 0:
  1239. nomoreoptions = 1;
  1240. break;
  1241. case 'd': flag_Debug = 1; flag_Verbose = 1; flag_List_Chunks = 1; break;
  1242. case 'a': flag_UpdateAlpha = 0; break;
  1243. case 'l': flag_List_Chunks = 1; break;
  1244. case 'p': flag_Process_Anyway = 1; break;
  1245. case 'v': flag_Verbose = 1; break;
  1246. case 's':
  1247. if (argv[i][2])
  1248. {
  1249. suffix = (char *)malloc(strlen(argv[i])+2);
  1250. if (suffix == NULL)
  1251. {
  1252. printf ("pngdefry : unexpected memory allocation error on line %d\n", __LINE__);
  1253. return -1;
  1254. }
  1255. strcpy (suffix, argv[i]+2);
  1256. } else
  1257. {
  1258. suffix = "";
  1259. }
  1260. argv[i][2] = 0;
  1261. flag_Rewrite = 1;
  1262. break;
  1263. case 'o':
  1264. if (argv[i][2])
  1265. {
  1266. outputPath = (char *)malloc(strlen(argv[i])+2);
  1267. if (outputPath == NULL)
  1268. {
  1269. printf ("pngdefry : unexpected memory allocation error on line %d\n", __LINE__);
  1270. return -1;
  1271. }
  1272. strcpy (outputPath, argv[i]+2);
  1273. } else
  1274. {
  1275. if (i < argc-1)
  1276. {
  1277. i++;
  1278. outputPath = (char *)malloc(strlen(argv[i])+2);
  1279. if (outputPath == NULL)
  1280. {
  1281. printf ("pngdefry : unexpected memory allocation error on line %d\n", __LINE__);
  1282. return -1;
  1283. }
  1284. strcpy (outputPath, argv[i]);
  1285. } else
  1286. {
  1287. printf ("pngdefry : -o is missing output path\n");
  1288. return -1;
  1289. }
  1290. }
  1291. argv[i][2] = 0;
  1292. flag_Rewrite = 1;
  1293. break;
  1294. case 'i':
  1295. if (argv[i][2])
  1296. {
  1297. char *endptr;
  1298. repack_IDAT_size = strtol(argv[i]+2, &endptr, 10);
  1299. if (*endptr || repack_IDAT_size < 1024)
  1300. {
  1301. printf ("pngdefry : invalid repack size '%s'\n", argv[i]+2);
  1302. return -1;
  1303. }
  1304. /* yuck. it does circumvent problems down later, thouh, and an extra flag to set/check :( */
  1305. argv[i][2] = 0;
  1306. break;
  1307. } else
  1308. {
  1309. if (i < argc-1)
  1310. {
  1311. char *endptr;
  1312. i++;
  1313. repack_IDAT_size = strtol(argv[i], &endptr, 10);
  1314. if (*endptr || repack_IDAT_size < 1024)
  1315. {
  1316. printf ("pngdefry : invalid repack size '%s'\n", argv[i]);
  1317. return -1;
  1318. }
  1319. /* yuck. it does circumvent problems down later, thouh, and an extra flag to set/check :( */
  1320. argv[i][2] = 0;
  1321. } else
  1322. {
  1323. printf ("pngdefry : -i is missing repack size\n");
  1324. return -1;
  1325. }
  1326. }
  1327. break;
  1328. default:
  1329. printf ("pngdefry : unknown option '%s'\n", argv[i]);
  1330. return -1;
  1331. }
  1332. /* was the last option seen '-' ? */
  1333. if (nomoreoptions)
  1334. {
  1335. i++;
  1336. break;
  1337. }
  1338. if (argv[i][2] != 0)
  1339. {
  1340. printf ("pngdefry : unknown option '%s'\n", argv[i]);
  1341. return -1;
  1342. }
  1343. }
  1344. if (i == argc)
  1345. {
  1346. printf ("pngdefry : no file name(s) provided\n");
  1347. return -1;
  1348. }
  1349. /* if (flag_Rewrite == 0)
  1350. printf ("pngdefry : no -s(suffix) or -o(path) provided, files will be processed but not written\n"); */
  1351. for (; i<argc; i++)
  1352. {
  1353. seenFiles++;
  1354. if (process (argv[i]))
  1355. processedFiles++;
  1356. }
  1357. if (flag_Rewrite)
  1358. printf ("pngdefry : seen %d file(s), wrote %d file(s)\n", seenFiles, processedFiles);
  1359. else
  1360. printf ("pngdefry : seen %d file(s), processed %d file(s)\n", seenFiles, processedFiles);
  1361. return 0;
  1362. }
  1363. /*
  1364. This is free and unencumbered software released into the public domain.
  1365. Anyone is free to copy, modify, publish, use, compile, sell, or
  1366. distribute this software, either in source code form or as a compiled
  1367. binary, for any purpose, commercial or non-commercial, and by any
  1368. means.
  1369. In jurisdictions that recognize copyright laws, the author or authors
  1370. of this software dedicate any and all copyright interest in the
  1371. software to the public domain. We make this dedication for the benefit
  1372. of the public at large and to the detriment of our heirs and
  1373. successors. We intend this dedication to be an overt act of
  1374. relinquishment in perpetuity of all present and future rights to this
  1375. software under copyright law.
  1376. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  1377. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  1378. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  1379. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  1380. OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  1381. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  1382. OTHER DEALINGS IN THE SOFTWARE.
  1383. For more information, please refer to <http://unlicense.org/>
  1384. */