Skip to content

Commit 83ffb87

Browse files
committed
more ICC tags support
1 parent 5a9bc92 commit 83ffb87

File tree

2 files changed

+66
-6
lines changed

2 files changed

+66
-6
lines changed

lodepng_util.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ struct LodePNGICC {
285285

286286
// Parameters of a tone reproduction curve, either with a power law formulaa or with a lookup table.
287287
struct Curve {
288-
int type; // 0=linear, 1=lut, 2 = simple gamma, 3-6 = parametric (matches ICC parametric types 1-4)
288+
unsigned type; // 0=linear, 1=lut, 2 = simple gamma, 3-6 = parametric (matches ICC parametric types 1-4)
289289
std::vector<float> lut; // for type 1
290290
float gamma; // for type 2 and more
291291
float a, b, c, d, e, f; // for type 3-7
@@ -419,7 +419,9 @@ static unsigned parseICC(LodePNGICC* icc, const unsigned char* data, size_t size
419419
pos += 4;
420420
size_t offset = decodeICCUint32(data, size, &pos);
421421
unsigned tagsize = decodeICCUint32(data, size, &pos);
422-
if(pos >= size || offset + tagsize > size) return 1;
422+
if(pos >= size || offset >= size) return 1;
423+
if(offset + tagsize > size) return 1;
424+
if(tagsize < 8) return 1;
423425

424426
if(isICCword(data, size, namepos, "wtpt")) {
425427
offset += 8; // skip tag and reserved
@@ -455,12 +457,12 @@ static unsigned parseICC(LodePNGICC* icc, const unsigned char* data, size_t size
455457
isICCword(data, size, namepos, "gTRC") ||
456458
isICCword(data, size, namepos, "bTRC") ||
457459
isICCword(data, size, namepos, "kTRC")) {
460+
char c = (char)data[namepos];
461+
int channel = (c == 'b') ? 2 : (c == 'g' ? 1 : 0);
462+
// "curv": linear, gamma power or LUT
458463
if(isICCword(data, size, offset, "curv")) {
459464
icc->has_trc = true;
460-
char c = (char)data[namepos];
461-
int channel = (c == 'b') ? 2 : (c == 'g' ? 1 : 0);
462465
LodePNGICC::Curve* trc = &icc->trc[channel];
463-
// TODO: set type to other things if it's not LUT
464466
offset += 8; // skip tag "curv" and reserved
465467
size_t count = decodeICCUint32(data, size, &offset);
466468
if(count == 0) {
@@ -477,7 +479,37 @@ static unsigned parseICC(LodePNGICC* icc, const unsigned char* data, size_t size
477479
}
478480
}
479481
}
482+
// "para": parametric formula with gamma power, multipliers, biases and comparison point
483+
// TODO: test this on a realistic sample
484+
if(isICCword(data, size, offset, "para")) {
485+
icc->has_trc = true;
486+
LodePNGICC::Curve* trc = &icc->trc[channel];
487+
offset += 8; // skip tag "para" and reserved
488+
unsigned type = decodeICCUint16(data, size, &offset);
489+
offset += 2;
490+
if(type > 4) return 1; // unknown parametric curve type
491+
trc->type = type + 2;
492+
trc->gamma = decodeICC15Fixed16(data, size, &offset);
493+
if(type >= 1) {
494+
trc->a = decodeICC15Fixed16(data, size, &offset);
495+
trc->b = decodeICC15Fixed16(data, size, &offset);
496+
}
497+
if(type >= 2) {
498+
trc->c = decodeICC15Fixed16(data, size, &offset);
499+
}
500+
if(type >= 3) {
501+
trc->d = decodeICC15Fixed16(data, size, &offset);
502+
}
503+
if(type == 4) {
504+
trc->e = decodeICC15Fixed16(data, size, &offset);
505+
trc->f = decodeICC15Fixed16(data, size, &offset);
506+
}
507+
}
508+
// TODO: verify: does the "chrm" tag participate in computation so should be parsed?
480509
}
510+
// Return error if any parse went beyond the filesize. Note that the
511+
// parsing itself was always safe since it bound-checks inside.
512+
if(offset > size) return 1;
481513
}
482514

483515
return 0;

pngdetail.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,10 +916,16 @@ static int getICCInt32(const unsigned char* icc, size_t size, size_t pos) {
916916
return (int)((icc[pos] << 24) | (icc[pos + 1] << 16) | (icc[pos + 2] << 8) | (icc[pos + 3] << 0));
917917
}
918918

919+
// Signed
919920
static float getICC15Fixed16(const unsigned char* icc, size_t size, size_t pos) {
920921
return getICCInt32(icc, size, pos) / 65536.0;
921922
}
922923

924+
// Unsigned
925+
static float getICC16Fixed16(const unsigned char* icc, size_t size, size_t pos) {
926+
return getICCUint32(icc, size, pos) / 65536.0;
927+
}
928+
923929
static std::string printableICCWord(const unsigned char* icc, size_t size, size_t pos) {
924930
if (pos + 4 > size) {
925931
return "out of range";
@@ -961,7 +967,7 @@ void printICCDetails(const unsigned char* icc, size_t size, const std::string& i
961967
getICCUint16(icc, size, 24), getICCUint16(icc, size, 26), getICCUint16(icc, size, 28),
962968
getICCUint16(icc, size, 30), getICCUint16(icc, size, 32), getICCUint16(icc, size, 34));
963969
std::cout << indent << "signature: " << printableICCWord(icc, size, 36) << std::endl;
964-
std::cout << indent << "target: " << printableICCWord(icc, size, 40) << std::endl;
970+
std::cout << indent << "platform: " << printableICCWord(icc, size, 40) << std::endl;
965971
std::cout << indent << "flags: " << getICCUint32(icc, size, 44) << std::endl;
966972
std::cout << indent << "device manufacturer: " << printableICCWord(icc, size, 48) << ", ";
967973
std::cout << "device model: " << printableICCWord(icc, size, 52) << ", ";
@@ -1018,13 +1024,35 @@ void printICCDetails(const unsigned char* icc, size_t size, const std::string& i
10181024
}
10191025
if(lutsize == 0) std::cout << " (linear)";
10201026
}
1027+
if(datatype == "para") {
1028+
unsigned type = getICCUint16(icc, size, offset + 8);
1029+
float gamma = getICC15Fixed16(icc, size, offset + 12);
1030+
int numparams = (type == 4) ? 7 : ((type >= 1 && type <= 3) ? (type + 1) : 0);
1031+
std::cout << " type: " << type << ", gamma: " << gamma;
1032+
if(numparams > 0) {
1033+
std::cout << "params: ";
1034+
for(int j = 0; j < numparams; j++) {
1035+
if(j > 0) std::cout << ", ";
1036+
std::cout << getICC15Fixed16(icc, size, offset + 16 + j * 4);
1037+
}
1038+
}
1039+
}
10211040
if(datatype == "sf32") {
10221041
std::cout << ":";
10231042
for(size_t j = 8; j < tagsize; j += 4) {
10241043
float v = getICC15Fixed16(icc, size, offset + j);
10251044
std::cout << " " << v;
10261045
}
10271046
}
1047+
if(datatype == "chrm") {
1048+
size_t numchannels = getICCUint16(icc, size, offset + 8);
1049+
std::cout << ": n:" << numchannels
1050+
<< " phosphor:" << getICCUint16(icc, size, offset + 10);
1051+
for(size_t j = 0; j < numchannels; j++) {
1052+
std::cout << " xy:" << getICC16Fixed16(icc, size, offset + 12 + j * 8)
1053+
<< "," << getICC16Fixed16(icc, size, offset + 12 + j * 8 + 4);
1054+
}
1055+
}
10281056
if(datatype == "text" || datatype == "mluc" || datatype == "desc") {
10291057
// TODO: this is a bit of a simplification of the parse for now, e.g.
10301058
// ignoring UTF-16, instead implicitely skipping non-ASCII bytes, and

0 commit comments

Comments
 (0)