iccfrompng.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. /*- iccfrompng
  2. *
  3. * COPYRIGHT: Written by John Cunningham Bowler, 2011.
  4. * To the extent possible under law, the author has waived all copyright and
  5. * related or neighboring rights to this work. This work is published from:
  6. * United States.
  7. *
  8. * Extract any icc profiles found in the given PNG files. This is a simple
  9. * example of a program that extracts information from the header of a PNG file
  10. * without processing the image. Notice that some header information may occur
  11. * after the image data. Textual data and comments are an example; the approach
  12. * in this file won't work reliably for such data because it only looks for the
  13. * information in the section of the file that preceeds the image data.
  14. *
  15. * Compile and link against libpng and zlib, plus anything else required on the
  16. * system you use.
  17. *
  18. * To use supply a list of PNG files containing iCCP chunks, the chunks will be
  19. * extracted to a similarly named file with the extension replaced by 'icc',
  20. * which will be overwritten without warning.
  21. */
  22. #include <stdlib.h>
  23. #include <setjmp.h>
  24. #include <string.h>
  25. #include <stdio.h>
  26. #include <png.h>
  27. #if defined(PNG_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) && \
  28. defined (PNG_iCCP_SUPPORTED)
  29. static int verbose = 1;
  30. static png_byte no_profile[] = "no profile";
  31. static png_bytep
  32. extract(FILE *fp, png_uint_32 *proflen)
  33. {
  34. png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,0,0,0);
  35. png_infop info_ptr = NULL;
  36. png_bytep result = NULL;
  37. /* Initialize for error or no profile: */
  38. *proflen = 0;
  39. if (png_ptr == NULL)
  40. {
  41. fprintf(stderr, "iccfrompng: version library mismatch?\n");
  42. return 0;
  43. }
  44. if (setjmp(png_jmpbuf(png_ptr)))
  45. {
  46. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  47. return 0;
  48. }
  49. png_init_io(png_ptr, fp);
  50. info_ptr = png_create_info_struct(png_ptr);
  51. if (info_ptr == NULL)
  52. png_error(png_ptr, "OOM allocating info structure");
  53. png_read_info(png_ptr, info_ptr);
  54. {
  55. png_charp name;
  56. int compression_type;
  57. png_bytep profile;
  58. if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile,
  59. proflen) & PNG_INFO_iCCP)
  60. {
  61. result = malloc(*proflen);
  62. if (result != NULL)
  63. memcpy(result, profile, *proflen);
  64. else
  65. png_error(png_ptr, "OOM allocating profile buffer");
  66. }
  67. else
  68. result = no_profile;
  69. }
  70. png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
  71. return result;
  72. }
  73. static int
  74. extract_one_file(const char *filename)
  75. {
  76. int result = 0;
  77. FILE *fp = fopen(filename, "rb");
  78. if (fp != NULL)
  79. {
  80. png_uint_32 proflen = 0;
  81. png_bytep profile = extract(fp, &proflen);
  82. if (profile != NULL && profile != no_profile)
  83. {
  84. size_t len;
  85. char *output;
  86. {
  87. const char *ep = strrchr(filename, '.');
  88. if (ep != NULL)
  89. len = ep-filename;
  90. else
  91. len = strlen(filename);
  92. }
  93. output = malloc(len + 5);
  94. if (output != NULL)
  95. {
  96. FILE *of;
  97. memcpy(output, filename, len);
  98. strcpy(output+len, ".icc");
  99. of = fopen(output, "wb");
  100. if (of != NULL)
  101. {
  102. if (fwrite(profile, proflen, 1, of) == 1 &&
  103. fflush(of) == 0 &&
  104. fclose(of) == 0)
  105. {
  106. if (verbose)
  107. printf("%s -> %s\n", filename, output);
  108. /* Success return */
  109. result = 1;
  110. }
  111. else
  112. {
  113. fprintf(stderr, "%s: error writing profile\n", output);
  114. if (remove(output))
  115. fprintf(stderr, "%s: could not remove file\n", output);
  116. }
  117. }
  118. else
  119. fprintf(stderr, "%s: failed to open output file\n", output);
  120. free(output);
  121. }
  122. else
  123. fprintf(stderr, "%s: OOM allocating string!\n", filename);
  124. free(profile);
  125. }
  126. else if (verbose && profile == no_profile)
  127. printf("%s has no profile\n", filename);
  128. }
  129. else
  130. fprintf(stderr, "%s: could not open file\n", filename);
  131. return result;
  132. }
  133. int
  134. main(int argc, char **argv)
  135. {
  136. int i;
  137. int extracted = 0;
  138. for (i=1; i<argc; ++i)
  139. {
  140. if (strcmp(argv[i], "-q") == 0)
  141. verbose = 0;
  142. else if (extract_one_file(argv[i]))
  143. extracted = 1;
  144. }
  145. /* Exit code is true if any extract succeeds */
  146. return extracted == 0;
  147. }
  148. #endif /* READ && STDIO && iCCP */