Image-ExifTool
view release on metacpan or search on metacpan
lib/Image/ExifTool/VCard.pm view on Meta::CPAN
#------------------------------------------------------------------------------
# File: VCard.pm
#
# Description: Read vCard and iCalendar meta information
#
# Revisions: 2015/04/05 - P. Harvey Created
# 2015/05/02 - PH Added iCalendar support
#
# References: 1) http://en.m.wikipedia.org/wiki/VCard
# 2) http://tools.ietf.org/html/rfc6350
# 3) http://tools.ietf.org/html/rfc5545
#------------------------------------------------------------------------------
package Image::ExifTool::VCard;
use strict;
use vars qw($VERSION);
use Image::ExifTool qw(:DataAccess :Utils);
$VERSION = '1.07';
my %unescapeVCard = ( '\\'=>'\\', ','=>',', 'n'=>"\n", 'N'=>"\n" );
# lookup for iCalendar components (used to generate family 1 group names if top level)
my %isComponent = ( Event=>1, Todo=>1, Journal=>1, Freebusy=>1, Timezone=>1, Alarm=>1 );
my %timeInfo = (
# convert common date/time formats to EXIF style
ValueConv => q{
$val =~ s/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z?)/$1:$2:$3 $4:$5:$6$7/g;
$val =~ s/(\d{4})(\d{2})(\d{2})/$1:$2:$3/g;
$val =~ s/(\d{4})-(\d{2})-(\d{2})/$1:$2:$3/g;
return $val;
},
PrintConv => '$self->ConvertDateTime($val)',
);
# vCard tags (ref 1/2/PH)
# Note: The case of all tag ID's is normalized to lowercase with uppercase first letter
%Image::ExifTool::VCard::Main = (
GROUPS => { 2 => 'Document' },
VARS => { NO_LOOKUP => 1 }, # omit tags from lookup
NOTES => q{
This table lists common vCard tags, but ExifTool will also extract any other
vCard tags found. Tag names may have "Pref" added to indicate the preferred
instance of a vCard property, and other "TYPE" parameters may also added to
the tag name. VCF files may contain multiple vCard entries which are
distinguished by the ExifTool family 3 group name (document number). See
L<http://tools.ietf.org/html/rfc6350> for the vCard 4.0 specification.
},
Version => { Name => 'VCardVersion', Description => 'VCard Version' },
Fn => { Name => 'FormattedName', Groups => { 2 => 'Author' } },
N => { Name => 'Name', Groups => { 2 => 'Author' } },
Bday => { Name => 'Birthday', Groups => { 2 => 'Time' }, %timeInfo },
Tz => { Name => 'TimeZone', Groups => { 2 => 'Time' } },
Adr => { Name => 'Address', Groups => { 2 => 'Location' } },
Geo => {
Name => 'Geolocation',
Groups => { 2 => 'Location' },
# when used as a parameter, VCard 4.0 adds a "geo:" prefix that we need to remove
ValueConv => '$val =~ s/^geo://; $val',
},
Anniversary => { },
Email => { },
Gender => { },
Impp => 'IMPP',
Lang => 'Language',
Logo => { },
Nickname => { },
Note => { },
Org => 'Organization',
Photo => { Groups => { 2 => 'Preview' } },
Prodid => 'Software',
Rev => 'Revision',
Sound => { },
Tel => 'Telephone',
Title => 'JobTitle',
Uid => 'UID',
Url => 'URL',
'X-ablabel' => { Name => 'ABLabel', PrintConv => '$val =~ s/^_\$!<(.*)>!\$_$/$1/; $val' },
'X-abdate' => { Name => 'ABDate', Groups => { 2 => 'Time' }, %timeInfo },
'X-aim' => 'AIM',
'X-icq' => 'ICQ',
'X-abuid' => 'AB_UID',
'X-abrelatednames' => 'ABRelatedNames',
'X-socialprofile' => 'SocialProfile',
);
%Image::ExifTool::VCard::VCalendar = (
GROUPS => { 1 => 'VCalendar', 2 => 'Document' },
VARS => {
NO_LOOKUP => 1, # omit tags from lookup
LONG_TAGS => 6, # some X-microsoft tags have unavoidably long ID's
},
NOTES => q{
The VCard module is also used to process iCalendar ICS files since they use
a format similar to vCard. The following table lists standard iCalendar
tags, but any existing tags will be extracted. Top-level iCalendar
components (eg. Event, Todo, Timezone, etc.) are used for the family 1 group
names, and embedded components (eg. Alarm) are added as a prefix to the tag
name. See L<http://tools.ietf.org/html/rfc5545> for the official iCalendar
2.0 specification.
},
Version => { Name => 'VCalendarVersion', Description => 'VCalendar Version' },
Calscale => 'CalendarScale',
Method => { },
Prodid => 'Software',
Attach => 'Attachment',
Categories => { },
Class => 'Classification',
Comment => { },
Description => { },
Geo => {
Name => 'Geolocation',
Groups => { 2 => 'Location' },
ValueConv => '$val =~ s/^geo://; $val',
},
Location => { Name => 'Location', Groups => { 2 => 'Location' } },
'Percent-complete' => 'PercentComplete',
Priority => { },
Resources => { },
Status => { },
Summary => { },
Completed => { Name => 'DateTimeCompleted', Groups => { 2 => 'Time' }, %timeInfo },
Dtend => { Name => 'DateTimeEnd', Groups => { 2 => 'Time' }, %timeInfo },
Due => { Name => 'DateTimeDue', Groups => { 2 => 'Time' }, %timeInfo },
Dtstart => { Name => 'DateTimeStart', Groups => { 2 => 'Time' }, %timeInfo },
Duration => { },
Freebusy => 'FreeBusyTime',
Transp => 'TimeTransparency',
Tzid => { Name => 'TimezoneID', Groups => { 2 => 'Time' } },
Tzname => { Name => 'TimezoneName', Groups => { 2 => 'Time' } },
Tzoffsetfrom=> { Name => 'TimezoneOffsetFrom', Groups => { 2 => 'Time' } },
Tzoffsetto => { Name => 'TimezoneOffsetTo', Groups => { 2 => 'Time' } },
Tzurl => { Name => 'TimeZoneURL', Groups => { 2 => 'Time' } },
Attendee => { },
Contact => { },
Organizer => { },
'Recurrence-id' => 'RecurrenceID',
'Related-to' => 'RelatedTo',
Url => 'URL',
Uid => 'UID',
Exdate => { Name => 'ExceptionDateTimes', Groups => { 2 => 'Time' }, %timeInfo },
Rdate => { Name => 'RecurrenceDateTimes', Groups => { 2 => 'Time' }, %timeInfo },
Rrule => { Name => 'RecurrenceRule', Groups => { 2 => 'Time' } },
Action => { },
Repeat => { },
Trigger => { },
Created => { Name => 'DateCreated', Groups => { 2 => 'Time' }, %timeInfo },
Dtstamp => { Name => 'DateTimeStamp', Groups => { 2 => 'Time' }, %timeInfo },
'Last-modified' => { Name => 'ModifyDate', Groups => { 2 => 'Time' }, %timeInfo },
Sequence => 'SequenceNumber',
'Request-status' => 'RequestStatus',
Acknowledged=> { Name => 'Acknowledged', Groups => { 2 => 'Time' }, %timeInfo },
#
# Observed X-tags (not a comprehensive list):
#
'X-apple-calendar-color'=> 'CalendarColor',
'X-apple-default-alarm' => 'DefaultAlarm',
'X-apple-local-default-alarm' => 'LocalDefaultAlarm',
'X-microsoft-cdo-appt-sequence' => 'AppointmentSequence',
'X-microsoft-cdo-ownerapptid' => 'OwnerAppointmentID',
'X-microsoft-cdo-busystatus' => 'BusyStatus',
'X-microsoft-cdo-intendedstatus' => 'IntendedBusyStatus',
'X-microsoft-cdo-alldayevent' => 'AllDayEvent',
'X-microsoft-cdo-importance' => {
Name => 'Importance',
PrintConv => {
0 => 'Low',
1 => 'Normal',
2 => 'High',
},
},
'X-microsoft-cdo-insttype' => {
Name => 'InstanceType',
PrintConv => {
0 => 'Non-recurring Appointment',
1 => 'Recurring Appointment',
2 => 'Single Instance of Recurring Appointment',
3 => 'Exception to Recurring Appointment',
},
},
'X-microsoft-donotforwardmeeting' => 'DoNotForwardMeeting',
'X-microsoft-disallow-counter' => 'DisallowCounterProposal',
'X-microsoft-locations' => { Name => 'MeetingLocations', Groups => { 2 => 'Location' } },
'X-wr-caldesc' => 'CalendarDescription',
'X-wr-calname' => 'CalendarName',
'X-wr-relcalid' => 'CalendarID',
'X-wr-timezone' => { Name => 'TimeZone2', Groups => { 2 => 'Time' } },
'X-wr-alarmuid' => 'AlarmUID',
);
%Image::ExifTool::VCard::VNote = (
GROUPS => { 1 => 'VNote', 2 => 'Document' },
NOTES => 'Tags extracted from V-Note VNT files.',
Version => { },
Body => { },
Dcreated => { Name => 'CreateDate', Groups => { 2 => 'Time' }, %timeInfo },
'Last-modified' => { Name => 'ModifyDate', Groups => { 2 => 'Time' }, %timeInfo },
);
#------------------------------------------------------------------------------
# Get vCard tag, creating if necessary
# Inputs: 0) ExifTool ref, 1) tag table ref, 2) tag ID, 3) tag Name,
# 4) source tagInfo ref, 5) lang code
# Returns: tagInfo ref
sub GetVCardTag($$$$;$$)
{
my ($et, $tagTablePtr, $tag, $name, $srcInfo, $langCode) = @_;
my $tagInfo = $$tagTablePtr{$tag};
unless ($tagInfo) {
if ($srcInfo) {
$tagInfo = { %$srcInfo };
} else {
$tagInfo = { };
$et->VPrint(0, $$et{INDENT}, "[adding $tag]\n");
}
$$tagInfo{Name} = $name;
delete $$tagInfo{Description}; # create new description
AddTagToTable($tagTablePtr, $tag, $tagInfo);
}
# handle alternate languages (the "language" parameter)
$tagInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode) if $langCode;
( run in 0.638 second using v1.01-cache-2.11-cpan-39bf76dae61 )