480
476
'%Y-%m-%d %H:%M:%S',
481
477
'%Y-%m-%dT%H:%M:%SZ')
483
_date_formats = ('%Y:%m:%d',)
485
479
def __init__(self, key, name, label, description, type, value, fvalue):
486
480
super(ExifTag, self).__init__(key, name, label,
487
481
description, type, value)
488
482
self.fvalue = fvalue
491
def _init_values(self):
492
# Initial conversion of the raw values to their corresponding python
494
if self.type in ('Short', 'Long', 'SLong', 'Rational', 'SRational'):
483
if type in ('Short', 'Long', 'SLong', 'Rational', 'SRational'):
495
484
# May contain multiple values
496
values = self.raw_value.split()
485
values = value.split()
497
486
if len(values) > 1:
498
# Make values a notifying list
499
values = map(self._convert_to_python, values)
500
self._value = NotifyingList(values)
501
self._value.register_listener(self)
488
map(lambda x: ExifTag._convert_to_python(x, type, fvalue), values)
503
self._value = self._convert_to_python(self.raw_value)
490
self._value = ExifTag._convert_to_python(value, type, fvalue)
505
492
def _get_value(self):
506
493
return self._value
508
495
def _set_value(self, new_value):
509
496
if self.metadata is not None:
510
if isinstance(new_value, (list, tuple)):
511
raw_values = map(self._convert_to_string, new_value)
512
raw_value = ' '.join(raw_values)
514
raw_value = self._convert_to_string(new_value)
497
raw_value = ExifTag._convert_to_string(new_value, self.type)
515
498
self.metadata._set_exif_tag_value(self.key, raw_value)
517
if isinstance(self._value, NotifyingList):
518
self._value.unregister_listener(self)
520
if isinstance(new_value, NotifyingList):
521
# Already a notifying list
522
self._value = new_value
523
self._value.register_listener(self)
524
elif isinstance(new_value, (list, tuple)):
525
# Make the values a notifying list
526
self._value = NotifyingList(new_value)
527
self._value.register_listener(self)
530
self._value = new_value
499
self._value = new_value
532
501
def _del_value(self):
533
502
if self.metadata is not None:
534
503
self.metadata._delete_exif_tag(self.key)
536
if isinstance(self._value, NotifyingList):
537
self._value.unregister_listener(self)
541
506
"""the value of the tag converted to its corresponding python type"""
542
507
value = property(fget=_get_value, fset=_set_value, fdel=_del_value,
545
def contents_changed(self):
547
Implementation of the L{ListenerInterface}.
548
React on changes to the list of values of the tag.
550
# self._value is a list of value and its contents changed.
551
self._set_value(self._value)
553
def _convert_to_python(self, value):
555
Convert one raw value to its corresponding python type.
511
def _convert_to_python(value, xtype, fvalue):
513
Convert a raw value to its corresponding python type.
557
515
@param value: the raw value to be converted
558
516
@type value: C{str}
517
@param xtype: the EXIF type of the value
519
@param fvalue: the value formatted as a human-readable string by exiv2
560
522
@return: the value converted to its corresponding python type
561
@rtype: depends on C{self.type} (DOCME)
523
@rtype: depends on xtype (DOCME)
563
525
@raise ExifValueError: if the conversion fails
565
if self.type == 'Ascii':
566
528
# The value may contain a Datetime
567
for format in self._datetime_formats:
529
for format in ExifTag._datetime_formats:
569
531
t = time.strptime(value, format)
570
532
except ValueError:
573
535
return datetime.datetime(*t[:6])
574
# Or a Date (e.g. Exif.GPSInfo.GPSDateStamp)
575
for format in self._date_formats:
577
t = time.strptime(value, format)
581
return datetime.date(*t[:3])
582
536
# Default to string
584
538
return unicode(value, 'utf-8')
585
539
except TypeError:
586
raise ExifValueError(value, self.type)
540
raise ExifValueError(value, xtype)
588
elif self.type == 'Byte':
542
elif xtype == 'Byte':
591
elif self.type == 'Short':
545
elif xtype == 'Short':
593
547
return int(value)
594
548
except ValueError:
595
raise ExifValueError(value, self.type)
549
raise ExifValueError(value, xtype)
597
elif self.type in ('Long', 'SLong'):
551
elif xtype in ('Long', 'SLong'):
599
553
return long(value)
600
554
except ValueError:
601
raise ExifValueError(value, self.type)
555
raise ExifValueError(value, xtype)
603
elif self.type in ('Rational', 'SRational'):
557
elif xtype in ('Rational', 'SRational'):
605
559
r = Rational.from_string(value)
606
560
except (ValueError, ZeroDivisionError):
607
raise ExifValueError(value, self.type)
561
raise ExifValueError(value, xtype)
609
if self.type == 'Rational' and r.numerator < 0:
610
raise ExifValueError(value, self.type)
563
if xtype == 'Rational' and r.numerator < 0:
564
raise ExifValueError(value, xtype)
613
elif self.type == 'Undefined':
567
elif xtype == 'Undefined':
615
return unicode(self.fvalue, 'utf-8')
569
return unicode(fvalue, 'utf-8')
616
570
except TypeError:
617
raise ExifValueError(self.fvalue, self.type)
619
raise ExifValueError(value, self.type)
621
def _convert_to_string(self, value):
571
raise ExifValueError(fvalue, xtype)
573
raise ExifValueError(value, xtype)
576
def _convert_to_string(value, xtype):
623
Convert one value to its corresponding string representation, suitable
578
Convert a value to its corresponding string representation, suitable to
626
581
@param value: the value to be converted
627
@type value: depends on C{self.type} (DOCME)
582
@type value: depends on xtype (DOCME)
583
@param xtype: the EXIF type of the value
629
586
@return: the value converted to its corresponding string representation
632
589
@raise ExifValueError: if the conversion fails
634
if self.type == 'Ascii':
635
592
if type(value) is datetime.datetime:
636
return value.strftime(self._datetime_formats[0])
593
return value.strftime('%Y:%m:%d %H:%M:%S')
637
594
elif type(value) is datetime.date:
638
if self.key == 'Exif.GPSInfo.GPSDateStamp':
640
return value.strftime(self._date_formats[0])
642
return value.strftime('%s 00:00:00' % self._date_formats[0])
595
return value.strftime('%Y:%m:%d 00:00:00')
643
596
elif type(value) is unicode:
645
598
return value.encode('utf-8')
646
599
except UnicodeEncodeError:
647
raise ExifValueError(value, self.type)
600
raise ExifValueError(value, xtype)
648
601
elif type(value) is str:
651
raise ExifValueError(value, self.type)
604
raise ExifValueError(value, xtype)
653
elif self.type == 'Byte':
606
elif xtype == 'Byte':
654
607
if type(value) is unicode:
656
609
return value.encode('utf-8')
657
610
except UnicodeEncodeError:
658
raise ExifValueError(value, self.type)
611
raise ExifValueError(value, xtype)
659
612
elif type(value) is str:
662
raise ExifValueError(value, self.type)
615
raise ExifValueError(value, xtype)
664
elif self.type == 'Short':
617
elif xtype == 'Short':
665
618
if type(value) is int and value >= 0:
666
619
return str(value)
668
raise ExifValueError(value, self.type)
621
raise ExifValueError(value, xtype)
670
elif self.type == 'Long':
623
elif xtype == 'Long':
671
624
if type(value) in (int, long) and value >= 0:
672
625
return str(value)
674
raise ExifValueError(value, self.type)
627
raise ExifValueError(value, xtype)
676
elif self.type == 'SLong':
629
elif xtype == 'SLong':
677
630
if type(value) in (int, long):
678
631
return str(value)
680
raise ExifValueError(value, self.type)
633
raise ExifValueError(value, xtype)
682
elif self.type == 'Rational':
635
elif xtype == 'Rational':
683
636
if type(value) is Rational and value.numerator >= 0:
684
637
return str(value)
686
raise ExifValueError(value, self.type)
639
raise ExifValueError(value, xtype)
688
elif self.type == 'SRational':
641
elif xtype == 'SRational':
689
642
if type(value) is Rational:
690
643
return str(value)
692
raise ExifValueError(value, self.type)
645
raise ExifValueError(value, xtype)
694
elif self.type == 'Undefined':
647
elif xtype == 'Undefined':
695
648
if type(value) is unicode:
697
650
return value.encode('utf-8')
698
651
except UnicodeEncodeError:
699
raise ExifValueError(value, self.type)
652
raise ExifValueError(value, xtype)
700
653
elif type(value) is str:
703
raise ExifValueError(value, self.type)
656
raise ExifValueError(value, xtype)
705
raise ExifValueError(value, self.type)
658
raise ExifValueError(value, xtype)
707
660
def to_string(self):