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.
 
 
 

168 lines
6.3 KiB

  1. /* fixes broken TIFF Files
  2. *
  3. * fixes invalid ICC header-field in Baseline-TIFFs,
  4. * based on http://www.awaresystems.be/imaging/tiff/tifftags/baseline.html
  5. *
  6. * author: Andreas Romeyke, 2016
  7. * licensed under conditions of libtiff
  8. */
  9. #include "fixit_tiff.h"
  10. #include "check_icc_header.h"
  11. #include "tiff_helper.h"
  12. /** corrects a ICC profile, fixes CMM type and/or fixes profile version */
  13. char * correct_iccprofile(unsigned long iccsize, char * iccdata) {
  14. int major=iccdata[8];
  15. int minor=(iccdata[9]>>4) & 0x000f;
  16. int bugfix= iccdata[9] & 0x000f;
  17. if (FLAGGED == flag_be_verbose) printf("ICC profile: major=%i minor=%i bugfix=%i (iccdata [8]=%i [9]=%i [10]=%i [11]=%i)\n", major, minor, bugfix, iccdata[8], iccdata[9], iccdata[10], iccdata[11]);
  18. if (/* fixes outdated ICC 2.xx profile versions */
  19. (major == 2) && /* major version */
  20. (minor < 4) ) {
  21. /* found 2.1/2.2/2.3 */
  22. iccdata[9] = 4 << 4;
  23. iccdata[10] = 0;
  24. iccdata[11] = 0;
  25. printf("Found outdated 2.xx profile version, try to correct it\n");
  26. } else if ( /* fixes outdated ICC 4.xx profile versions */
  27. (major == 4) && /* major version */
  28. (minor < 3) ) {
  29. /* found 4.0/4.1/4.2 */
  30. iccdata[9] = 3 << 4;
  31. iccdata[10] = 0;
  32. iccdata[11] = 0;
  33. printf("Found outdated 4.xx profile version, try to correct it\n");
  34. }
  35. /* fixes only wrong 'APPL ' -> 'appl ' in preferredcmmtype */
  36. char preferredcmmtype[5]=" "; memcpy(preferredcmmtype, &iccdata[4],4);
  37. if (0 == strncmp("APPL", preferredcmmtype, 4)) {
  38. printf("Found wrong 'APPL' in preferred cmmtype, try to correct it\n");
  39. char * newiccdata = malloc( sizeof( char ) * iccsize);
  40. if (NULL == newiccdata) {
  41. perror("Could not allocate memory for new iccdata");
  42. exit(FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  43. }
  44. memcpy (newiccdata, iccdata, iccsize);
  45. memcpy(&newiccdata[4], "appl", 4);
  46. return newiccdata;
  47. } else if (0 == strncmp("Lino", preferredcmmtype, 4)) {
  48. /* fixes only unregistered entry 'Lino' -> 0x00000000*/
  49. printf("Found unregistered entry 'Lino' in preferred cmmtype, try to correct it\n");
  50. char * newiccdata = malloc( sizeof( char ) * iccsize);
  51. if (NULL == newiccdata) {
  52. perror("Could not allocate memory for new iccdata");
  53. exit(FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  54. }
  55. memcpy (newiccdata, iccdata, iccsize);
  56. memset(&newiccdata[4], 0x0, 4);
  57. return newiccdata;
  58. }
  59. return iccdata;
  60. }
  61. /** loads a tiff, fix it if needed, stores tiff
  62. * @param filename filename which should be processed, repaired
  63. */
  64. int cleanup_icc_header(const char * filename ) {
  65. if (FIXIT_TIFF_IS_VALID == check_icc_header(filename)) return FIXIT_TIFF_IS_VALID;
  66. else {
  67. /* load file */
  68. TIFF* tif = TIFFOpen(filename, "r+");
  69. if (NULL == tif) {
  70. fprintf( stderr, "file '%s' could not be opened\n", filename);
  71. exit (FIXIT_TIFF_READ_PERMISSION_ERROR);
  72. };
  73. if (FLAGGED == flag_be_verbose) printf("Before correction\n-----------------\n");
  74. if (FLAGGED == flag_be_verbose) TIFFPrintDirectory(tif, stdout, TIFFPRINT_NONE);
  75. /* find ICC-tag and fix it */
  76. char *iccprofile=NULL;
  77. uint32 tag_counter=TIFFGetRawTagListCount(tif);
  78. uint32 tagidx;
  79. for (tagidx=0; tagidx < tag_counter; tagidx++) {
  80. uint32 tag = TIFFGetRawTagListEntry( tif, tagidx );
  81. if (tag == TIFFTAG_ICCPROFILE) {
  82. /* via TIFFGetRawTagListEntry we have the tag
  83. * read, the next 2 bytes are the type, next 2 count, last 4 value/offset */
  84. int fd = TIFFFileno( tif);
  85. uint16 tagtype=0;
  86. if ( read( fd, &tagtype, 2) != 2 ) {
  87. perror ("TIFF Header read error tagtype");
  88. exit( FIXIT_TIFF_READ_ERROR );
  89. }
  90. if (TIFFIsByteSwapped(tif))
  91. TIFFSwabShort(&tagtype);
  92. assert(TIFF_UNDEFINED == tagtype);
  93. uint32 count=0;
  94. if ( read( fd, &count, 4) != 4 ) {
  95. perror ("TIFF Header read error tagcount");
  96. exit( FIXIT_TIFF_READ_ERROR );
  97. }
  98. if (TIFFIsByteSwapped(tif))
  99. TIFFSwabLong(&count);
  100. uint32 offset=0;
  101. if ( read( fd, &offset, 4) != 4 ) {
  102. perror ("TIFF Header read error offset");
  103. exit( FIXIT_TIFF_READ_ERROR );
  104. }
  105. if (TIFFIsByteSwapped(tif))
  106. TIFFSwabLong(&offset);
  107. if (FLAGGED == flag_be_verbose) printf("tag=%u tagtype=%i c=%u offset=%u\n", tag, tagtype, count, offset);
  108. iccprofile = malloc( sizeof( char ) * count);
  109. if (NULL == iccprofile) {
  110. perror("Could not allocate memory for new iccdata");
  111. exit(FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  112. }
  113. /* rewind to offset */
  114. if (lseek(fd, offset, SEEK_SET) != offset) {
  115. perror("TIFF ICC profile seek error to offset");
  116. exit( FIXIT_TIFF_READ_ERROR );
  117. }
  118. if (read(fd, iccprofile, count) != count) {
  119. perror ("TIFF ICC profile read error offset");
  120. exit( FIXIT_TIFF_READ_ERROR );
  121. }
  122. /* repair */
  123. char * new_iccprofile = correct_iccprofile(count, iccprofile );
  124. if (NULL == new_iccprofile) {
  125. perror("Could not allocate memory for new icc profile");
  126. exit(FIXIT_TIFF_MEMORY_ALLOCATION_ERROR);
  127. }
  128. /* rewind to offset */
  129. if (lseek(fd, offset, SEEK_SET) != offset) {
  130. perror("TIFF ICC profile seek error to offset");
  131. exit( FIXIT_TIFF_READ_ERROR );
  132. }
  133. /* write data back, only if no flag_check_only is set */
  134. if (write(fd, new_iccprofile, count) != count) {
  135. perror("TIFF ICC Profile write error");
  136. exit(FIXIT_TIFF_WRITE_ERROR);
  137. }
  138. TIFFClose(tif);
  139. if (FLAGGED == flag_be_verbose) {
  140. printf("tag=%u tagtype=%i count=%u offset=%u (0x%04x)\n", tag, tagtype, count, offset, offset);
  141. printf("old_profile=\n");
  142. for (int i=0; i <40; i++) {
  143. printf("0x%02x ", *(iccprofile++));
  144. }
  145. char * p=new_iccprofile;
  146. printf("\nnew_profile=\n");
  147. for (int i=0; i <40; i++) {
  148. printf("0x%02x ", *(p++));
  149. }
  150. printf("\n");
  151. }
  152. free(new_iccprofile);
  153. break;
  154. }
  155. if (FLAGGED == flag_be_verbose) printf("After correction\n-----------------\n");
  156. }
  157. if (FIXIT_TIFF_IS_VALID == check_icc_header (filename)) return FIXIT_TIFF_IS_CORRECTED;
  158. else return FIXIT_TIFF_IS_CHECKED;
  159. }
  160. }