I am not getting intelligible decoded output for binary extraction of the palette inside PNGs. It should be a flat list of RGB values. I can make it work using PIL in Python, so the data is there. For the sample image (attached), ExifTool outputs:
␀␀␀=5(95$ämm9-$]]e5- $(-1-␜eUEeME"í9aMAIIQfl≤ ∂û∆QEE($ û≤¶û aI-$$␜û}ä $␘ ␘I==QA1␜ ␔␜␜␔≤ñÆM=-äuä-((␘␜␐␘␜␐∆ñöA9559=␘␔␐=5115999-␔␔␌␔␔␌␐␘␈95-␐␔␈␐␐␈␌␌␄␌␈␄öuueeyE9(ieiuaa11(1-(-1$m]Y5-␘™y5äeQ]MIYMEaM9III$$(QI= $$QE=EEE␜$ ñ}é( ␘mmäMA9IA5 ␜␐E=1-( ␐␘␔í鬬¬˚␐␔␔555515151---␄␌␈ymq␄␈␈¬≤Á␀␈␄␀␄␄ûÜíE5 ¢¶Ô91(a]muaYi]ae]]a]Yu]EUUa ™ YQQMMYUQMÆÇi∫¶ŒUMMQMI(($yuéYI=MIE$$ =AIEE= ␜ä}é␜ ␘E==␜␜␘␜␜␘¶ñ∫␘␜␔==5␘␘␔␘␘␔␘␘␔␔␘␐␔␘␐␔␔␐␔␔␐"æÔ951Î"˜-$␘␐␔␌␐␐␌␐␐␌¬∫Û51-␌␐␈ym}¢ä¢␌␌␈␈␌␄íܶ␈␈␄␄␈␀(- fl¬Î␄␄␀yeiäu}␄␀␀ueeÜqy--(UYm((-iYYaUQUUY]QMMMQUMEUIEÇ}¶ME=AEE$$␘AAEIA9␘␜ ==AEA59==E95␐␘␘-$$␐␔␘=9-␔␔␈␈␔␐115-11␈␌␐␐␐␄␄␌␌␌␐␀␌␌␀™Üé␀␄␈ueq55(5-(iYQ]UYeQM$$$ QA9A==␘␜␘␘␘␘␔␜␔=99E=-1( ␔␘␔␔␘␔␐␜␐E9-995995␔␔␔␐␘␐¶í™-$␜␐␔␐␐␔␐␐␐␐␌␔␌␌␐␌11-␌␌␌␈␐␈∂äí◊ ˚␈␌␈␈␈␈␄␌␄␈␄␈␄␈␄␀␌␀␄␄␄␀␈␀∂ÆÎ␀␄␀
my Python script:
from PIL import Image
def extract_palette(png_file_path):
# Open the image
with Image.open(png_file_path) as img:
# Ensure the image has a palette
if not img.mode == 'P':
raise ValueError("This image does not use a palette (not in 'P' mode).")
# Get the palette
palette = img.getpalette()
# The palette is a flat list of RGB values, so group it into tuples of (R, G, B)
colors = [tuple(palette[i:i+3]) for i in range(0, len(palette), 3)]
return colors
# Example usage
png_file_path = '~/OwlAlpha-0.5.png'
palette = extract_palette(png_file_path)
print(palette)
the output is:
[(0, 0, 0), (61, 53, 40), (57, 53, 36), (138, 109, 109), (57, 45, 36), (93, 93, 101), (53, 45, 32), (36, 40, 45), (49, 45, 28), (101, 85, 69), (101, 77, 69), (210, 146, 57), (97, 77, 65), (73, 73, 81), (223, 178, 202), (182, 158, 198), (81, 69, 69), (40, 36, 32), (202, 158, 178), (166, 158, 202), (97, 73, 45), (36, 36, 28), (158, 125, 138), (32, 36, 24), (32, 32, 24), (73, 61, 61), (81, 65, 49), (28, 32, 20), (28, 28, 20), (178, 150, 174), (77, 61, 45), (138, 117, 138), (45, 40, 40), (24, 28, 16), (24, 28, 16), (198, 150, 154), (65, 57, 53), (53, 57, 61), (24, 20, 16), (61, 53, 49), (49, 53, 57), (57, 57, 45), (20, 20, 12), (20, 20, 12), (16, 24, 8), (57, 53, 45), (16, 20, 8), (16, 16, 8), (12, 12, 4), (12, 8, 4), (154, 117, 117), (101, 101, 121), (69, 57, 40), (105, 101, 105), (117, 97, 97), (49, 49, 40), (49, 45, 40), (45, 49, 36), (109, 93, 89), (53, 45, 24), (170, 121, 53), (138, 101, 81), (93, 77, 73), (89, 77, 69), (97, 77, 57), (73, 73, 73), (36, 36, 40), (81, 73, 61), (32, 36, 36), (81, 69, 61), (69, 69, 69), (28, 36, 32), (150, 125, 142), (40, 32, 24), (109, 109, 138), (77, 65, 57), (73, 65, 53), (32, 28, 16), (69, 61, 49), (45, 40, 32), (16, 24, 20), (146, 142, 194), (194, 194, 251), (16, 20, 20), (53, 53, 53), (53, 49, 53), (49, 53, 49), (45, 45, 45), (4, 12, 8), (121, 109, 113), (4, 8, 8), (194, 178, 231), (0, 8, 4), (0, 4, 4), (158, 134, 146), (69, 53, 32), (162, 166, 239), (57, 49, 40), (97, 93, 109), (117, 97, 89), (105, 93, 97), (101, 93, 93), (97, 93, 89), (117, 93, 69), (85, 85, 97), (202, 170, 202), (89, 81, 81), (77, 77, 89), (85, 81, 77), (174, 130, 105), (186, 166, 206), (85, 77, 77), (81, 77, 73), (40, 40, 36), (121, 117, 142), (89, 73, 61), (77, 73, 69), (36, 36, 32), (61, 65, 73), (69, 69, 61), (32, 32, 28), (138, 125, 142), (28, 32, 24), (69, 61, 61), (28, 28, 24), (28, 28, 24), (166, 150, 186), (24, 28, 20), (61, 61, 53), (24, 24, 20), (24, 24, 20), (24, 24, 20), (20, 24, 16), (20, 24, 16), (20, 20, 16), (20, 20, 16), (210, 190, 239), (57, 53, 49), (235, 210, 247), (45, 36, 24), (16, 20, 12), (16, 16, 12), (16, 16, 12), (194, 186, 243), (53, 49, 45), (12, 16, 8), (121, 109, 125), (162, 138, 162), (12, 12, 8), (8, 12, 4), (146, 134, 166), (8, 8, 4), (4, 8, 0), (40, 45, 32), (223, 194, 235), (4, 4, 0), (121, 101, 105), (138, 117, 125), (4, 0, 0), (117, 101, 101), (134, 113, 121), (45, 45, 40), (85, 89, 109), (40, 40, 45), (105, 89, 89), (97, 85, 81), (85, 85, 89), (93, 81, 77), (77, 77, 81), (85, 77, 69), (85, 73, 69), (130, 125, 166), (77, 69, 61), (65, 69, 69), (36, 36, 24), (65, 65, 69), (73, 65, 57), (24, 28, 32), (61, 61, 65), (69, 65, 53), (57, 61, 61), (69, 57, 53), (16, 24, 24), (45, 36, 36), (16, 20, 24), (61, 57, 45), (20, 20, 8), (8, 20, 16), (49, 49, 53), (45, 49, 49), (8, 12, 16), (16, 16, 4), (4, 12, 12), (12, 16, 0), (12, 12, 0), (170, 134, 142), (0, 4, 8), (117, 101, 113), (53, 53, 40), (53, 45, 40), (105, 89, 81), (93, 85, 89), (101, 81, 77), (36, 36, 36), (32, 32, 32), (81, 65, 57), (65, 61, 61), (24, 28, 24), (24, 24, 24), (20, 28, 20), (61, 57, 57), (69, 61, 45), (49, 40, 32), (20, 24, 20), (20, 24, 20), (16, 28, 16), (69, 57, 45), (57, 57, 53), (57, 57, 53), (20, 20, 20), (16, 24, 16), (166, 146, 170), (45, 36, 28), (16, 20, 16), (16, 20, 16), (16, 16, 16), (12, 20, 12), (12, 16, 12), (49, 49, 45), (12, 12, 12), (8, 16, 8), (182, 138, 146), (215, 202, 251), (8, 12, 8), (8, 8, 8), (4, 12, 4), (8, 4, 8), (4, 8, 4), (0, 12, 0), (4, 4, 4), (0, 8, 0), (182, 174, 235), (0, 4, 0)]
of course i would always rather use ExifTool. is this achievable? I pray it might be an easy change.
- J
Here is a config file that will give you that exact format:
%Image::ExifTool::UserDefined = (
'Image::ExifTool::PNG::Main' => {
PLTE => {
Name => 'Palette',
ValueConv => q{
my $str = '[' . join(', ', unpack('C*',$val)) . ']';
$str =~ s/(\d+, \d+, \d+)/($1)/g;
return $str;
},
},
},
);
1;
- Phil
that's very generous, Phil! thanks! - J
hey Phil, i am giving a try at doing the same with the tRNS chunk now.
%Image::ExifTool::UserDefined = (
'Image::ExifTool::PNG::Main' => {
tRNS => {
Name => 'Transparency',
ValueConv => q{
my @transparency = unpack('C*',$val);
my $colorType = GetTagValue('ColorType'); # pseudocode
if ($colorType == 3) { # Indexed-color
return '[' . join(',', @transparency) . ']';
} elsif ($colorType == 0 || $colorType == 4) { # Grayscale
return unpack('n', $val); # Assuming $val is the 2-byte grayscale value
} elsif ($colorType == 2) { # Truecolor
my @rgbTransparency = unpack('n3', $val);
return '[' . join(',', @rgbTransparency) . ']';
}
return '';
},
},
},
);
i just don't know how to get a value from another field in here (pseudocode abounding). not sure i have ever done that! (note i futzed with the formatting to make an array of triplets in JSON, like [ [1,2,3], [4,5,6] ])
You need to use a Composite tag if you want to combine the values of multiple tags.
- Phil
i put this in the composite section and it fails silently (-composite:PNGTransparency). not sure whats going on... do you see the gaffe?
PNGTransparency => {
Require => {
0 => 'PNG:Transparency',
1 => 'PNG:ColorType',
},
ValueConv => q{
my @transparencyData = unpack('C*', $val[0]);
if ($val[1] == 3) { # Indexed-color/palette
return '[' . join(',', @transparencyData) . ']';
} elsif ($val[1] == 0) { # Grayscale
# Unpack as a single 2-byte value
my ($transparency) = unpack('n', $val[0]);
return $transparency;
} elsif ($val[1] == 2) { # RGB
# Unpack the first three 2-byte values from transparency data
my @rgbaTransparency = unpack('n3', $val[0]);
return '[' . join(',', @rgbaTransparency) . ']';
}
return '';
},
},
- J
This is how your code works for me:
> exiftool -config test.config OwlAlpha-0.5.png -PNGTransparency
PNG Transparency : [83,67,65,76,65,82,40,48,120,55,102,101,99,98,101,48,97,51,97,51,56,41]
I've attached the attached config file.
- Phil
Sigh. It was a nesting issue. You'd think with my being blue-j that would not occur. Thanks, Phil!
the config actually was not working. it did indeed export the values shown above, but it always exported something along those lines. it was exporting the wrong text! i pounded on this a lot and arrived here, which worked for me:
'Image::ExifTool::PNG::Main' => {
tRNS => {
Name => 'Transparency',
ValueConv => q{
my @transparencyData = unpack('C*', $val);
my $str = '[';
$str .= join(',', @transparencyData);
$str .= ']'; # Add closing bracket here, outside the join
return $str;
},
},
},
i just was not able to get a composite tag to work, but this meets my needs. not sure where i went wrong.
- J
Ah, yes. Sorry. I didn't check the value to see if it made sense. I think that replacing $val[0] with $$val should fix this, but I don't have time to test it right now.
- Phil
I gave that a try, but it didn't seem to change the output. Thank you for your attention to this! - J
At any rate, the reason for the incorrect output is because a scalar reference wasn't dereferenced. The output is the byte sequence for "SCALAR...". Not sure if it is worth spending time to fix it at this point though.
- phil
this seems to work, though i have not tested every permutation! thanks for the tip!
PNGTransparency => {
Require => {
0 => 'PNG:Transparency',
1 => 'PNG:ColorType',
},
ValueConv => q{
my @transparencyData = unpack('C*', ${$val[o]});
if ($val[1] == 3) { # Indexed-color/palette
return '[' . join(',', @transparencyData) . ']';
} elsif ($val[1] == 0) { # Grayscale
# Unpack as a single 2-byte value
my ($transparency) = unpack('n', ${$val[o]});
return $transparency;
} elsif ($val[1] == 2) { # RGB
# Unpack the first three 2-byte values from transparency data
my @rgbaTransparency = unpack('n3', ${$val[o]});
return '[' . join(',', @rgbaTransparency) . ']';
}
return '';
},
},
- J
Yes, that does it. But I thought $$val should be equivalent to $$val[0] (because I thought $val should be set to $val[0]). Not sure why this didn't work, but again I don't have time to look into it right now.
- Phil
strange. i ran into a fail case and can't see the reason. the hex is very simple:
00000000 89 50 4E 47:0D 0A 1A 0A|00 00 00 0D:49 48 44 52
00000010 00 00 00 20:00 00 00 20|02 03 00 00:00 0E 14 92
00000020 67 00 00 00:0C 50 4C 54|45 00 00 FF:00 00 FF 00
00000030 00 FF 00 00:FF B5 9F 43|CE 00 00 00:03 74 52 4E
00000040 53 00 55 AA:0B B9 27 39|00 00 00 14:49 44 41 54
00000050 78 5E 63 64:00 82 50 20|1E 2C 8C 55:83 8B 01 00
00000060 2B 17 15 61:16 33 2E 41|00 00 00 00:49 45 4E 44
00000070 AE 42 60 82
the tRNS chunk is 00 55 AA which is just 0 85 170, proper transparency values. i don't see anything vexing in the data... ExifTool DOES print this PNG:Transparency as "0 85 170" with no binary flag... perhaps this points the way?
- J