exiftool_vendored 10.65.0 → 11.41.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of exiftool_vendored might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/Changes +818 -19
- data/bin/MANIFEST +38 -0
- data/bin/META.json +1 -1
- data/bin/META.yml +1 -1
- data/bin/README +48 -44
- data/bin/arg_files/exif2xmp.args +4 -1
- data/bin/arg_files/gps2xmp.args +4 -1
- data/bin/arg_files/iptcCore.args +8 -0
- data/bin/arg_files/xmp2exif.args +4 -1
- data/bin/arg_files/xmp2gps.args +4 -1
- data/bin/config_files/dji.config +131 -0
- data/bin/config_files/example.config +6 -2
- data/bin/config_files/gps2utm.config +256 -256
- data/bin/config_files/nksc.config +146 -0
- data/bin/config_files/picasa_faces.config +382 -382
- data/bin/exiftool +688 -408
- data/bin/fmt_files/gpx.fmt +10 -6
- data/bin/fmt_files/gpx_wpt.fmt +10 -6
- data/bin/fmt_files/kml.fmt +8 -5
- data/bin/lib/File/RandomAccess.pm +48 -8
- data/bin/lib/File/RandomAccess.pod +21 -2
- data/bin/lib/Image/ExifTool.pm +645 -256
- data/bin/lib/Image/ExifTool.pod +219 -164
- data/bin/lib/Image/ExifTool/AES.pm +1 -1
- data/bin/lib/Image/ExifTool/AFCP.pm +3 -8
- data/bin/lib/Image/ExifTool/AIFF.pm +12 -4
- data/bin/lib/Image/ExifTool/APE.pm +1 -1
- data/bin/lib/Image/ExifTool/APP12.pm +1 -1
- data/bin/lib/Image/ExifTool/ASF.pm +19 -6
- data/bin/lib/Image/ExifTool/Apple.pm +13 -5
- data/bin/lib/Image/ExifTool/Audible.pm +1 -1
- data/bin/lib/Image/ExifTool/BMP.pm +1 -1
- data/bin/lib/Image/ExifTool/BPG.pm +17 -15
- data/bin/lib/Image/ExifTool/BZZ.pm +1 -1
- data/bin/lib/Image/ExifTool/BigTIFF.pm +30 -15
- data/bin/lib/Image/ExifTool/BuildTagLookup.pm +103 -52
- data/bin/lib/Image/ExifTool/Canon.pm +684 -112
- data/bin/lib/Image/ExifTool/CanonCustom.pm +119 -9
- data/bin/lib/Image/ExifTool/CanonRaw.pm +1 -1
- data/bin/lib/Image/ExifTool/CanonVRD.pm +13 -26
- data/bin/lib/Image/ExifTool/CaptureOne.pm +1 -1
- data/bin/lib/Image/ExifTool/Casio.pm +1 -1
- data/bin/lib/Image/ExifTool/Charset.pm +1 -1
- data/bin/lib/Image/ExifTool/DICOM.pm +12 -5
- data/bin/lib/Image/ExifTool/DJI.pm +51 -3
- data/bin/lib/Image/ExifTool/DNG.pm +15 -8
- data/bin/lib/Image/ExifTool/DPX.pm +1 -1
- data/bin/lib/Image/ExifTool/DV.pm +1 -1
- data/bin/lib/Image/ExifTool/DarwinCore.pm +63 -23
- data/bin/lib/Image/ExifTool/DjVu.pm +4 -2
- data/bin/lib/Image/ExifTool/EXE.pm +30 -6
- data/bin/lib/Image/ExifTool/Exif.pm +351 -109
- data/bin/lib/Image/ExifTool/FITS.pm +148 -0
- data/bin/lib/Image/ExifTool/FLAC.pm +2 -2
- data/bin/lib/Image/ExifTool/FLIF.pm +1 -1
- data/bin/lib/Image/ExifTool/FLIR.pm +109 -13
- data/bin/lib/Image/ExifTool/Fixup.pm +1 -1
- data/bin/lib/Image/ExifTool/Flash.pm +3 -3
- data/bin/lib/Image/ExifTool/FlashPix.pm +433 -9
- data/bin/lib/Image/ExifTool/Font.pm +2 -2
- data/bin/lib/Image/ExifTool/FotoStation.pm +1 -1
- data/bin/lib/Image/ExifTool/FujiFilm.pm +336 -16
- data/bin/lib/Image/ExifTool/GE.pm +1 -1
- data/bin/lib/Image/ExifTool/GIF.pm +5 -7
- data/bin/lib/Image/ExifTool/GIMP.pm +39 -3
- data/bin/lib/Image/ExifTool/GPS.pm +48 -22
- data/bin/lib/Image/ExifTool/GeoTiff.pm +23 -23
- data/bin/lib/Image/ExifTool/Geotag.pm +80 -45
- data/bin/lib/Image/ExifTool/GoPro.pm +709 -0
- data/bin/lib/Image/ExifTool/H264.pm +40 -18
- data/bin/lib/Image/ExifTool/HP.pm +1 -1
- data/bin/lib/Image/ExifTool/HTML.pm +19 -12
- data/bin/lib/Image/ExifTool/HtmlDump.pm +37 -26
- data/bin/lib/Image/ExifTool/ICC_Profile.pm +297 -23
- data/bin/lib/Image/ExifTool/ID3.pm +12 -7
- data/bin/lib/Image/ExifTool/IPTC.pm +48 -19
- data/bin/lib/Image/ExifTool/ISO.pm +1 -1
- data/bin/lib/Image/ExifTool/ITC.pm +1 -1
- data/bin/lib/Image/ExifTool/Import.pm +13 -9
- data/bin/lib/Image/ExifTool/InDesign.pm +3 -5
- data/bin/lib/Image/ExifTool/JPEG.pm +22 -11
- data/bin/lib/Image/ExifTool/JPEGDigest.pm +1 -1
- data/bin/lib/Image/ExifTool/JSON.pm +3 -3
- data/bin/lib/Image/ExifTool/JVC.pm +1 -1
- data/bin/lib/Image/ExifTool/Jpeg2000.pm +2 -2
- data/bin/lib/Image/ExifTool/Kodak.pm +1233 -58
- data/bin/lib/Image/ExifTool/KyoceraRaw.pm +1 -1
- data/bin/lib/Image/ExifTool/LNK.pm +1 -1
- data/bin/lib/Image/ExifTool/Lang/cs.pm +1 -1
- data/bin/lib/Image/ExifTool/Lang/de.pm +33 -24
- data/bin/lib/Image/ExifTool/Lang/en_ca.pm +64 -2
- data/bin/lib/Image/ExifTool/Lang/en_gb.pm +64 -2
- data/bin/lib/Image/ExifTool/Lang/es.pm +8 -4
- data/bin/lib/Image/ExifTool/Lang/fi.pm +46 -4
- data/bin/lib/Image/ExifTool/Lang/fr.pm +5 -3
- data/bin/lib/Image/ExifTool/Lang/it.pm +6 -3
- data/bin/lib/Image/ExifTool/Lang/ja.pm +15 -3
- data/bin/lib/Image/ExifTool/Lang/ko.pm +5 -2
- data/bin/lib/Image/ExifTool/Lang/nl.pm +6 -3
- data/bin/lib/Image/ExifTool/Lang/pl.pm +2 -2
- data/bin/lib/Image/ExifTool/Lang/ru.pm +1 -1
- data/bin/lib/Image/ExifTool/Lang/sv.pm +1 -1
- data/bin/lib/Image/ExifTool/Lang/tr.pm +4 -2
- data/bin/lib/Image/ExifTool/Lang/zh_cn.pm +1 -1
- data/bin/lib/Image/ExifTool/Lang/zh_tw.pm +1 -1
- data/bin/lib/Image/ExifTool/Leaf.pm +1 -1
- data/bin/lib/Image/ExifTool/Lytro.pm +4 -8
- data/bin/lib/Image/ExifTool/M2TS.pm +10 -9
- data/bin/lib/Image/ExifTool/MIE.pm +12 -8
- data/bin/lib/Image/ExifTool/MIEUnits.pod +1 -1
- data/bin/lib/Image/ExifTool/MIFF.pm +1 -1
- data/bin/lib/Image/ExifTool/MNG.pm +1 -1
- data/bin/lib/Image/ExifTool/MOI.pm +1 -1
- data/bin/lib/Image/ExifTool/MPC.pm +1 -1
- data/bin/lib/Image/ExifTool/MPEG.pm +2 -3
- data/bin/lib/Image/ExifTool/MPF.pm +6 -6
- data/bin/lib/Image/ExifTool/MWG.pm +4 -4
- data/bin/lib/Image/ExifTool/MXF.pm +2 -2
- data/bin/lib/Image/ExifTool/MacOS.pm +184 -34
- data/bin/lib/Image/ExifTool/MakerNotes.pm +101 -18
- data/bin/lib/Image/ExifTool/Matroska.pm +1 -1
- data/bin/lib/Image/ExifTool/Microsoft.pm +5 -3
- data/bin/lib/Image/ExifTool/Minolta.pm +89 -62
- data/bin/lib/Image/ExifTool/MinoltaRaw.pm +1 -1
- data/bin/lib/Image/ExifTool/Motorola.pm +1 -1
- data/bin/lib/Image/ExifTool/Nikon.pm +1511 -380
- data/bin/lib/Image/ExifTool/NikonCapture.pm +1 -1
- data/bin/lib/Image/ExifTool/NikonCustom.pm +2758 -2935
- data/bin/lib/Image/ExifTool/Nintendo.pm +1 -1
- data/bin/lib/Image/ExifTool/OOXML.pm +1 -1
- data/bin/lib/Image/ExifTool/Ogg.pm +1 -1
- data/bin/lib/Image/ExifTool/Olympus.pm +47 -8
- data/bin/lib/Image/ExifTool/OpenEXR.pm +1 -1
- data/bin/lib/Image/ExifTool/Opus.pm +1 -1
- data/bin/lib/Image/ExifTool/PCX.pm +138 -0
- data/bin/lib/Image/ExifTool/PDF.pm +58 -42
- data/bin/lib/Image/ExifTool/PGF.pm +1 -1
- data/bin/lib/Image/ExifTool/PICT.pm +1 -1
- data/bin/lib/Image/ExifTool/PLIST.pm +12 -5
- data/bin/lib/Image/ExifTool/PLUS.pm +1 -1
- data/bin/lib/Image/ExifTool/PNG.pm +108 -10
- data/bin/lib/Image/ExifTool/PPM.pm +3 -3
- data/bin/lib/Image/ExifTool/PSP.pm +1 -1
- data/bin/lib/Image/ExifTool/Palm.pm +1 -1
- data/bin/lib/Image/ExifTool/Panasonic.pm +299 -31
- data/bin/lib/Image/ExifTool/PanasonicRaw.pm +201 -19
- data/bin/lib/Image/ExifTool/Pentax.pm +164 -143
- data/bin/lib/Image/ExifTool/PhaseOne.pm +12 -5
- data/bin/lib/Image/ExifTool/PhotoCD.pm +9 -10
- data/bin/lib/Image/ExifTool/PhotoMechanic.pm +1 -1
- data/bin/lib/Image/ExifTool/Photoshop.pm +230 -60
- data/bin/lib/Image/ExifTool/PostScript.pm +29 -4
- data/bin/lib/Image/ExifTool/PrintIM.pm +1 -1
- data/bin/lib/Image/ExifTool/Qualcomm.pm +2 -2
- data/bin/lib/Image/ExifTool/QuickTime.pm +1539 -279
- data/bin/lib/Image/ExifTool/QuickTimeStream.pl +1857 -0
- data/bin/lib/Image/ExifTool/README +84 -46
- data/bin/lib/Image/ExifTool/RIFF.pm +116 -23
- data/bin/lib/Image/ExifTool/RSRC.pm +1 -1
- data/bin/lib/Image/ExifTool/RTF.pm +6 -4
- data/bin/lib/Image/ExifTool/Radiance.pm +1 -1
- data/bin/lib/Image/ExifTool/Rawzor.pm +3 -2
- data/bin/lib/Image/ExifTool/Real.pm +1 -1
- data/bin/lib/Image/ExifTool/Reconyx.pm +261 -7
- data/bin/lib/Image/ExifTool/Red.pm +325 -0
- data/bin/lib/Image/ExifTool/Ricoh.pm +3 -7
- data/bin/lib/Image/ExifTool/Samsung.pm +95 -25
- data/bin/lib/Image/ExifTool/Sanyo.pm +1 -1
- data/bin/lib/Image/ExifTool/Scalado.pm +1 -1
- data/bin/lib/Image/ExifTool/Shift.pl +26 -12
- data/bin/lib/Image/ExifTool/Shortcuts.pm +9 -2
- data/bin/lib/Image/ExifTool/Sigma.pm +36 -30
- data/bin/lib/Image/ExifTool/SigmaRaw.pm +3 -8
- data/bin/lib/Image/ExifTool/Sony.pm +531 -177
- data/bin/lib/Image/ExifTool/SonyIDC.pm +63 -3
- data/bin/lib/Image/ExifTool/Stim.pm +2 -2
- data/bin/lib/Image/ExifTool/TagInfoXML.pm +23 -23
- data/bin/lib/Image/ExifTool/TagLookup.pm +6352 -5062
- data/bin/lib/Image/ExifTool/TagNames.pod +3024 -565
- data/bin/lib/Image/ExifTool/Theora.pm +1 -1
- data/bin/lib/Image/ExifTool/Torrent.pm +2 -2
- data/bin/lib/Image/ExifTool/Unknown.pm +1 -1
- data/bin/lib/Image/ExifTool/VCard.pm +47 -9
- data/bin/lib/Image/ExifTool/Validate.pm +391 -99
- data/bin/lib/Image/ExifTool/Vorbis.pm +1 -1
- data/bin/lib/Image/ExifTool/WTV.pm +319 -0
- data/bin/lib/Image/ExifTool/WriteCanonRaw.pl +1 -1
- data/bin/lib/Image/ExifTool/WriteExif.pl +91 -18
- data/bin/lib/Image/ExifTool/WriteIPTC.pl +6 -6
- data/bin/lib/Image/ExifTool/WritePDF.pl +13 -12
- data/bin/lib/Image/ExifTool/WritePNG.pl +1 -1
- data/bin/lib/Image/ExifTool/WritePhotoshop.pl +1 -1
- data/bin/lib/Image/ExifTool/WritePostScript.pl +2 -2
- data/bin/lib/Image/ExifTool/WriteQuickTime.pl +764 -121
- data/bin/lib/Image/ExifTool/WriteXMP.pl +176 -67
- data/bin/lib/Image/ExifTool/Writer.pl +490 -246
- data/bin/lib/Image/ExifTool/XMP.pm +216 -76
- data/bin/lib/Image/ExifTool/XMP2.pl +54 -10
- data/bin/lib/Image/ExifTool/XMPStruct.pl +14 -11
- data/bin/lib/Image/ExifTool/ZIP.pm +60 -15
- data/bin/lib/Image/ExifTool/iWork.pm +12 -5
- data/bin/perl-Image-ExifTool.spec +46 -44
- data/lib/exiftool_vendored/version.rb +1 -1
- metadata +14 -4
@@ -0,0 +1,146 @@
|
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: nksc.config
|
3
|
+
#
|
4
|
+
# Description: This config file contains tag definitions to extract metadata
|
5
|
+
# from RDF/XML-based Nikon ViewNX NKSC sidecar files
|
6
|
+
#
|
7
|
+
# Usage: exiftool -config nksc.config -ext nksc DIR
|
8
|
+
#
|
9
|
+
# Requires: ExifTool version 11.38 or later
|
10
|
+
#
|
11
|
+
# Revisions: 2019/04/24 - P. Harvey Created
|
12
|
+
#------------------------------------------------------------------------------
|
13
|
+
|
14
|
+
%Image::ExifTool::UserDefined = (
|
15
|
+
'Image::ExifTool::XMP::Main' => {
|
16
|
+
ast => {
|
17
|
+
SubDirectory => { TagTable => 'Image::ExifTool::UserDefined::ast' },
|
18
|
+
},
|
19
|
+
sdc => {
|
20
|
+
SubDirectory => { TagTable => 'Image::ExifTool::UserDefined::sdc' },
|
21
|
+
},
|
22
|
+
nine => {
|
23
|
+
SubDirectory => { TagTable => 'Image::ExifTool::UserDefined::nine' },
|
24
|
+
},
|
25
|
+
},
|
26
|
+
'Image::ExifTool::Composite' => {
|
27
|
+
GPSLatitude => {
|
28
|
+
Require => {
|
29
|
+
0 => 'XMP-ast:GPSLatitude',
|
30
|
+
1 => 'XMP-ast:GPSLatitudeRef',
|
31
|
+
},
|
32
|
+
ValueConv => '$prt[1] =~ /^S/i ? -$val[0] : $val[0]',
|
33
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")',
|
34
|
+
},
|
35
|
+
GPSLongitude => {
|
36
|
+
Require => {
|
37
|
+
0 => 'XMP-ast:GPSLongitude',
|
38
|
+
1 => 'XMP-ast:GPSLongitudeRef',
|
39
|
+
},
|
40
|
+
ValueConv => '$prt[1] =~ /^W/i ? -$val[0] : $val[0]',
|
41
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")',
|
42
|
+
},
|
43
|
+
},
|
44
|
+
);
|
45
|
+
|
46
|
+
%Image::ExifTool::UserDefined::ast = (
|
47
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-ast', 2 => 'Location' },
|
48
|
+
NAMESPACE => { 'ast' => 'http://ns.nikon.com/asteroid/1.0/' },
|
49
|
+
about => { Groups => { 2 => 'Image' } },
|
50
|
+
version => { Groups => { 2 => 'Image' } },
|
51
|
+
GPSVersionID => {
|
52
|
+
ValueConv => q{
|
53
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
54
|
+
SetByteOrder('II');
|
55
|
+
ReadValue($valPt, 0, 'int8u', 4, length($$valPt));
|
56
|
+
},
|
57
|
+
PrintConv => '$val =~ tr/ /./; $val',
|
58
|
+
},
|
59
|
+
GPSLatitude => {
|
60
|
+
ValueConv => q{
|
61
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
62
|
+
SetByteOrder('II');
|
63
|
+
$val = ReadValue($valPt, 0, 'double', 3, length($$valPt));
|
64
|
+
Image::ExifTool::GPS::ToDegrees($val);
|
65
|
+
},
|
66
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val)',
|
67
|
+
},
|
68
|
+
GPSLatitudeRef => {
|
69
|
+
ValueConv => q{
|
70
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
71
|
+
SetByteOrder('II');
|
72
|
+
ReadValue($valPt, 0, 'int32u', 3, length($$valPt));
|
73
|
+
},
|
74
|
+
PrintConv => { 0 => 'North', 1 => 'South' },
|
75
|
+
},
|
76
|
+
GPSLongitude => {
|
77
|
+
ValueConv => q{
|
78
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
79
|
+
SetByteOrder('II');
|
80
|
+
$val = ReadValue($valPt, 0, 'double', 3, length($$valPt));
|
81
|
+
Image::ExifTool::GPS::ToDegrees($val);
|
82
|
+
},
|
83
|
+
PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val)',
|
84
|
+
},
|
85
|
+
GPSLongitudeRef => {
|
86
|
+
ValueConv => q{
|
87
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
88
|
+
SetByteOrder('II');
|
89
|
+
ReadValue($valPt, 0, 'int32u', 3, length($$valPt));
|
90
|
+
},
|
91
|
+
PrintConv => { 2 => 'East', 3 => 'West' },
|
92
|
+
},
|
93
|
+
GPSAltitude => {
|
94
|
+
ValueConv => q{
|
95
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
96
|
+
SetByteOrder('II');
|
97
|
+
ReadValue($valPt, 0, 'double');
|
98
|
+
},
|
99
|
+
PrintConv => '$val =~ /^(inf|undef)$/ ? $val : "$val m"',
|
100
|
+
},
|
101
|
+
GPSAltitudeRef => {
|
102
|
+
ValueConv => q{
|
103
|
+
my $valPt = Image::ExifTool::XMP::DecodeBase64($val);
|
104
|
+
ReadValue($valPt, 0, 'int8u');
|
105
|
+
},
|
106
|
+
PrintConv => {
|
107
|
+
0 => 'Above Sea Level',
|
108
|
+
1 => 'Below Sea Level',
|
109
|
+
},
|
110
|
+
},
|
111
|
+
GPSMapDatum => { },
|
112
|
+
XMLPackets => {
|
113
|
+
Name => 'XMP',
|
114
|
+
Groups => { 2 => 'Image' },
|
115
|
+
RawConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
116
|
+
SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' },
|
117
|
+
},
|
118
|
+
IPTC => {
|
119
|
+
Name => 'IPTC',
|
120
|
+
Groups => { 2 => 'Image' },
|
121
|
+
RawConv => 'Image::ExifTool::XMP::DecodeBase64($val)',
|
122
|
+
SubDirectory => { TagTable => 'Image::ExifTool::IPTC::Main' },
|
123
|
+
},
|
124
|
+
);
|
125
|
+
|
126
|
+
%Image::ExifTool::UserDefined::sdc = (
|
127
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-sdc', 2 => 'Image' },
|
128
|
+
NAMESPACE => { 'sdc' => 'http://ns.nikon.com/sdc/1.0/' },
|
129
|
+
about => { },
|
130
|
+
version => { },
|
131
|
+
appversion => { },
|
132
|
+
appname => { },
|
133
|
+
);
|
134
|
+
|
135
|
+
%Image::ExifTool::UserDefined::nine = (
|
136
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-nine', 2 => 'Image' },
|
137
|
+
NAMESPACE => { 'nine' => 'http://ns.nikon.com/nine/1.0/' },
|
138
|
+
about => { },
|
139
|
+
version => { },
|
140
|
+
NineEdits => { Binary => 1 },
|
141
|
+
Label => { },
|
142
|
+
Rating => { },
|
143
|
+
Trim => { ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)' },
|
144
|
+
);
|
145
|
+
|
146
|
+
1; #end
|
@@ -1,382 +1,382 @@
|
|
1
|
-
#------------------------------------------------------------------------------
|
2
|
-
# File: picasa_faces.config
|
3
|
-
#
|
4
|
-
# Description: User-defined Composite tag definitions to convert face regions
|
5
|
-
# in .picasa.ini files to MWG region tags (Metadata Working Group
|
6
|
-
# region, used by Picasa) and MP region tags (used by Microsoft
|
7
|
-
# Photo Library).
|
8
|
-
#
|
9
|
-
# Tag definitions and examples:
|
10
|
-
#
|
11
|
-
# PicasaToMWGRegion
|
12
|
-
# This will create the MWG region tag but will filter out the regions
|
13
|
-
# that are still unnamed in Picasa. Picasa defaults to naming these
|
14
|
-
# regions 'ffffffffffffffff' but normally will not save these to file.
|
15
|
-
# Example:
|
16
|
-
# exiftool -config picasa_faces.config "-RegionInfo<PicasaToMWGRegion" FILE
|
17
|
-
#
|
18
|
-
# PicasaToMPRegion
|
19
|
-
# This will create the MP region tag but will filter out the regions that
|
20
|
-
# are still unnamed in Picasa. Picasa defaults to naming these regions
|
21
|
-
# 'ffffffffffffffff' but normally will not save these to file.
|
22
|
-
# Example:
|
23
|
-
# exiftool -config picasa_faces.config "-RegionInfoMP<PicasaToMPRegion" FILE
|
24
|
-
#
|
25
|
-
# PicasaRegionNames
|
26
|
-
# Returns a list of the region names associated with the file. This
|
27
|
-
# allows copying of the region names to XMP:Subject and/or IPTC:Keywords.
|
28
|
-
# It also allows checking to see if regions need to be updated.
|
29
|
-
# Example:
|
30
|
-
# exiftool -config picasa_faces.config "-XMP:Subject<PicasaRegionNames" FILE
|
31
|
-
#
|
32
|
-
# PicasaToMWGRegionUnfiltered
|
33
|
-
# This will create the MWG region tag. This version does not filter out
|
34
|
-
# the unnamed regions. Picasa normally will filter out unnamed regions
|
35
|
-
# when it saves regions in the file.
|
36
|
-
# Example:
|
37
|
-
# exiftool -config picasa_faces.config "-RegionInfo<PicasaToMWGRegionUnfiltered" FILE
|
38
|
-
#
|
39
|
-
# PicasaToMPRegionUnfiltered
|
40
|
-
# This will create the MP region tag. This version does not filter out
|
41
|
-
# the unnamed regions. Picasa normally will filter out unnamed regions
|
42
|
-
# when it saves regions in the file.
|
43
|
-
# Example:
|
44
|
-
# exiftool -config picasa_faces.config "-RegionInfoMP<PicasaToMPRegionUnfiltered" FILE
|
45
|
-
#
|
46
|
-
# Notes: The face names are loaded from the Picasa contacts file, which
|
47
|
-
# defaults to:
|
48
|
-
#
|
49
|
-
# C:/Users/MainUser/AppData/Local/PicasaData/Google/Picasa2/contacts/contacts.xml
|
50
|
-
#
|
51
|
-
# The default contacts file may be changed by editing the value
|
52
|
-
# of $contactXML below, or on the command line with ExifTool 9.90
|
53
|
-
# or later via the -userParam option, eg:
|
54
|
-
# -userparam PicasaContactsFile=/path/to/contacts.xml
|
55
|
-
#
|
56
|
-
# Requires: ExifTool version 8.82 or later (9.90 or later for -userparam)
|
57
|
-
#
|
58
|
-
# Revisions: 2015/03/07 - Bryan K. Williams (aka StarGeek) Created
|
59
|
-
# 2015/03/12 - PH Minor changes, optimizations and reformatting
|
60
|
-
# 2015/05/11 - BKW Fix bug where Picasa writes region data for
|
61
|
-
# rotated NEF and CR2 images as if the orientation
|
62
|
-
# is not rotated.
|
63
|
-
# 2015/05/12 - PH Minor code tweaks
|
64
|
-
# 2015/10/26 - BKW Round off area sizes to 7 decimal places
|
65
|
-
# 2016/01/18 - BKW Improved rounding algorithm
|
66
|
-
# 2016/05/14 - BKW Increased rounding to 9 decimal places (Max Picasa accepts),
|
67
|
-
# moved rounding operation to subroutine
|
68
|
-
#
|
69
|
-
# References: http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,6354.0.html
|
70
|
-
#------------------------------------------------------------------------------
|
71
|
-
|
72
|
-
# Picasa contacts file name
|
73
|
-
my $contactXML = 'C:/Users/MainUser/AppData/Local/PicasaData/Google/Picasa2/contacts/contacts.xml';
|
74
|
-
|
75
|
-
# local variables
|
76
|
-
my $lastIniFile = ''; # path of last .picasa.ini file loaded
|
77
|
-
my $lastContactFile = ''; # path of last contacts.xml file loaded
|
78
|
-
|
79
|
-
# raw file types that need additional processing to get regions correct
|
80
|
-
my %isRawFile = map { $_ => 1 } qw(
|
81
|
-
3FR ARW CR2 CRW CS1 DCR DNG EIP ERF IIQ K25 KDC MEF MOS MRW NEF NRW
|
82
|
-
ORF PEF RAF RAW RW2 RWL SR2 SRF SRW X3F), 'Canon 1D RAW';
|
83
|
-
|
84
|
-
my %contactHash; # lookup for loaded contacts.xml entries
|
85
|
-
my %fileHash; # lookup for loaded .picasa.ini entries
|
86
|
-
|
87
|
-
#------------------------------------------------------------------------------
|
88
|
-
# Load Picasa's contacts.xml and .picasa.ini files.
|
89
|
-
# Inputs: 0) ExifTool object reference, 1) .picasa.ini directory
|
90
|
-
# Returns: 1 if files were loaded and parsed, undef on error
|
91
|
-
# Notes: If file has already been loaded, it isn't reloaded
|
92
|
-
sub LoadPicasaFiles($$)
|
93
|
-
{
|
94
|
-
local (*CONTACTS, *INI);
|
95
|
-
my ($et, $iniDir) = @_;
|
96
|
-
|
97
|
-
# check ExifTool version to see if there might be
|
98
|
-
# a command line setting for the contact file
|
99
|
-
my $contactFile = ($Image::ExifTool::VERSION >= 9.89 and
|
100
|
-
defined($et->Options(UserParam => 'PicasaContactsFile'))) ?
|
101
|
-
$et->Options(UserParam => 'PicasaContactsFile') : $contactXML;
|
102
|
-
|
103
|
-
# load Picasa contacts.xml file unless done already
|
104
|
-
unless ($contactFile eq $lastContactFile) {
|
105
|
-
$lastContactFile = $contactFile;
|
106
|
-
undef %contactHash;
|
107
|
-
# Picasa's default setting for unnamed faces.
|
108
|
-
$contactHash{'ffffffffffffffff'} = 'unnamed';
|
109
|
-
if (open(CONTACTS, $contactFile)) {
|
110
|
-
require Image::ExifTool::HTML;
|
111
|
-
while (<CONTACTS>) {
|
112
|
-
/name="(.*?)"/ or next;
|
113
|
-
my $name = $1;
|
114
|
-
/id="([a-f0-9]+)"/ or next;
|
115
|
-
my $id = $1;
|
116
|
-
$contactHash{$id} = Image::ExifTool::HTML::UnescapeHTML($name);
|
117
|
-
}
|
118
|
-
close(CONTACTS);
|
119
|
-
} else {
|
120
|
-
local $SIG{'__WARN__'} = undef; # stop ExifTool from catching the warning
|
121
|
-
warn "Error reading contacts file $contactFile\n";
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
# load .picasa.ini file from the specified directory
|
126
|
-
my $iniFile = "$iniDir/.picasa.ini";
|
127
|
-
|
128
|
-
if ($iniFile eq $lastIniFile) {
|
129
|
-
return %fileHash ? 1 : undef;
|
130
|
-
}
|
131
|
-
$lastIniFile = $iniFile;
|
132
|
-
open(INI, $iniFile) or return undef;
|
133
|
-
my $section = '';
|
134
|
-
while (<INI>) {
|
135
|
-
# Process New Section
|
136
|
-
/^\s*\[(.+)\][\n\r]*$/ and $section = $1, next;
|
137
|
-
# process entry (all we care about are the "faces" lines)
|
138
|
-
/^faces=(.*)$/ or next;
|
139
|
-
my @temp = split /;/, $1;
|
140
|
-
foreach (@temp) {
|
141
|
-
/rect64\(([\da-f]{1,16})\),([\da-f]{1,16})/ or next;
|
142
|
-
# the string in parens after "rect64" is a 64 bit number in hex,
|
143
|
-
# but Picasa doesn't add leading zeroes, so the length of the string
|
144
|
-
# cannot be assumed to be 16 bytes. Handle this as two 32-bit numbers
|
145
|
-
# for compatibility with 32-bit systems.
|
146
|
-
my $hi = hex(substr($1, 0, -8));
|
147
|
-
my $lo = hex(substr($1, -8));
|
148
|
-
my $x0 = ($hi >> 16) /65535;
|
149
|
-
my $y0 = ($hi & 0xffff)/65535;
|
150
|
-
my $x1 = ($lo >> 16) /65535;
|
151
|
-
my $y1 = ($lo & 0xffff)/65535;
|
152
|
-
push @{ $fileHash{$section} }, {
|
153
|
-
ContactID => $2,
|
154
|
-
X => $x0,
|
155
|
-
Y => $y0,
|
156
|
-
W => $x1 - $x0,
|
157
|
-
H => $y1 - $y0,
|
158
|
-
};
|
159
|
-
}
|
160
|
-
}
|
161
|
-
close(INI);
|
162
|
-
return %fileHash ? 1 : undef;
|
163
|
-
}
|
164
|
-
|
165
|
-
#------------------------------------------------------------------------------
|
166
|
-
# Rotate region to specified orientation (for RAW file types only)
|
167
|
-
# Input: 0) rectangle array ref (x,y,w,h), 1) EXIF orientation value, 2) file type
|
168
|
-
sub RotateRegion($$$)
|
169
|
-
{
|
170
|
-
my ($rect, $orientation, $fileType) = @_;
|
171
|
-
if ($orientation and $fileType and $isRawFile{$fileType}) {
|
172
|
-
my ($x,$y,$w,$h) = @$rect;
|
173
|
-
if ($orientation == 8) { # CW 90
|
174
|
-
@$rect = (1-$h-$y, $x, $h, $w);
|
175
|
-
} elsif ($orientation == 3) { # CW 180
|
176
|
-
@$rect = (1-$x-$w, 1-$y-$h, $w, $h);
|
177
|
-
} elsif ($orientation == 6) { # CW 270
|
178
|
-
@$rect = ($y, 1-$x-$w, $h, $w);
|
179
|
-
}
|
180
|
-
}
|
181
|
-
}
|
182
|
-
|
183
|
-
#------------------------------------------------------------------------------
|
184
|
-
# Rounds number to 9 decimal places, which is the limit to the number of decimal places that Picasa can read.
|
185
|
-
sub Rounded
|
186
|
-
{
|
187
|
-
my $DecAcc = 10**9;
|
188
|
-
return(int($_[0]*$DecAcc+.5)/$DecAcc);
|
189
|
-
}
|
190
|
-
|
191
|
-
#------------------------------------------------------------------------------
|
192
|
-
# User-defined tag definitions
|
193
|
-
#
|
194
|
-
%Image::ExifTool::UserDefined = (
|
195
|
-
'Image::ExifTool::Composite' => {
|
196
|
-
#
|
197
|
-
# Versions that filter out unnamed regions (ContactID=ffffffffffffffff)
|
198
|
-
#
|
199
|
-
PicasaToMWGRegion => {
|
200
|
-
Require => {
|
201
|
-
0 => 'Directory',
|
202
|
-
1 => 'FileName',
|
203
|
-
2 => 'ImageWidth',
|
204
|
-
3 => 'ImageHeight',
|
205
|
-
},
|
206
|
-
Desire => {
|
207
|
-
4 => 'Orientation',
|
208
|
-
5 => 'FileType',
|
209
|
-
},
|
210
|
-
ValueConv => sub {
|
211
|
-
my ($val, $et) = @_;
|
212
|
-
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
213
|
-
my $filename = $$val[1];
|
214
|
-
my @regList;
|
215
|
-
# convert to local variables for readability, and make
|
216
|
-
# sure there is a region associated with the current file
|
217
|
-
my $contactHashRef = \%contactHash;
|
218
|
-
my $tempArrayRef = $fileHash{$filename} or return undef;
|
219
|
-
foreach my $tempHash (@$tempArrayRef) {
|
220
|
-
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
|
221
|
-
my $name = $$contactHashRef{$$tempHash{ContactID}};
|
222
|
-
next unless defined $name;
|
223
|
-
my @rect = @$tempHash{'X','Y','W','H'};
|
224
|
-
RotateRegion(\@rect, $$val[4], $$val[5]);
|
225
|
-
push @regList, {
|
226
|
-
Area => {
|
227
|
-
X => Rounded($rect[0] + $rect[2] / 2),
|
228
|
-
Y => Rounded($rect[1] + $rect[3] / 2),
|
229
|
-
W => Rounded($rect[2]),
|
230
|
-
H => Rounded($rect[3]),
|
231
|
-
Unit => 'normalized',
|
232
|
-
},
|
233
|
-
Name => $name,
|
234
|
-
Type => 'Face',
|
235
|
-
};
|
236
|
-
}
|
237
|
-
# make sure a region exists, otherwise return undef
|
238
|
-
return @regList ? {
|
239
|
-
AppliedToDimensions => { W => $$val[2], H => $$val[3], Unit => 'pixel' },
|
240
|
-
RegionList => \@regList,
|
241
|
-
} : undef;
|
242
|
-
},
|
243
|
-
},
|
244
|
-
PicasaToMPRegion => {
|
245
|
-
Require => {
|
246
|
-
0 => 'Directory',
|
247
|
-
1 => 'FileName',
|
248
|
-
},
|
249
|
-
Desire => {
|
250
|
-
2 => 'Orientation',
|
251
|
-
3 => 'FileType',
|
252
|
-
},
|
253
|
-
ValueConv => sub {
|
254
|
-
my ($val, $et) = @_;
|
255
|
-
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
256
|
-
my $filename = $$val[1];
|
257
|
-
my @regList;
|
258
|
-
# convert to local variables for readability, and make
|
259
|
-
# sure there is a region associated with the current file
|
260
|
-
my $contactHashRef = \%contactHash;
|
261
|
-
my $tempArrayRef = $fileHash{$filename} or return undef;
|
262
|
-
foreach my $tempHash (@$tempArrayRef) {
|
263
|
-
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
|
264
|
-
my $name = $$contactHashRef{$$tempHash{ContactID}};
|
265
|
-
next unless defined $name;
|
266
|
-
my @rect = @$tempHash{'X','Y','W','H'};
|
267
|
-
RotateRegion(\@rect, $$val[2], $$val[3]);
|
268
|
-
@rect = map {Rounded($_)} @rect;
|
269
|
-
push @regList, {
|
270
|
-
PersonDisplayName => $name,
|
271
|
-
Rectangle => join(', ', @rect),
|
272
|
-
};
|
273
|
-
}
|
274
|
-
# make sure a region exists, otherwise return undef
|
275
|
-
return @regList ? { Regions => \@regList } : undef;
|
276
|
-
},
|
277
|
-
},
|
278
|
-
PicasaRegionNames => {
|
279
|
-
Require => {
|
280
|
-
0 => 'Directory',
|
281
|
-
1 => 'FileName',
|
282
|
-
},
|
283
|
-
ValueConv => sub {
|
284
|
-
my ($val, $et) = @_;
|
285
|
-
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
286
|
-
my $filename = $$val[1];
|
287
|
-
my @regList;
|
288
|
-
# convert to local variables for readability, and make
|
289
|
-
# sure there is a region associated with the current file
|
290
|
-
my $contactHashRef = \%contactHash;
|
291
|
-
my $tempArrayRef = $fileHash{$filename} or return undef;
|
292
|
-
foreach my $tempHash (@$tempArrayRef) {
|
293
|
-
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
|
294
|
-
my $name = $$contactHashRef{$$tempHash{ContactID}};
|
295
|
-
push @regList, $name if defined $name;
|
296
|
-
}
|
297
|
-
# make sure a region exists, otherwise return undef
|
298
|
-
return @regList ? \@regList : undef;
|
299
|
-
},
|
300
|
-
},
|
301
|
-
#
|
302
|
-
# Versions that do not filter out unnamed regions (ContactID=ffffffffffffffff)
|
303
|
-
# Picasa normally does not add these regions when it saves names to the file.
|
304
|
-
#
|
305
|
-
PicasaToMWGRegionUnfiltered => {
|
306
|
-
Require => {
|
307
|
-
0 => 'Directory',
|
308
|
-
1 => 'FileName',
|
309
|
-
2 => 'ImageWidth',
|
310
|
-
3 => 'ImageHeight',
|
311
|
-
},
|
312
|
-
Desire => {
|
313
|
-
4 => 'Orientation',
|
314
|
-
5 => 'FileType',
|
315
|
-
},
|
316
|
-
ValueConv => sub {
|
317
|
-
my ($val, $et) = @_;
|
318
|
-
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
319
|
-
my $filename = $$val[1];
|
320
|
-
my @regList;
|
321
|
-
# convert to local variables for readability, and make
|
322
|
-
# sure there is a region associated with the current file
|
323
|
-
my $contactHashRef = \%contactHash;
|
324
|
-
my $tempArrayRef = $fileHash{$filename} or return undef;
|
325
|
-
foreach my $tempHash (@$tempArrayRef) {
|
326
|
-
my @rect = @$tempHash{'X','Y','W','H'};
|
327
|
-
RotateRegion(\@rect, $$val[4], $$val[5]);
|
328
|
-
push @regList, {
|
329
|
-
Area => {
|
330
|
-
X => Rounded($rect[0] + $rect[2] / 2),
|
331
|
-
Y => Rounded($rect[1] + $rect[3] / 2),
|
332
|
-
W => Rounded($rect[2]),
|
333
|
-
H => Rounded($rect[3]),
|
334
|
-
Unit => 'normalized',
|
335
|
-
},
|
336
|
-
Name => $$contactHashRef{$$tempHash{ContactID}} || 'unnamed',
|
337
|
-
Type => 'Face',
|
338
|
-
};
|
339
|
-
}
|
340
|
-
# make sure a region exists, otherwise return undef
|
341
|
-
return @regList ? {
|
342
|
-
AppliedToDimensions => { W => $$val[2], H => $$val[3], Unit => 'pixel' },
|
343
|
-
RegionList => \@regList,
|
344
|
-
} : undef;
|
345
|
-
},
|
346
|
-
},
|
347
|
-
PicasaToMPRegionUnfiltered => {
|
348
|
-
Require => {
|
349
|
-
0 => 'Directory',
|
350
|
-
1 => 'FileName',
|
351
|
-
},
|
352
|
-
Desire => {
|
353
|
-
2 => 'Orientation',
|
354
|
-
3 => 'FileType',
|
355
|
-
},
|
356
|
-
ValueConv => sub {
|
357
|
-
my ($val, $et) = @_;
|
358
|
-
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
359
|
-
my $filename = $$val[1];
|
360
|
-
my @regList;
|
361
|
-
# convert to local variables for readability, and make
|
362
|
-
# sure there is a region associated with the current file
|
363
|
-
my $contactHashRef = \%contactHash;
|
364
|
-
my $tempArrayRef = $fileHash{$filename} or return undef;
|
365
|
-
foreach my $tempHash (@$tempArrayRef) {
|
366
|
-
my @rect = @$tempHash{'X','Y','W','H'};
|
367
|
-
RotateRegion(\@rect, $$val[2], $$val[3]);
|
368
|
-
@rect = map {Rounded($_)} @rect;
|
369
|
-
push @regList, {
|
370
|
-
PersonDisplayName => $$contactHashRef{$$tempHash{ContactID}} || 'unnamed',
|
371
|
-
Rectangle => join(', ', @rect),
|
372
|
-
}
|
373
|
-
}
|
374
|
-
# make sure a region exists, otherwise return undef
|
375
|
-
return @regList ? { Regions => \@regList } : undef;
|
376
|
-
},
|
377
|
-
},
|
378
|
-
},
|
379
|
-
);
|
380
|
-
|
381
|
-
#------------------------------------------------------------------------------
|
382
|
-
1; #end
|
1
|
+
#------------------------------------------------------------------------------
|
2
|
+
# File: picasa_faces.config
|
3
|
+
#
|
4
|
+
# Description: User-defined Composite tag definitions to convert face regions
|
5
|
+
# in .picasa.ini files to MWG region tags (Metadata Working Group
|
6
|
+
# region, used by Picasa) and MP region tags (used by Microsoft
|
7
|
+
# Photo Library).
|
8
|
+
#
|
9
|
+
# Tag definitions and examples:
|
10
|
+
#
|
11
|
+
# PicasaToMWGRegion
|
12
|
+
# This will create the MWG region tag but will filter out the regions
|
13
|
+
# that are still unnamed in Picasa. Picasa defaults to naming these
|
14
|
+
# regions 'ffffffffffffffff' but normally will not save these to file.
|
15
|
+
# Example:
|
16
|
+
# exiftool -config picasa_faces.config "-RegionInfo<PicasaToMWGRegion" FILE
|
17
|
+
#
|
18
|
+
# PicasaToMPRegion
|
19
|
+
# This will create the MP region tag but will filter out the regions that
|
20
|
+
# are still unnamed in Picasa. Picasa defaults to naming these regions
|
21
|
+
# 'ffffffffffffffff' but normally will not save these to file.
|
22
|
+
# Example:
|
23
|
+
# exiftool -config picasa_faces.config "-RegionInfoMP<PicasaToMPRegion" FILE
|
24
|
+
#
|
25
|
+
# PicasaRegionNames
|
26
|
+
# Returns a list of the region names associated with the file. This
|
27
|
+
# allows copying of the region names to XMP:Subject and/or IPTC:Keywords.
|
28
|
+
# It also allows checking to see if regions need to be updated.
|
29
|
+
# Example:
|
30
|
+
# exiftool -config picasa_faces.config "-XMP:Subject<PicasaRegionNames" FILE
|
31
|
+
#
|
32
|
+
# PicasaToMWGRegionUnfiltered
|
33
|
+
# This will create the MWG region tag. This version does not filter out
|
34
|
+
# the unnamed regions. Picasa normally will filter out unnamed regions
|
35
|
+
# when it saves regions in the file.
|
36
|
+
# Example:
|
37
|
+
# exiftool -config picasa_faces.config "-RegionInfo<PicasaToMWGRegionUnfiltered" FILE
|
38
|
+
#
|
39
|
+
# PicasaToMPRegionUnfiltered
|
40
|
+
# This will create the MP region tag. This version does not filter out
|
41
|
+
# the unnamed regions. Picasa normally will filter out unnamed regions
|
42
|
+
# when it saves regions in the file.
|
43
|
+
# Example:
|
44
|
+
# exiftool -config picasa_faces.config "-RegionInfoMP<PicasaToMPRegionUnfiltered" FILE
|
45
|
+
#
|
46
|
+
# Notes: The face names are loaded from the Picasa contacts file, which
|
47
|
+
# defaults to:
|
48
|
+
#
|
49
|
+
# C:/Users/MainUser/AppData/Local/PicasaData/Google/Picasa2/contacts/contacts.xml
|
50
|
+
#
|
51
|
+
# The default contacts file may be changed by editing the value
|
52
|
+
# of $contactXML below, or on the command line with ExifTool 9.90
|
53
|
+
# or later via the -userParam option, eg:
|
54
|
+
# -userparam PicasaContactsFile=/path/to/contacts.xml
|
55
|
+
#
|
56
|
+
# Requires: ExifTool version 8.82 or later (9.90 or later for -userparam)
|
57
|
+
#
|
58
|
+
# Revisions: 2015/03/07 - Bryan K. Williams (aka StarGeek) Created
|
59
|
+
# 2015/03/12 - PH Minor changes, optimizations and reformatting
|
60
|
+
# 2015/05/11 - BKW Fix bug where Picasa writes region data for
|
61
|
+
# rotated NEF and CR2 images as if the orientation
|
62
|
+
# is not rotated.
|
63
|
+
# 2015/05/12 - PH Minor code tweaks
|
64
|
+
# 2015/10/26 - BKW Round off area sizes to 7 decimal places
|
65
|
+
# 2016/01/18 - BKW Improved rounding algorithm
|
66
|
+
# 2016/05/14 - BKW Increased rounding to 9 decimal places (Max Picasa accepts),
|
67
|
+
# moved rounding operation to subroutine
|
68
|
+
#
|
69
|
+
# References: http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,6354.0.html
|
70
|
+
#------------------------------------------------------------------------------
|
71
|
+
|
72
|
+
# Picasa contacts file name
|
73
|
+
my $contactXML = 'C:/Users/MainUser/AppData/Local/PicasaData/Google/Picasa2/contacts/contacts.xml';
|
74
|
+
|
75
|
+
# local variables
|
76
|
+
my $lastIniFile = ''; # path of last .picasa.ini file loaded
|
77
|
+
my $lastContactFile = ''; # path of last contacts.xml file loaded
|
78
|
+
|
79
|
+
# raw file types that need additional processing to get regions correct
|
80
|
+
my %isRawFile = map { $_ => 1 } qw(
|
81
|
+
3FR ARW CR2 CRW CS1 DCR DNG EIP ERF IIQ K25 KDC MEF MOS MRW NEF NRW
|
82
|
+
ORF PEF RAF RAW RW2 RWL SR2 SRF SRW X3F), 'Canon 1D RAW';
|
83
|
+
|
84
|
+
my %contactHash; # lookup for loaded contacts.xml entries
|
85
|
+
my %fileHash; # lookup for loaded .picasa.ini entries
|
86
|
+
|
87
|
+
#------------------------------------------------------------------------------
|
88
|
+
# Load Picasa's contacts.xml and .picasa.ini files.
|
89
|
+
# Inputs: 0) ExifTool object reference, 1) .picasa.ini directory
|
90
|
+
# Returns: 1 if files were loaded and parsed, undef on error
|
91
|
+
# Notes: If file has already been loaded, it isn't reloaded
|
92
|
+
sub LoadPicasaFiles($$)
|
93
|
+
{
|
94
|
+
local (*CONTACTS, *INI);
|
95
|
+
my ($et, $iniDir) = @_;
|
96
|
+
|
97
|
+
# check ExifTool version to see if there might be
|
98
|
+
# a command line setting for the contact file
|
99
|
+
my $contactFile = ($Image::ExifTool::VERSION >= 9.89 and
|
100
|
+
defined($et->Options(UserParam => 'PicasaContactsFile'))) ?
|
101
|
+
$et->Options(UserParam => 'PicasaContactsFile') : $contactXML;
|
102
|
+
|
103
|
+
# load Picasa contacts.xml file unless done already
|
104
|
+
unless ($contactFile eq $lastContactFile) {
|
105
|
+
$lastContactFile = $contactFile;
|
106
|
+
undef %contactHash;
|
107
|
+
# Picasa's default setting for unnamed faces.
|
108
|
+
$contactHash{'ffffffffffffffff'} = 'unnamed';
|
109
|
+
if (open(CONTACTS, $contactFile)) {
|
110
|
+
require Image::ExifTool::HTML;
|
111
|
+
while (<CONTACTS>) {
|
112
|
+
/name="(.*?)"/ or next;
|
113
|
+
my $name = $1;
|
114
|
+
/id="([a-f0-9]+)"/ or next;
|
115
|
+
my $id = $1;
|
116
|
+
$contactHash{$id} = Image::ExifTool::HTML::UnescapeHTML($name);
|
117
|
+
}
|
118
|
+
close(CONTACTS);
|
119
|
+
} else {
|
120
|
+
local $SIG{'__WARN__'} = undef; # stop ExifTool from catching the warning
|
121
|
+
warn "Error reading contacts file $contactFile\n";
|
122
|
+
}
|
123
|
+
}
|
124
|
+
|
125
|
+
# load .picasa.ini file from the specified directory
|
126
|
+
my $iniFile = "$iniDir/.picasa.ini";
|
127
|
+
|
128
|
+
if ($iniFile eq $lastIniFile) {
|
129
|
+
return %fileHash ? 1 : undef;
|
130
|
+
}
|
131
|
+
$lastIniFile = $iniFile;
|
132
|
+
open(INI, $iniFile) or return undef;
|
133
|
+
my $section = '';
|
134
|
+
while (<INI>) {
|
135
|
+
# Process New Section
|
136
|
+
/^\s*\[(.+)\][\n\r]*$/ and $section = $1, next;
|
137
|
+
# process entry (all we care about are the "faces" lines)
|
138
|
+
/^faces=(.*)$/ or next;
|
139
|
+
my @temp = split /;/, $1;
|
140
|
+
foreach (@temp) {
|
141
|
+
/rect64\(([\da-f]{1,16})\),([\da-f]{1,16})/ or next;
|
142
|
+
# the string in parens after "rect64" is a 64 bit number in hex,
|
143
|
+
# but Picasa doesn't add leading zeroes, so the length of the string
|
144
|
+
# cannot be assumed to be 16 bytes. Handle this as two 32-bit numbers
|
145
|
+
# for compatibility with 32-bit systems.
|
146
|
+
my $hi = hex(substr($1, 0, -8));
|
147
|
+
my $lo = hex(substr($1, -8));
|
148
|
+
my $x0 = ($hi >> 16) /65535;
|
149
|
+
my $y0 = ($hi & 0xffff)/65535;
|
150
|
+
my $x1 = ($lo >> 16) /65535;
|
151
|
+
my $y1 = ($lo & 0xffff)/65535;
|
152
|
+
push @{ $fileHash{$section} }, {
|
153
|
+
ContactID => $2,
|
154
|
+
X => $x0,
|
155
|
+
Y => $y0,
|
156
|
+
W => $x1 - $x0,
|
157
|
+
H => $y1 - $y0,
|
158
|
+
};
|
159
|
+
}
|
160
|
+
}
|
161
|
+
close(INI);
|
162
|
+
return %fileHash ? 1 : undef;
|
163
|
+
}
|
164
|
+
|
165
|
+
#------------------------------------------------------------------------------
|
166
|
+
# Rotate region to specified orientation (for RAW file types only)
|
167
|
+
# Input: 0) rectangle array ref (x,y,w,h), 1) EXIF orientation value, 2) file type
|
168
|
+
sub RotateRegion($$$)
|
169
|
+
{
|
170
|
+
my ($rect, $orientation, $fileType) = @_;
|
171
|
+
if ($orientation and $fileType and $isRawFile{$fileType}) {
|
172
|
+
my ($x,$y,$w,$h) = @$rect;
|
173
|
+
if ($orientation == 8) { # CW 90
|
174
|
+
@$rect = (1-$h-$y, $x, $h, $w);
|
175
|
+
} elsif ($orientation == 3) { # CW 180
|
176
|
+
@$rect = (1-$x-$w, 1-$y-$h, $w, $h);
|
177
|
+
} elsif ($orientation == 6) { # CW 270
|
178
|
+
@$rect = ($y, 1-$x-$w, $h, $w);
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
|
183
|
+
#------------------------------------------------------------------------------
|
184
|
+
# Rounds number to 9 decimal places, which is the limit to the number of decimal places that Picasa can read.
|
185
|
+
sub Rounded
|
186
|
+
{
|
187
|
+
my $DecAcc = 10**9;
|
188
|
+
return(int($_[0]*$DecAcc+.5)/$DecAcc);
|
189
|
+
}
|
190
|
+
|
191
|
+
#------------------------------------------------------------------------------
|
192
|
+
# User-defined tag definitions
|
193
|
+
#
|
194
|
+
%Image::ExifTool::UserDefined = (
|
195
|
+
'Image::ExifTool::Composite' => {
|
196
|
+
#
|
197
|
+
# Versions that filter out unnamed regions (ContactID=ffffffffffffffff)
|
198
|
+
#
|
199
|
+
PicasaToMWGRegion => {
|
200
|
+
Require => {
|
201
|
+
0 => 'Directory',
|
202
|
+
1 => 'FileName',
|
203
|
+
2 => 'ImageWidth',
|
204
|
+
3 => 'ImageHeight',
|
205
|
+
},
|
206
|
+
Desire => {
|
207
|
+
4 => 'Orientation',
|
208
|
+
5 => 'FileType',
|
209
|
+
},
|
210
|
+
ValueConv => sub {
|
211
|
+
my ($val, $et) = @_;
|
212
|
+
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
213
|
+
my $filename = $$val[1];
|
214
|
+
my @regList;
|
215
|
+
# convert to local variables for readability, and make
|
216
|
+
# sure there is a region associated with the current file
|
217
|
+
my $contactHashRef = \%contactHash;
|
218
|
+
my $tempArrayRef = $fileHash{$filename} or return undef;
|
219
|
+
foreach my $tempHash (@$tempArrayRef) {
|
220
|
+
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
|
221
|
+
my $name = $$contactHashRef{$$tempHash{ContactID}};
|
222
|
+
next unless defined $name;
|
223
|
+
my @rect = @$tempHash{'X','Y','W','H'};
|
224
|
+
RotateRegion(\@rect, $$val[4], $$val[5]);
|
225
|
+
push @regList, {
|
226
|
+
Area => {
|
227
|
+
X => Rounded($rect[0] + $rect[2] / 2),
|
228
|
+
Y => Rounded($rect[1] + $rect[3] / 2),
|
229
|
+
W => Rounded($rect[2]),
|
230
|
+
H => Rounded($rect[3]),
|
231
|
+
Unit => 'normalized',
|
232
|
+
},
|
233
|
+
Name => $name,
|
234
|
+
Type => 'Face',
|
235
|
+
};
|
236
|
+
}
|
237
|
+
# make sure a region exists, otherwise return undef
|
238
|
+
return @regList ? {
|
239
|
+
AppliedToDimensions => { W => $$val[2], H => $$val[3], Unit => 'pixel' },
|
240
|
+
RegionList => \@regList,
|
241
|
+
} : undef;
|
242
|
+
},
|
243
|
+
},
|
244
|
+
PicasaToMPRegion => {
|
245
|
+
Require => {
|
246
|
+
0 => 'Directory',
|
247
|
+
1 => 'FileName',
|
248
|
+
},
|
249
|
+
Desire => {
|
250
|
+
2 => 'Orientation',
|
251
|
+
3 => 'FileType',
|
252
|
+
},
|
253
|
+
ValueConv => sub {
|
254
|
+
my ($val, $et) = @_;
|
255
|
+
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
256
|
+
my $filename = $$val[1];
|
257
|
+
my @regList;
|
258
|
+
# convert to local variables for readability, and make
|
259
|
+
# sure there is a region associated with the current file
|
260
|
+
my $contactHashRef = \%contactHash;
|
261
|
+
my $tempArrayRef = $fileHash{$filename} or return undef;
|
262
|
+
foreach my $tempHash (@$tempArrayRef) {
|
263
|
+
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
|
264
|
+
my $name = $$contactHashRef{$$tempHash{ContactID}};
|
265
|
+
next unless defined $name;
|
266
|
+
my @rect = @$tempHash{'X','Y','W','H'};
|
267
|
+
RotateRegion(\@rect, $$val[2], $$val[3]);
|
268
|
+
@rect = map {Rounded($_)} @rect;
|
269
|
+
push @regList, {
|
270
|
+
PersonDisplayName => $name,
|
271
|
+
Rectangle => join(', ', @rect),
|
272
|
+
};
|
273
|
+
}
|
274
|
+
# make sure a region exists, otherwise return undef
|
275
|
+
return @regList ? { Regions => \@regList } : undef;
|
276
|
+
},
|
277
|
+
},
|
278
|
+
PicasaRegionNames => {
|
279
|
+
Require => {
|
280
|
+
0 => 'Directory',
|
281
|
+
1 => 'FileName',
|
282
|
+
},
|
283
|
+
ValueConv => sub {
|
284
|
+
my ($val, $et) = @_;
|
285
|
+
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
286
|
+
my $filename = $$val[1];
|
287
|
+
my @regList;
|
288
|
+
# convert to local variables for readability, and make
|
289
|
+
# sure there is a region associated with the current file
|
290
|
+
my $contactHashRef = \%contactHash;
|
291
|
+
my $tempArrayRef = $fileHash{$filename} or return undef;
|
292
|
+
foreach my $tempHash (@$tempArrayRef) {
|
293
|
+
next if $$tempHash{ContactID} eq 'ffffffffffffffff';
|
294
|
+
my $name = $$contactHashRef{$$tempHash{ContactID}};
|
295
|
+
push @regList, $name if defined $name;
|
296
|
+
}
|
297
|
+
# make sure a region exists, otherwise return undef
|
298
|
+
return @regList ? \@regList : undef;
|
299
|
+
},
|
300
|
+
},
|
301
|
+
#
|
302
|
+
# Versions that do not filter out unnamed regions (ContactID=ffffffffffffffff)
|
303
|
+
# Picasa normally does not add these regions when it saves names to the file.
|
304
|
+
#
|
305
|
+
PicasaToMWGRegionUnfiltered => {
|
306
|
+
Require => {
|
307
|
+
0 => 'Directory',
|
308
|
+
1 => 'FileName',
|
309
|
+
2 => 'ImageWidth',
|
310
|
+
3 => 'ImageHeight',
|
311
|
+
},
|
312
|
+
Desire => {
|
313
|
+
4 => 'Orientation',
|
314
|
+
5 => 'FileType',
|
315
|
+
},
|
316
|
+
ValueConv => sub {
|
317
|
+
my ($val, $et) = @_;
|
318
|
+
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
319
|
+
my $filename = $$val[1];
|
320
|
+
my @regList;
|
321
|
+
# convert to local variables for readability, and make
|
322
|
+
# sure there is a region associated with the current file
|
323
|
+
my $contactHashRef = \%contactHash;
|
324
|
+
my $tempArrayRef = $fileHash{$filename} or return undef;
|
325
|
+
foreach my $tempHash (@$tempArrayRef) {
|
326
|
+
my @rect = @$tempHash{'X','Y','W','H'};
|
327
|
+
RotateRegion(\@rect, $$val[4], $$val[5]);
|
328
|
+
push @regList, {
|
329
|
+
Area => {
|
330
|
+
X => Rounded($rect[0] + $rect[2] / 2),
|
331
|
+
Y => Rounded($rect[1] + $rect[3] / 2),
|
332
|
+
W => Rounded($rect[2]),
|
333
|
+
H => Rounded($rect[3]),
|
334
|
+
Unit => 'normalized',
|
335
|
+
},
|
336
|
+
Name => $$contactHashRef{$$tempHash{ContactID}} || 'unnamed',
|
337
|
+
Type => 'Face',
|
338
|
+
};
|
339
|
+
}
|
340
|
+
# make sure a region exists, otherwise return undef
|
341
|
+
return @regList ? {
|
342
|
+
AppliedToDimensions => { W => $$val[2], H => $$val[3], Unit => 'pixel' },
|
343
|
+
RegionList => \@regList,
|
344
|
+
} : undef;
|
345
|
+
},
|
346
|
+
},
|
347
|
+
PicasaToMPRegionUnfiltered => {
|
348
|
+
Require => {
|
349
|
+
0 => 'Directory',
|
350
|
+
1 => 'FileName',
|
351
|
+
},
|
352
|
+
Desire => {
|
353
|
+
2 => 'Orientation',
|
354
|
+
3 => 'FileType',
|
355
|
+
},
|
356
|
+
ValueConv => sub {
|
357
|
+
my ($val, $et) = @_;
|
358
|
+
LoadPicasaFiles($et, $$val[0]) or return undef; # load contacts.xml and Picasa.ini
|
359
|
+
my $filename = $$val[1];
|
360
|
+
my @regList;
|
361
|
+
# convert to local variables for readability, and make
|
362
|
+
# sure there is a region associated with the current file
|
363
|
+
my $contactHashRef = \%contactHash;
|
364
|
+
my $tempArrayRef = $fileHash{$filename} or return undef;
|
365
|
+
foreach my $tempHash (@$tempArrayRef) {
|
366
|
+
my @rect = @$tempHash{'X','Y','W','H'};
|
367
|
+
RotateRegion(\@rect, $$val[2], $$val[3]);
|
368
|
+
@rect = map {Rounded($_)} @rect;
|
369
|
+
push @regList, {
|
370
|
+
PersonDisplayName => $$contactHashRef{$$tempHash{ContactID}} || 'unnamed',
|
371
|
+
Rectangle => join(', ', @rect),
|
372
|
+
}
|
373
|
+
}
|
374
|
+
# make sure a region exists, otherwise return undef
|
375
|
+
return @regList ? { Regions => \@regList } : undef;
|
376
|
+
},
|
377
|
+
},
|
378
|
+
},
|
379
|
+
);
|
380
|
+
|
381
|
+
#------------------------------------------------------------------------------
|
382
|
+
1; #end
|