"checkit_tiff" is an incredibly fast conformance checker for baseline TIFFs (with various 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.
 
 
 
 
 
 

223 lines
11 KiB

  1. /* checks ICC Profile, using Spec http://www.color.org/specification/ICC1v43_2010-12.pdf */
  2. #include "validate_icc.h"
  3. /*
  4. #define USE_WARNING
  5. #ifdef USE_WARNING
  6. #define FAIL(...) {fprintf(stderr, __VA_ARGS__); return 1;};
  7. #define INFO(...) fprintf(stderr,__VA_ARGS__);
  8. #else
  9. #define FAIL(...) {return 1;};
  10. #define INFO(...) ;
  11. #endif
  12. */
  13. #define FAIL(RETCODE, ...) {snprintf(errmessage, errsize, __VA_ARGS__); return RETCODE;};
  14. #define INFO(...) ;
  15. // TODO: errormessage pointer und maxsize übergeben
  16. icc_returncode_t parse_icc_header_v240_v430(unsigned long iccsize, char * iccdata, unsigned long errsize, char * errmessage) {
  17. assert(iccdata != NULL);
  18. assert(errmessage != NULL);
  19. assert(errsize > 0);
  20. if (iccsize < 128) FAIL(icc_error_header_generic, "iccsize=%lu", iccsize);
  21. unsigned long profilesize = (
  22. ((iccdata[0] & 0x00ff) <<24) |
  23. ((iccdata[1] & 0x00ff) <<16) |
  24. ((iccdata[2] & 0x00ff) <<8) |
  25. (iccdata[3] & 0x00ff)
  26. ) & 0xffffffff;
  27. INFO("ICC: profilesize=%li %0x\n", profilesize, profilesize);
  28. if (profilesize != iccsize) FAIL(icc_error_committed_size_differs, "committed ICC size (%li / 0x%04lx) differs from encoded profilesize (%li / 0x%04lx)", iccsize, iccsize, profilesize, profilesize);
  29. /* -- */
  30. char preferredcmmtype[5]=" "; memcpy(preferredcmmtype, &iccdata[4],4);
  31. INFO("ICC: preferredcmmtype='%s'\n", preferredcmmtype);
  32. /* TODO: check if this is really correct, because found some TIFFs with
  33. * value 'Lino', handle with care! */
  34. if ( /* see document http://www.color.org/registry/signature/TagRegistry-2016-05.pdf */
  35. ('\0' != preferredcmmtype[0]) &&
  36. (0 != strncmp("ADBE", preferredcmmtype, 4)) &&
  37. (0 != strncmp("ACMS", preferredcmmtype, 4)) &&
  38. (0 != strncmp("appl", preferredcmmtype, 4)) &&
  39. (0 != strncmp("CCMS", preferredcmmtype, 4)) &&
  40. (0 != strncmp("UCCM", preferredcmmtype, 4)) &&
  41. (0 != strncmp("UCMS", preferredcmmtype, 4)) &&
  42. (0 != strncmp("EFI ", preferredcmmtype, 4)) &&
  43. (0 != strncmp("FF ", preferredcmmtype, 4)) &&
  44. (0 != strncmp("EXAC", preferredcmmtype, 4)) &&
  45. (0 != strncmp("HCMM", preferredcmmtype, 4)) &&
  46. (0 != strncmp("argl", preferredcmmtype, 4)) &&
  47. (0 != strncmp("LgoS", preferredcmmtype, 4)) &&
  48. (0 != strncmp("HDM ", preferredcmmtype, 4)) &&
  49. (0 != strncmp("lcms", preferredcmmtype, 4)) &&
  50. (0 != strncmp("KCMS", preferredcmmtype, 4)) &&
  51. (0 != strncmp("MCML", preferredcmmtype, 4)) &&
  52. (0 != strncmp("WCS ", preferredcmmtype, 4)) &&
  53. (0 != strncmp("SIGN", preferredcmmtype, 4)) &&
  54. (0 != strncmp("RGMS", preferredcmmtype, 4)) &&
  55. (0 != strncmp("SICC", preferredcmmtype, 4)) &&
  56. (0 != strncmp("TCMM", preferredcmmtype, 4)) &&
  57. (0 != strncmp("32BT", preferredcmmtype, 4)) &&
  58. (0 != strncmp("WTG ", preferredcmmtype, 4)) &&
  59. #ifdef ALLOW_CMMTYPE_LINO
  60. (0 != strncmp("LINO", preferredcmmtype, 4)) &&
  61. #endif
  62. (0 != strncmp("zc00", preferredcmmtype, 4))
  63. ) FAIL(icc_error_preferredcmmtype, "preferred cmmtype ('%s') should be empty or (possibly, because ICC validation is alpha code) one of following strings: 'ADBE' 'ACMS' 'appl' 'CCMS' 'UCCM' 'UCMS' 'EFI ' 'FF ' 'EXAC' 'HCMM' 'argl' 'LgoS' 'HDM ' 'lcms' 'KCMS' 'MCML' 'WCS ' 'SIGN' 'RGMS' 'SICC' 'TCMM' '32BT' 'WTG ' 'zc00'", preferredcmmtype);
  64. /* -- */
  65. char profileversion[6]=" "; snprintf(profileversion, 6, "%i.%i.%i", (iccdata[8]) & 0x000f, ((iccdata[9] & 0x00f0) >>4), (iccdata[9] & 0x000f));
  66. INFO("ICC: profileversion='%s'\n", profileversion);
  67. // TODO: 2.4.0 or 4.3.0, others not allowed?
  68. /* -- */
  69. char profileclass[5]=" "; memcpy(profileclass, &iccdata[12],4);
  70. INFO("ICC: profileclass='%s'\n", profileclass);
  71. if ( /* see page 13, table 11 of http://www.color.org/ICC_Minor_Revision_for_Web.pdf */
  72. (0 != strncmp("scnr", profileclass, 4)) &&
  73. (0 != strncmp("mntr", profileclass, 4)) &&
  74. (0 != strncmp("prtr", profileclass, 4)) &&
  75. (0 != strncmp("link", profileclass, 4)) &&
  76. (0 != strncmp("spac", profileclass, 4)) &&
  77. (0 != strncmp("abst", profileclass, 4)) &&
  78. (0 != strncmp("nmcl", profileclass, 4))
  79. ) FAIL(icc_error_profileclass, "profile class ('%s'), should be one of following strings for device classes: 'scnr', 'mntr', 'prtr' or for profile classes: 'link', 'spac', 'abst', 'nmcl'", profileclass);
  80. /* -- */
  81. char colorspacedata[5]=" "; memcpy(colorspacedata, &iccdata[16],4);
  82. INFO("ICC: colorspacedata='%s'\n", colorspacedata);
  83. if ( /* see page 14, table 13 of http://www.color.org/ICC_Minor_Revision_for_Web.pdf */
  84. (0 != strncmp("XYZ ", colorspacedata, 4)) &&
  85. (0 != strncmp("Lab ", colorspacedata, 4)) &&
  86. (0 != strncmp("Luv ", colorspacedata, 4)) &&
  87. (0 != strncmp("YCbr", colorspacedata, 4)) &&
  88. (0 != strncmp("Yvx ", colorspacedata, 4)) &&
  89. (0 != strncmp("RGB ", colorspacedata, 4)) &&
  90. (0 != strncmp("GRAY", colorspacedata, 4)) &&
  91. (0 != strncmp("HSV ", colorspacedata, 4)) &&
  92. (0 != strncmp("HLS ", colorspacedata, 4)) &&
  93. (0 != strncmp("CMYK", colorspacedata, 4)) &&
  94. (0 != strncmp("CMY ", colorspacedata, 4)) &&
  95. (0 != strncmp("2CLR", colorspacedata, 4)) &&
  96. (0 != strncmp("3CLR", colorspacedata, 4)) &&
  97. (0 != strncmp("4CLR", colorspacedata, 4)) &&
  98. (0 != strncmp("5CLR", colorspacedata, 4)) &&
  99. (0 != strncmp("6CLR", colorspacedata, 4)) &&
  100. (0 != strncmp("7CLR", colorspacedata, 4)) &&
  101. (0 != strncmp("8CLR", colorspacedata, 4)) &&
  102. (0 != strncmp("9CLR", colorspacedata, 4)) &&
  103. (0 != strncmp("ACLR", colorspacedata, 4)) &&
  104. (0 != strncmp("BCLR", colorspacedata, 4)) &&
  105. (0 != strncmp("CCLR", colorspacedata, 4)) &&
  106. (0 != strncmp("DCLR", colorspacedata, 4)) &&
  107. (0 != strncmp("ECLR", colorspacedata, 4)) &&
  108. (0 != strncmp("FCLR", colorspacedata, 4))
  109. ) FAIL(icc_error_colorspacedata, "colorspace data ('%s'), should be one of following strings: 'XYZ ' 'Lab ' 'Luv ' 'YCbr' 'Yvx ' 'RGB ' 'GRAY' 'HSV ' 'HLS ' 'CMYK' 'CMY ' '2CLR' '3CLR' '4CLR' '5CLR' '6CLR' '7CLR' '8CLR' '9CLR' 'ACLR' 'BCLR' 'CCLR' 'DCLR' 'ECLR' 'FCLR'", colorspacedata);
  110. /* -- */
  111. char connectionspacedata[5]=" "; memcpy(connectionspacedata, &iccdata[20],4);
  112. INFO("ICC: connectionspacedata(PCS)='%s'\n", connectionspacedata);
  113. if ( /* see page 15, table 14 of http://www.color.org/ICC_Minor_Revision_for_Web.pdf */
  114. (0 != strncmp("XYZ ", connectionspacedata, 4)) &&
  115. (0 != strncmp("Lab ", connectionspacedata, 4))
  116. ) FAIL(icc_error_connectionspacedata, "connection space data ('%s') should be one of following strings: 'XYZ ' 'Lab '", connectionspacedata);
  117. /* -- */
  118. // datetime 24-35
  119. char datetime[20]; snprintf(datetime, 20, "%.4d:%.2d:%.2d %.2d:%.2d:%.2d",
  120. ((iccdata[24] & 0x00ff)<<8 | (iccdata[25] & 0x00ff)), // yyyy
  121. ((iccdata[26] & 0x00ff)<<8 | (iccdata[27] & 0x00ff)), // MM
  122. ((iccdata[28] & 0x00ff)<<8 | (iccdata[29] & 0x00ff)), // DD
  123. ((iccdata[30] & 0x00ff)<<8 | (iccdata[31] & 0x00ff)), // hh
  124. ((iccdata[32] & 0x00ff)<<8 | (iccdata[33] & 0x00ff)), // mm
  125. ((iccdata[34] & 0x00ff)<<8 | (iccdata[35] & 0x00ff)) // ss
  126. );
  127. INFO("ICC: datetime='%s'\n", datetime);
  128. /* -- */
  129. char profilefilesignature[5]=" "; memcpy(profilefilesignature, &iccdata[36],4);
  130. INFO("ICC: profilefilesignature='%s'\n", profilefilesignature);
  131. /* -- */
  132. char primaryplattformsignature[5]=" "; memcpy(primaryplattformsignature, &iccdata[40],4);
  133. INFO("ICC: primaryplattformsignature='%s'\n", primaryplattformsignature);
  134. if ( /* see page 15, table 15 of http://www.color.org/ICC_Minor_Revision_for_Web.pdf */
  135. ('\0' != primaryplattformsignature[0]) &&
  136. (0 != strncmp("APPL", primaryplattformsignature, 4)) &&
  137. (0 != strncmp("MSFT", primaryplattformsignature, 4)) &&
  138. (0 != strncmp("SGI ", primaryplattformsignature, 4)) &&
  139. (0 != strncmp("SUNW", primaryplattformsignature, 4)) &&
  140. (0 != strncmp("TGNT", primaryplattformsignature, 4))
  141. ) FAIL(icc_error_primaryplatformsignature, "primary plattform signature ('%s') should be empty or one of following strings: 'APPL', 'MSFT', 'SGI ', 'SUNW', 'TGNT'", primaryplattformsignature);
  142. /* -- */
  143. // Profile Flags 44-47
  144. /* -- */
  145. char devicemanufacturer[5]=" "; memcpy(devicemanufacturer, &iccdata[48],4);
  146. INFO("ICC: devicemanufacturer='%s'\n", devicemanufacturer);
  147. /* -- */
  148. char devicemodel[5]=" "; memcpy(devicemodel, &iccdata[52],4);
  149. INFO("ICC: devicemodel='%s'\n", devicemodel);
  150. /* -- */
  151. // device attributes 56-63
  152. /* -- */
  153. // rendering intent field 64-67
  154. /* -- */
  155. return icc_is_valid;
  156. }
  157. /* checks a ICC header, see chapter 7 of http://www.color.org/specification/ICC1v43_2010-12.pdf */
  158. icc_returncode_t parse_icc_v430(unsigned long iccsize, char* iccdata, unsigned long errsize, char * errmessage) {
  159. assert(iccdata != NULL);
  160. assert(errmessage != NULL);
  161. assert(errsize > 0);
  162. if (iccsize < 128) FAIL (icc_error_header_1v43_2010, "Invalid ICC profile 1v43_2010, see http://www.color.org/specification/ICC1v43_2010-12.pdf for details");
  163. icc_returncode_t ret_header = parse_icc_header_v240_v430( iccsize, iccdata, errsize, errmessage);
  164. if (icc_is_valid != ret_header) return ret_header;
  165. else {
  166. // PCS illuminant field 68-79
  167. /* -- */
  168. // Profile creator field 80-83
  169. /* -- */
  170. // Profile ID field 84-99
  171. /* -- */
  172. // Reserved field bytes 100-127
  173. };
  174. return icc_is_valid;
  175. }
  176. /* checks a ICC header, see chapter 6 of http://www.color.org/ICC_Minor_Revision_for_Web.pdf */
  177. icc_returncode_t parse_icc_v240(unsigned long iccsize, char* iccdata, unsigned long errsize, char * errmessage) {
  178. assert(iccdata != NULL);
  179. assert(errmessage != NULL);
  180. assert(errsize > 0);
  181. if (iccsize < 128) FAIL (icc_error_header_v240_v430, "Invalid ICC profile ICC.1:2001-04, see http://www.color.org/ICC_Minor_Revision_for_Web.pdf for details");
  182. int ret_header = parse_icc_header_v240_v430( iccsize, iccdata, errsize, errmessage);
  183. if (icc_is_valid != ret_header) return ret_header;
  184. else {
  185. // PCS xyz illuminant 68-79
  186. /* -- */
  187. // Profile creator signature 80-83
  188. /* -- */
  189. // Reserved field bytes 84-127
  190. };
  191. return icc_is_valid;
  192. }
  193. /* returns 0 if valid, !0 if errorneous */
  194. icc_returncode_t parse_icc(unsigned long iccsize, char* iccdata, unsigned long errsize, char * errmessage) {
  195. assert(iccdata != NULL);
  196. assert(errmessage != NULL);
  197. assert(errsize > 0);
  198. if (iccsize < 10) FAIL (icc_error_header_generic, "Invalid ICC profile");
  199. short a = (iccdata[8]) & 0x000f;
  200. short b = ((iccdata[9] & 0x00f0) >>4);
  201. short c = (iccdata[9] & 0x000f);
  202. char profileversion[6]=" "; snprintf(profileversion, 6, "%1i.%1i.%1i", a, b, c);
  203. INFO("ICC: profileversion='%s'\n", profileversion);
  204. if (0==strncmp(profileversion, "4.3.0",5)) return parse_icc_v430(iccsize, iccdata, errsize, errmessage);
  205. else if (0==strncmp(profileversion, "2.4.0",5)) return parse_icc_v240(iccsize,iccdata, errsize, errmessage);
  206. else {
  207. return parse_icc_header_v240_v430(iccsize,iccdata, errsize, errmessage);
  208. }
  209. return icc_should_not_occur;
  210. }
  211. /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 smarttab expandtab :*/