tool to fixes some issues in baseline tiffs (with extensions), see http://andreas-romeyke.de
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.
 
 
 

217 lines
8.1 KiB

  1. /* fixes broken TIFF Files
  2. *
  3. * fixes invalid DateTime-field in Baseline-TIFFs,
  4. * based on http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
  5. *
  6. * author: Andreas Romeyke, 2013
  7. * licensed under conditions of libtiff
  8. */
  9. #include "fixit_tiff.h"
  10. #include "check_baseline.h"
  11. #include "check_datetime.h"
  12. /** help function */
  13. void help () {
  14. printf ("fixit_tiff, a tool to fix common problems in extended baseline TIFF files\n");
  15. printf ("uses libtiff version %s\n", TIFFGetVersion());
  16. printf ("\ncall it with:\n");
  17. printf ("\tfixit_tiff -h\n");
  18. printf ("\tfixit_tiff [-q] -c -i <infile>\n");
  19. printf ("\tfixit_tiff [-q] [-s] -i <infile> [-o <outfile>]\n");
  20. printf ("\tfixit_tiff [-q] [-e|-b|-x <tag>|-p] -i <infile> [-o <outfile>]\n");
  21. printf ("\nwhere <infile> is the possibly broken file\n");
  22. printf ("and <outfile> is the name of the corrected file\n");
  23. printf ("\nOptions in detail:\n");
  24. printf ("\t-c ... checks file only (rudimentary, lists baseline tags, dumps libtiff errors. For deeper checks, please use 'checkit_tiff'\n");
  25. printf ("\t-s ... inplace file substitution (only -i needed, dangerous, only works with datetime-fixes)\n");
  26. printf ("\t-b ... clean up (eliminates tags to be baseline tiff conform)\n");
  27. printf ("\t-q ... disables describing messages\n");
  28. printf ("\t-t ... try to fix tagorder (dangerous)\n");
  29. printf ("\t-x <tag> ... remove given tag\n");
  30. printf ("\t-p ... try to repair ICC header profile, correct preferred CMM type (autocorrect misspelled entries or erase 'Lino' to zero)\n");
  31. printf ("\t or to fix CMM version (replaces only the version-string)\n");
  32. printf ("\t-e ... try to repair some wrong tagtypes\n");
  33. printf ("\n");
  34. printf ("Hint: 'fixit_tiff -i <infile> -o <outfile>' repairs broken datetimes only\n");
  35. }
  36. /** copy infile to outfile
  37. * @param inf string with infile name
  38. * @param outf string with outfile name
  39. */
  40. void copy_file (const char * inf, const char * outf) {
  41. FILE * in = fopen( inf, "rb");
  42. if (NULL == in) {
  43. fprintf(stderr, "could not open file '%s' for reading\n", inf);
  44. exit (FIXIT_TIFF_READ_PERMISSION_ERROR);
  45. }
  46. FILE * out = fopen(outf, "wb");
  47. if (NULL == out) {
  48. fprintf(stderr, "could not open file '%s' for writing\n", outf);
  49. exit (FIXIT_TIFF_WRITE_PERMISSION_ERROR);
  50. }
  51. /* copy infile to outfile */
  52. char buffer[512];
  53. size_t n;
  54. while ((n = fread(buffer, sizeof(char), sizeof(buffer), in)) > 0)
  55. {
  56. if (n != fwrite(buffer, sizeof(char), n, out)) {
  57. fprintf(stderr, "failure writing to file '%s'\n", outf);
  58. exit (FIXIT_TIFF_WRITE_ERROR);
  59. }
  60. }
  61. fclose(in);
  62. fclose(out);
  63. }
  64. /** main */
  65. int main (int argc, char * argv[]) {
  66. const char *infilename = NULL;
  67. const char *outfilename= NULL;
  68. //opterr = 0;
  69. int c;
  70. int flag_substitute_only=UNFLAGGED;
  71. int flag_baseline_cleanup=UNFLAGGED;
  72. int flag_tagorder=UNFLAGGED;
  73. int flag_clean_icc=UNFLAGGED;
  74. int flag_check_only=UNFLAGGED;
  75. int flag_fix_tagtypes=UNFLAGGED;
  76. int clean_tag=UNFLAGGED;
  77. flag_be_verbose = FLAGGED;
  78. while ((c = getopt (argc, argv, "s::cbqtp::hi:o:x:e")) != -1) {
  79. switch (c)
  80. {
  81. case 'h': /* help */
  82. help();
  83. exit (0);
  84. case 's': /* inplace file substitution (no new output file is written) */
  85. flag_substitute_only = FLAGGED;
  86. break;
  87. case 'b': /* clean up to be baseline tiff conform */
  88. flag_baseline_cleanup=FLAGGED;
  89. break;
  90. case 't': /* try to fix tagorder */
  91. flag_tagorder=FLAGGED;
  92. break;
  93. case 'c': /* reports only if repair needed */
  94. flag_check_only = FLAGGED;
  95. break;
  96. case 'q': /* disables describing messages */
  97. flag_be_verbose = UNFLAGGED;
  98. break;
  99. case 'i': /* expects infile */
  100. infilename=optarg;
  101. break;
  102. case 'o': /* expects outfile */
  103. outfilename=optarg;
  104. break;
  105. case 'x': /* expects tagnumber */
  106. clean_tag =atoi(optarg);
  107. break;
  108. case 'p': /* try to clean ICC header */
  109. flag_clean_icc = FLAGGED;
  110. break;
  111. case 'e': /* try to fix tag type */
  112. flag_fix_tagtypes = FLAGGED;
  113. break;
  114. case '?': /* something goes wrong */
  115. if (optopt == 'i' || optopt == 'o' || optopt == 'x')
  116. fprintf (stderr, "Option -%c requires an argument.\n", optopt);
  117. else if (isprint (optopt))
  118. fprintf (stderr, "Unknown option `-%c'.\n", optopt);
  119. else if (0 !=optopt) {
  120. fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
  121. return (-1);
  122. }
  123. break;
  124. default:
  125. abort();
  126. }
  127. }
  128. /* added additional checks */
  129. /* TODO: add check that no inline and no check if cleantag */
  130. if ((UNFLAGGED != clean_tag) && ((clean_tag < 254) || (clean_tag > 65535))) {
  131. fprintf(stderr, "The option '-x' expects a value in range 254..65535, see '%s -h' for details\n", argv[0]);
  132. exit(FIXIT_TIFF_CMDLINE_ARGUMENTS_ERROR);
  133. }
  134. if ((FLAGGED == flag_substitute_only) && (FLAGGED == flag_check_only)) {
  135. fprintf (stderr, "The options '-s' and '-c' could not be used in combination, see '%s -h' for details\n", argv[0]);
  136. exit (FIXIT_TIFF_CMDLINE_ARGUMENTS_ERROR);
  137. }
  138. if (NULL == infilename) {
  139. fprintf (stderr, "You need to specify infile with '-i filename', see '%s -h' for details\n", argv[0]);
  140. exit (FIXIT_TIFF_MISSED_INFILE);
  141. }
  142. if ((FLAGGED!=flag_substitute_only) && (FLAGGED!=flag_check_only)) {
  143. if (NULL == outfilename) {
  144. fprintf (stderr, "You need to specify outfile with '-o outfilename', see '%s -h' for details\n", argv[0]);
  145. exit (FIXIT_TIFF_MISSED_OUTFILE);
  146. }
  147. }
  148. if (FLAGGED == flag_be_verbose) printf ("infile='%s', outfile='%s'\n", infilename, outfilename);
  149. /* check only if file is valid */
  150. if (FLAGGED == flag_check_only) {
  151. /*
  152. exit (
  153. check_required(infilename));
  154. */
  155. exit (
  156. check_required(infilename) ||
  157. check_baseline(infilename) ||
  158. check_datetime(infilename)
  159. );
  160. }
  161. /* try to fix tag order */
  162. if (FLAGGED == flag_tagorder) {
  163. copy_file (infilename, outfilename);
  164. if (FLAGGED == flag_be_verbose) printf ("tagorder cleanup infile='%s', outfile='%s'\n", infilename, outfilename);
  165. cleanup_tagorder(outfilename);
  166. exit (FIXIT_TIFF_IS_CORRECTED);
  167. }
  168. /* try to fix ICC header */
  169. if (FLAGGED == flag_clean_icc) {
  170. copy_file (infilename, outfilename);
  171. if (FLAGGED == flag_be_verbose) printf ("ICC header cleanup infile='%s', outfile='%s'\n", infilename, outfilename);
  172. cleanup_icc_header(outfilename);
  173. exit (FIXIT_TIFF_IS_CORRECTED);
  174. }
  175. /* try to fix tag types */
  176. if (FLAGGED == flag_fix_tagtypes) {
  177. copy_file (infilename, outfilename);
  178. if (FLAGGED == flag_be_verbose) printf ("fix tagtypes cleanup infile='%s', outfile='%s'\n", infilename, outfilename);
  179. cleanup_tagtype(outfilename, 34665); // EXIFIFDOFFSET
  180. cleanup_tagtype(outfilename, 33723); // RICHTIFFIPTC
  181. exit (FIXIT_TIFF_IS_CORRECTED);
  182. }
  183. if (UNFLAGGED != clean_tag) { /* explicite correction via source target, clean given tag */
  184. copy_file (infilename, outfilename);
  185. if (FLAGGED == flag_be_verbose) printf ("tag cleanup infile='%s', outfile='%s'\n", infilename, outfilename);
  186. cleanup_tag(outfilename, clean_tag);
  187. exit (FIXIT_TIFF_IS_CORRECTED);
  188. }
  189. /* inplace correction */
  190. if (FLAGGED == flag_substitute_only) { /* inplace correction */
  191. cleanup_datetime(infilename);
  192. if (FLAGGED == flag_baseline_cleanup) { /* baseline tiff cleanup */
  193. cleanup_baseline(infilename);
  194. }
  195. } else { /* explicite correction via source target */
  196. copy_file (infilename, outfilename);
  197. cleanup_datetime(outfilename);
  198. if (FLAGGED == flag_baseline_cleanup) { /* baseline tiff cleanup */
  199. if (FLAGGED == flag_be_verbose) printf ("baseline cleanup infile='%s', outfile='%s'\n", infilename, outfilename);
  200. cleanup_baseline(outfilename);
  201. }
  202. }
  203. exit (FIXIT_TIFF_IS_CORRECTED);
  204. }