Hoyt's FORK of DemoIccMAX 2.1.17.hoyt
Documentation for Hoyt's FORK of DemoIccMAX
Loading...
Searching...
No Matches
iccDumpProfile.cpp File Reference
#include <stdio.h>
#include <cstring>
#include "IccProfile.h"
#include "IccTag.h"
#include "IccUtil.h"
#include "IccProfLibVer.h"
+ Include dependency graph for iccDumpProfile.cpp:

Go to the source code of this file.

Macros

#define MEMORY_LEAK_CHECK
 

Functions

void DumpTag (CIccProfile *pIcc, icTagSignature sig, int nVerboseness)
 
int main (int argc, char *argv[])
 

Macro Definition Documentation

◆ MEMORY_LEAK_CHECK

#define MEMORY_LEAK_CHECK

Definition at line 81 of file iccDumpProfile.cpp.

Function Documentation

◆ DumpTag()

void DumpTag ( CIccProfile * pIcc,
icTagSignature sig,
int nVerboseness )

Definition at line 90 of file iccDumpProfile.cpp.

91{
92 CIccTag *pTag = pIcc->FindTag(sig);
93 char buf[64];
94 CIccInfo Fmt;
95
96 std::string contents;
97
98 if (pTag) {
99 printf("\nContents of %s tag (%s)\n", Fmt.GetTagSigName(sig), icGetSig(buf, sig));
100 printf("Type: ");
101 if (pTag->IsArrayType()) {
102 printf("Array of ");
103 }
104 printf("%s (%s)\n", Fmt.GetTagTypeSigName(pTag->GetType()), icGetSig(buf, pTag->GetType()));
105 pTag->Describe(contents, nVerboseness);
106 fwrite(contents.c_str(), contents.length(), 1, stdout);
107 }
108 else {
109 printf("Tag (%s) not found in profile\n", icGetSig(buf, sig));
110 }
111}
icArraySignature sig
const icChar * icGetSig(icChar *pBuf, icUInt32Number nSig, bool bGetHexVal)
Definition IccUtil.cpp:1028
Type: Class.
Definition IccUtil.h:303
const icChar * GetTagSigName(icTagSignature sig)
Definition IccUtil.cpp:1495
const icChar * GetTagTypeSigName(icTagTypeSignature sig)
Definition IccUtil.cpp:1594
Class: CIccTag.
virtual icTagTypeSignature GetType() const
Function: GetType()
virtual void Describe(std::string &sDescription, int nVerboseness=0)
Function: Describe(sDescription) Each derived tag will implement it's own Describe() function.
virtual bool IsArrayType()

References CIccTag::Describe(), CIccInfo::GetTagSigName(), CIccInfo::GetTagTypeSigName(), CIccTag::GetType(), icGetSig(), CIccTag::IsArrayType(), and sig.

Referenced by main().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ main()

int main ( int argc,
char * argv[] )

Definition at line 113 of file iccDumpProfile.cpp.

114{
115#if defined(MEMORY_LEAK_CHECK) && defined(_DEBUG)
116#if defined(WIN32) || defined(_WIN32)
117#if 0
118 // Suppress windows dialogs for assertions and errors - send to stderr instead during batch CLI processing
119 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
120 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
121 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
122 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
123#endif
124 int tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
125 tmp = tmp | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF; // | _CRTDBG_CHECK_ALWAYS_DF;
126 _CrtSetDbgFlag(tmp);
127 //_CrtSetBreakAlloc(1163);
128#elif __GLIBC__
129 mcheck(NULL);
130#endif // WIN32
131#endif // MEMORY_LEAK_CHECK && _DEBUG
132
133 int nArg = 1;
134 long int verbosity = 100; // default is maximum verbosity (old behaviour)
135
136 if (argc <= 1) {
137print_usage:
138 printf("Usage: iccDumpProfile {-v} {int} profile {tagId to dump/\"ALL\"}\n");
139 printf("Built with IccProfLib version " ICCPROFLIBVER "\n");
140 printf("\nThe -v option causes profile validation to be performed."
141 "\nThe optional integer parameter specifies verboseness of output (1-100, default=100).\n");
142 printf("iccDumpProfile built with IccProfLib version " ICCPROFLIBVER "\n\n");
143
144 return -1;
145 }
146
147 CIccProfile *pIcc;
148 std::string sReport;
150 bool bDumpValidation = false;
151
152 if (!strncmp(argv[1], "-V", 2) || !strncmp(argv[1], "-v", 2)) {
153 nArg++;
154 if (argc <= nArg)
155 goto print_usage;
156
157 // support case where ICC filename starts with an integer: e.g. "123.icc"
158 char *endptr = nullptr;
159 verbosity = strtol(argv[nArg], &endptr, 10);
160 if ((verbosity != 0L) && (errno != ERANGE) && ((endptr == nullptr) || (*endptr == '\0'))) {
161 // clamp verbosity to 1-100 inclusive
162 if (verbosity < 0)
163 verbosity = 1;
164 else if (verbosity > 100)
165 verbosity = 100;
166 nArg++;
167 if (argc <= nArg)
168 goto print_usage;
169 }
170 else if (argv[nArg] == endptr) {
171 verbosity = 100;
172 }
173
174 pIcc = ValidateIccProfile(argv[nArg], sReport, nStatus);
175 bDumpValidation = true;
176 }
177 else {
178 // support case where ICC filename starts with an integer: e.g. "123.icc"
179 char* endptr = nullptr;
180 verbosity = strtol(argv[nArg], &endptr, 10);
181 if ((verbosity != 0L) && (errno != ERANGE) && ((endptr == nullptr) || (*endptr == '\0'))) {
182 // clamp verbosity to 1-100 inclusive
183 if (verbosity < 0)
184 verbosity = 1;
185 else if (verbosity > 100)
186 verbosity = 100;
187 nArg++;
188 if (argc <= nArg)
189 goto print_usage;
190 }
191
192 pIcc = OpenIccProfile(argv[nArg]);
193 }
194
195 CIccInfo Fmt;
196 icHeader* pHdr = NULL;
197
198 // Precondition: nArg is argument of ICC profile filename
199 printf("Built with IccProfLib version " ICCPROFLIBVER "\n\n");
200 if (!pIcc) {
201 printf("Unable to parse '%s' as ICC profile!\n", argv[nArg]);
202 nStatus = icValidateCriticalError;
203 }
204 else {
205 pHdr = &pIcc->m_Header;
206 char buf[64];
207
208 printf("Profile: '%s'\n", argv[nArg]);
209 if(Fmt.IsProfileIDCalculated(&pHdr->profileID))
210 printf("Profile ID: %s\n", Fmt.GetProfileID(&pHdr->profileID));
211 else
212 printf("Profile ID: Profile ID not calculated.\n");
213 printf("Size: %d (0x%x) bytes\n", pHdr->size, pHdr->size);
214
215 printf("\nHeader\n");
216 printf( "------\n");
217 printf("Attributes: %s\n", Fmt.GetDeviceAttrName(pHdr->attributes));
218 printf("Cmm: %s\n", Fmt.GetCmmSigName((icCmmSignature)(pHdr->cmmId)));
219 printf("Creation Date: %d/%d/%d (M/D/Y) %02u:%02u:%02u\n",
220 pHdr->date.month, pHdr->date.day, pHdr->date.year,
221 pHdr->date.hours, pHdr->date.minutes, pHdr->date.seconds);
222 printf("Creator: %s\n", icGetSig(buf, pHdr->creator));
223 printf("Device Manufacturer:%s\n", icGetSig(buf, pHdr->manufacturer));
224 printf("Data Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->colorSpace));
225 printf("Flags: %s\n", Fmt.GetProfileFlagsName(pHdr->flags));
226 printf("PCS Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->pcs));
227 printf("Platform: %s\n", Fmt.GetPlatformSigName(pHdr->platform));
228 printf("Rendering Intent: %s\n", Fmt.GetRenderingIntentName((icRenderingIntent)(pHdr->renderingIntent)));
229 printf("Profile Class: %s\n", Fmt.GetProfileClassSigName(pHdr->deviceClass));
230 if (pHdr->deviceSubClass)
231 printf("Profile SubClass: %s\n", icGetSig(buf, pHdr->deviceSubClass));
232 else
233 printf("Profile SubClass: Not Defined\n");
234 printf("Version: %s\n", Fmt.GetVersionName(pHdr->version));
235 if (pHdr->version >= icVersionNumberV5 && pHdr->deviceSubClass) {
236 printf("SubClass Version: %s\n", Fmt.GetSubClassVersionName(pHdr->version));
237 }
238 printf("Illuminant: X=%.4lf, Y=%.4lf, Z=%.4lf\n",
239 icFtoD(pHdr->illuminant.X),
240 icFtoD(pHdr->illuminant.Y),
241 icFtoD(pHdr->illuminant.Z));
242 printf("Spectral PCS: %s\n", Fmt.GetSpectralColorSigName(pHdr->spectralPCS));
243 if (pHdr->spectralRange.start || pHdr->spectralRange.end || pHdr->spectralRange.steps) {
244 printf("Spectral PCS Range: start=%.1fnm, end=%.1fnm, steps=%d\n",
247 pHdr->spectralRange.steps);
248 }
249 else {
250 printf("Spectral PCS Range: Not Defined\n");
251 }
252
253 if (pHdr->biSpectralRange.start || pHdr->biSpectralRange.end || pHdr->biSpectralRange.steps) {
254 printf("BiSpectral Range: start=%.1fnm, end=%.1fnm, steps=%d\n",
257 pHdr->biSpectralRange.steps);
258 }
259 else {
260 printf("BiSpectral Range: Not Defined\n");
261 }
262
263 if (pHdr->mcs) {
264 printf("MCS Color Space: %s\n", Fmt.GetColorSpaceSigName((icColorSpaceSignature)pHdr->mcs));
265 }
266 else {
267 printf("MCS Color Space: Not Defined\n");
268 }
269
270 printf("\nProfile Tags\n");
271 printf( "------------\n");
272
273 printf("%28s ID %8s\t%8s\t%8s\n", "Tag", "Offset", "Size", "Pad");
274 printf("%28s ------ %8s\t%8s\t%8s\n", "----", "------", "----", "---");
275
276 int n, closest, pad;
277 TagEntryList::iterator i, j;
278
279 // n is number of Tags in Tag Table
280 for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++) {
281 // Find closest tag after this tag, by scanning all offsets of other tags
282 closest = pHdr->size;
283 for (j = pIcc->m_Tags->begin(); j != pIcc->m_Tags->end(); j++) {
284 if ((i != j) && (j->TagInfo.offset >= i->TagInfo.offset + i->TagInfo.size) && ((int)j->TagInfo.offset <= closest)) {
285 closest = j->TagInfo.offset;
286 }
287 }
288 // Number of actual padding bytes between this tag and closest neighbour (or EOF)
289 // Should be 0-3 if compliant. Negative number if tags overlap!
290 pad = closest - i->TagInfo.offset - i->TagInfo.size;
291
292 printf("%28s %s %8d\t%8d\t%8d\n", Fmt.GetTagSigName(i->TagInfo.sig),
293 icGetSig(buf, i->TagInfo.sig, false), i->TagInfo.offset, i->TagInfo.size, pad);
294 }
295
296 printf("\n");
297
298 // Report all duplicated tags in the tag index
299 // Both ICC.1 and ICC.2 are silent on what should happen for this but report as a warning!!!
300 int m;
301 for (n=0, i = pIcc->m_Tags->begin(); i != pIcc->m_Tags->end(); i++, n++)
302 for (m=0, j = pIcc->m_Tags->begin(); j != pIcc->m_Tags->end(); j++, m++)
303 if ((i != j) && (i->TagInfo.sig == j->TagInfo.sig)) {
304 printf("%28s is duplicated at positions %d and %d!\n", Fmt.GetTagSigName(i->TagInfo.sig), n, m);
305 nStatus = icMaxStatus(nStatus, icValidateWarning);
306 }
307
308
309 // Check additional details if doing detailed validation:
310 // - First tag data offset is immediately after the Tag Table
311 // - Tag data offsets are all 4-byte aligned
312 // - Tag data should be tightly abutted with adjacent tags (or the end of the Tag Table)
313 // (note that tag data can be reused by multiple tags and tags do NOT have to be order)
314 // - Last tag also has to be padded and thus file size is always a multiple of 4. See clause
315 // 7.2.1, bullet (c) of ICC.1:2010 and ICC.2:2019 specs.
316 // - Tag offset + Tag Size should never go beyond EOF
317 // - Multiple tags can reuse data and this is NOT reported as it is perfectly valid and
318 // occurs in real-world ICC profiles
319 // - Tags with overlapping tag data are considered highly suspect (but officially valid)
320 // - 1-3 padding bytes after each tag's data need to be all zero *** NOT DONE - TODO ***
321 if (bDumpValidation) {
322 char str[256];
323 int rndup, smallest_offset = pHdr->size;
324
325 // File size is required to be a multiple of 4 bytes according to clause 7.2.1 bullet (c):
326 // "all tagged element data, including the last, shall be padded by no more than three
327 // following pad bytes to reach a 4 - byte boundary"
328 if ((pHdr->version >= icVersionNumberV4_2) && (pHdr->size % 4 != 0)) {
329 sReport += icMsgValidateNonCompliant;
330 sReport += "File size is not a multiple of 4 bytes (last tag needs padding?).\n";
331 nStatus = icMaxStatus(nStatus, icValidateNonCompliant);
332 }
333
334 for (i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++) {
335 rndup = 4 * ((i->TagInfo.size + 3) / 4); // Round up to a 4-byte aligned size as per ICC spec
336 pad = rndup - i->TagInfo.size; // Optimal smallest number of bytes of padding for this tag (0-3)
337
338 // Is the Tag offset + Tag Size beyond EOF?
339 if (i->TagInfo.offset + i->TagInfo.size > pHdr->size) {
340 sReport += icMsgValidateNonCompliant;
341 sprintf(str, "Tag %s (offset %d, size %d) ends beyond EOF.\n",
342 Fmt.GetTagSigName(i->TagInfo.sig), i->TagInfo.offset, i->TagInfo.size);
343 sReport += str;
344 nStatus = icMaxStatus(nStatus, icValidateNonCompliant);
345 }
346
347 // Is it the first tag data in the file?
348 if ((int)i->TagInfo.offset < smallest_offset) {
349 smallest_offset = (int)i->TagInfo.offset;
350 }
351
352 // Find closest tag after this tag, by scanning all other tag offsets
353 closest = pHdr->size;
354 for (j=pIcc->m_Tags->begin(); j!=pIcc->m_Tags->end(); j++) {
355 if ((i!=j) && (j->TagInfo.offset > i->TagInfo.offset) && ((int)j->TagInfo.offset <= closest)) {
356 closest = j->TagInfo.offset;
357 }
358 }
359
360 // Check if closest tag after this tag is less than offset+size - in which case it overlaps! Ignore last tag.
361 if ((closest < (int)i->TagInfo.offset + (int)i->TagInfo.size) && (closest < (int)pHdr->size)) {
362 sReport += icMsgValidateWarning;
363 sprintf(str, "Tag %s (offset %d, size %d) overlaps with following tag data starting at offset %d.\n",
364 Fmt.GetTagSigName(i->TagInfo.sig), i->TagInfo.offset, i->TagInfo.size, closest);
365 sReport += str;
366 nStatus = icMaxStatus(nStatus, icValidateWarning);
367 }
368
369 // Check for gaps between tag data (accounting for 4-byte alignment)
370 if (closest > (int)i->TagInfo.offset + rndup) {
371 sReport += icMsgValidateWarning;
372 sprintf(str, "Tag %s (size %d) is followed by %d unnecessary additional bytes (from offset %d).\n",
373 Fmt.GetTagSigName(i->TagInfo.sig), i->TagInfo.size, closest-(i->TagInfo.offset+rndup), (i->TagInfo.offset+rndup));
374 sReport += str;
375 nStatus = icMaxStatus(nStatus, icValidateWarning);
376 }
377 }
378
379 // Clause 7.2.1, bullet (b): "the first set of tagged element data shall immediately follow the tag table"
380 // 1st tag offset should be = Header (128) + Tag Count (4) + Tag Table (n*12)
381 if ((n > 0) && (smallest_offset > 128 + 4 + (n * 12))) {
382 sReport += icMsgValidateNonCompliant;
383 sprintf(str, "First tag data is at offset %d rather than immediately after tag table (offset %d).\n",
384 smallest_offset, 128 + 4 + (n * 12));
385 sReport += str;
386 nStatus = icMaxStatus(nStatus, icValidateNonCompliant);
387 }
388 }
389
390 if (argc>nArg+1) {
391 if (!stricmp(argv[nArg+1], "ALL")) {
392 for (i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++) {
393 DumpTag(pIcc, i->TagInfo.sig, verbosity);
394 }
395 }
396 else {
397 DumpTag(pIcc, (icTagSignature)icGetSigVal(argv[nArg+1]), verbosity);
398 }
399 }
400 }
401
402 int nValid = 0;
403
404 if (bDumpValidation) {
405 printf("\nValidation Report\n");
406 printf( "-----------------\n");
407 switch (nStatus) {
408 case icValidateOK:
409 printf("Profile is valid");
410 if (pHdr)
411 printf(" for version %s", Fmt.GetVersionName(pHdr->version));
412 break;
414 printf("Profile has warning(s)");
415 if (pHdr)
416 printf(" for version %s", Fmt.GetVersionName(pHdr->version));
417 break;
419 printf("Profile violates ICC specification");
420 if (pHdr)
421 printf(" for version %s", Fmt.GetVersionName(pHdr->version));
422 break;
424 printf("Profile has Critical Error(s) that violate ICC specification");
425 if (pHdr)
426 printf(" for version %s", Fmt.GetVersionName(pHdr->version));
427 nValid = -1;
428 break;
429 default:
430 printf("Profile has unknown status!");
431 nValid = -2;
432 break;
433 }
434 }
435 printf("\n\n");
436
437 sReport += "\n";
438 fwrite(sReport.c_str(), sReport.length(), 1, stdout);
439
440 delete pIcc;
441
442#if defined(_DEBUG) || defined(DEBUG)
443 printf("EXIT %d\n", nValid);
444#endif
445 return nValid;
446}
icValidateStatus
Definition IccDefs.h:118
@ icValidateOK
Definition IccDefs.h:119
@ icValidateWarning
Definition IccDefs.h:120
@ icValidateCriticalError
Definition IccDefs.h:122
@ icValidateNonCompliant
Definition IccDefs.h:121
#define stricmp
#define ICCPROFLIBVER
CIccProfile * ValidateIccProfile(CIccIO *pIO, std::string &sReport, icValidateStatus &nStatus)
Name: ValidateIccProfile.
CIccProfile * OpenIccProfile(const icChar *szFilename, bool bUseSubProfile)
Name: OpenIccProfile.
icValidateStatus icMaxStatus(icValidateStatus s1, icValidateStatus s2)
Name: icMaxStatus.
Definition IccUtil.cpp:244
const char * icMsgValidateWarning
Definition IccUtil.cpp:90
icFloatNumber icFtoD(icS15Fixed16Number num)
Definition IccUtil.cpp:559
const char * icMsgValidateNonCompliant
Definition IccUtil.cpp:91
icUInt32Number icGetSigVal(const icChar *pBuf)
Definition IccUtil.cpp:1258
icFloatNumber icF16toF(icFloat16Number num)
Definition IccUtil.cpp:629
bool IsProfileIDCalculated(icProfileID *profileID)
Definition IccUtil.cpp:2305
const icChar * GetVersionName(icUInt32Number val)
Definition IccUtil.cpp:1428
const icChar * GetSpectralColorSigName(icSpectralColorSignature sig)
Definition IccUtil.cpp:1769
const icChar * GetCmmSigName(icCmmSignature sig)
Definition IccUtil.cpp:1874
const icChar * GetProfileClassSigName(icProfileClassSignature sig)
Definition IccUtil.cpp:1804
const icChar * GetProfileFlagsName(icUInt32Number val, bool bCheckMCS=false)
Definition IccUtil.cpp:1465
const icChar * GetPlatformSigName(icPlatformSignature sig)
Definition IccUtil.cpp:1845
const icChar * GetProfileID(icProfileID *profileID)
Definition IccUtil.cpp:2293
const icChar * GetColorSpaceSigName(icColorSpaceSignature sig)
Definition IccUtil.cpp:1640
const icChar * GetDeviceAttrName(icUInt64Number val)
Definition IccUtil.cpp:1448
const icChar * GetSubClassVersionName(icUInt32Number val)
Definition IccUtil.cpp:1438
const icChar * GetRenderingIntentName(icRenderingIntent val, bool bIsV5=false)
Definition IccUtil.cpp:2091
#define icVersionNumberV4_2
icColorSpaceSignature
Color Space Signatures.
#define icVersionNumberV5
icTagSignature
public tags and sizes
icRenderingIntent
Rendering Intents, used in the profile header.
icCmmSignature
CMM signatures from the signature registry (as of Mar 6, 2018)
void DumpTag(CIccProfile *pIcc, icTagSignature sig, int nVerboseness)
icUInt16Number year
icUInt16Number month
icUInt16Number minutes
icUInt16Number seconds
icUInt16Number hours
icUInt16Number day
The Profile header.
icSpectralRange spectralRange
icXYZNumber illuminant
icUInt32Number renderingIntent
icUInt64Number attributes
icColorSpaceSignature colorSpace
icProfileClassSignature deviceClass
icSignature deviceSubClass
icSignature cmmId
icSpectralColorSignature spectralPCS
icDateTimeNumber date
icPlatformSignature platform
icSignature creator
icUInt32Number flags
icUInt32Number version
icMaterialColorSignature mcs
icProfileID profileID
icUInt32Number size
icSpectralRange biSpectralRange
icSignature manufacturer
icColorSpaceSignature pcs
icUInt16Number steps
icFloat16Number start
icFloat16Number end
icS15Fixed16Number Y
icS15Fixed16Number Z
icS15Fixed16Number X

References icHeader::attributes, icHeader::biSpectralRange, icHeader::cmmId, icHeader::colorSpace, icHeader::creator, icHeader::date, icDateTimeNumber::day, icHeader::deviceClass, icHeader::deviceSubClass, DumpTag(), icSpectralRange::end, icHeader::flags, CIccInfo::GetCmmSigName(), CIccInfo::GetColorSpaceSigName(), CIccInfo::GetDeviceAttrName(), CIccInfo::GetPlatformSigName(), CIccInfo::GetProfileClassSigName(), CIccInfo::GetProfileFlagsName(), CIccInfo::GetProfileID(), CIccInfo::GetRenderingIntentName(), CIccInfo::GetSpectralColorSigName(), CIccInfo::GetSubClassVersionName(), CIccInfo::GetTagSigName(), CIccInfo::GetVersionName(), icDateTimeNumber::hours, ICCPROFLIBVER, icF16toF(), icFtoD(), icGetSig(), icGetSigVal(), icMaxStatus(), icMsgValidateNonCompliant, icMsgValidateWarning, icValidateCriticalError, icValidateNonCompliant, icValidateOK, icValidateWarning, icVersionNumberV4_2, icVersionNumberV5, icHeader::illuminant, CIccInfo::IsProfileIDCalculated(), icHeader::manufacturer, icHeader::mcs, icDateTimeNumber::minutes, icDateTimeNumber::month, OpenIccProfile(), icHeader::pcs, icHeader::platform, icHeader::profileID, icHeader::renderingIntent, icDateTimeNumber::seconds, icHeader::size, icHeader::spectralPCS, icHeader::spectralRange, icSpectralRange::start, icSpectralRange::steps, stricmp, ValidateIccProfile(), icHeader::version, icXYZNumber::X, icXYZNumber::Y, icDateTimeNumber::year, and icXYZNumber::Z.

+ Here is the call graph for this function: