Clean up of import section, added node category -- thanks Nick Hall. Cleanup of code.
svn: r17894
This commit is contained in:
parent
29d4daeec9
commit
58657454f5
@ -25,10 +25,10 @@
|
||||
# Python Modules
|
||||
# *****************************************************************************
|
||||
import os
|
||||
from datetime import datetime
|
||||
import datetime
|
||||
import calendar
|
||||
import time
|
||||
from PIL import Image, ImageEnhance, ImageFilter
|
||||
from PIL import Image
|
||||
|
||||
# abilty to escape certain characters from output...
|
||||
from xml.sax.saxutils import escape as _html_escape
|
||||
@ -55,7 +55,6 @@ from gen.ggettext import gettext as _
|
||||
|
||||
from DateHandler import displayer as _dd
|
||||
from DateHandler import parser as _dp
|
||||
from gen.lib.date import Date
|
||||
|
||||
from gen.plug import Gramplet
|
||||
|
||||
@ -71,81 +70,136 @@ from PlaceUtils import conv_lat_lon
|
||||
from gen.db import DbTxn
|
||||
|
||||
from ListModel import ListModel
|
||||
import pyexiv2
|
||||
|
||||
#####################################################################
|
||||
# Check for pyexiv2 library...
|
||||
#####################################################################
|
||||
# pyexiv2 download page (C) Olivier Tilloy
|
||||
_DOWNLOAD_LINK = "http://tilloy.net/dev/pyexiv2/download.html"
|
||||
|
||||
# make sure the pyexiv2 library is installed and at least a minimum version
|
||||
software_version = False
|
||||
Min_VERSION = (0, 1, 3)
|
||||
Min_VERSION_str = "pyexiv2-%d.%d.%d" % Min_VERSION
|
||||
Pref_VERSION_str = "pyexiv2-%d.%d.%d" % (0, 3, 0)
|
||||
|
||||
try:
|
||||
import pyexiv2
|
||||
software_version = pyexiv2.version_info
|
||||
|
||||
except ImportError, msg:
|
||||
WarningDialog(_("You need to install, %s or greater, for this addon to work...\n"
|
||||
"I would recommend installing, %s, and it may be downloaded from here: \n%s") % (
|
||||
Min_VERSION_str, Pref_VERSION_str, _DOWNLOAD_LINK), str(msg))
|
||||
raise Exception(_("Failed to load 'Edit Image Exif Metadata'..."))
|
||||
|
||||
# This only happends if the user has pyexiv2-0.1.3 installed on their computer...
|
||||
except AttributeError:
|
||||
software_version = pyexiv2.__version__
|
||||
|
||||
# v0.1 has a different API than v0.2 and above...
|
||||
# v0.1 has a different API to v0.2 and above
|
||||
if hasattr(pyexiv2, 'version_info'):
|
||||
LesserVersion = False
|
||||
OLD_API = False
|
||||
else:
|
||||
# version_info attribute does not exist prior to v0.2.0
|
||||
LesserVersion = True
|
||||
OLD_API = True
|
||||
|
||||
# the library is either not installed or does not meet minimum required version for this addon....
|
||||
if (software_version and (software_version < Min_VERSION)):
|
||||
msg = _("The minimum required version for pyexiv2 must be %s \n"
|
||||
"or greater. Or you do not have the python library installed yet. "
|
||||
"You may download it from here: %s\n\n I recommend getting, %s") % (
|
||||
Min_VERSION_str, _DOWNLOAD_LINK, Pref_VERSION_str)
|
||||
WarningDialog(msg)
|
||||
raise Exception(msg)
|
||||
# -----------------------------------------------
|
||||
# Support Functions
|
||||
# -----------------------------------------------
|
||||
def _format_datetime(exif_dt):
|
||||
"""
|
||||
Convert a python datetime object into a string for display, using the
|
||||
standard Gramps date format.
|
||||
"""
|
||||
if type(exif_dt) is not datetime:
|
||||
return ''
|
||||
|
||||
# check to make sure that exiv2 is installed and some kind of delete command...
|
||||
system_platform = os.sys.platform
|
||||
if system_platform == "Win32":
|
||||
EXIV2_OUND_ = "exiv2.exe" if Utils.search_for("exiv2.exe") else False
|
||||
elif system_platform == "linux2":
|
||||
EXIV2_FOUND_ = "exiv2" if Utils.search_for("exiv2") else False
|
||||
else:
|
||||
EXIV2_FOUND_ = "exiv2" if Utils.search_for("exiv2") else False
|
||||
date_part = gen.lib.date.Date()
|
||||
date_part.set_yr_mon_day(exif_dt.year, exif_dt.month, exif_dt.day)
|
||||
date_str = _dd.display(date_part)
|
||||
time_str = _('%(hr)02d:%(min)02d:%(sec)02d') % {'hr': exif_dt.hour,
|
||||
'min': exif_dt.minute,
|
||||
'sec': exif_dt.second}
|
||||
return _('%(date)s %(time)s') % {'date': date_str, 'time': time_str}
|
||||
|
||||
def _format_gps(tag_value):
|
||||
"""
|
||||
Convert a (degrees, minutes, seconds) tuple into a string for display.
|
||||
"""
|
||||
|
||||
return "%d° %02d' %05.2f\"" % (tag_value[0], tag_value[1], tag_value[2])
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Constants
|
||||
# -----------------------------------------------------------------------------
|
||||
# available image types for exiv2 and pyexiv2
|
||||
_vtypes = [".tiff", ".jpeg", ".png", ".exv", ".dng", ".bmp", ".nef", ".psd",
|
||||
".jp2", ".pef", ".srw", ".pgf"]
|
||||
_vtypes = [".jpeg", ".jpg", ".jfif", ".exv", ".dng", ".bmp", ".nef", ".png", ".psd",
|
||||
".jp2", ".pef", ".srw", ".pgf", ".tiff"]
|
||||
_vtypes.sort()
|
||||
_VTYPEMAP = dict( (index, imgtype_) for index, imgtype_ in enumerate(_vtypes) )
|
||||
_VALIDIMAGEMAP = dict( (index, imgtype_) for index, imgtype_ in enumerate(_vtypes) )
|
||||
|
||||
# valid converting types for PIL.Image...
|
||||
_validconvert = list( (_("-- Image Types --"), ".bmp", ".gif", ".jpg", ".msp",
|
||||
".pcx", ".png", ".ppm", ".tiff", ".xbm") )
|
||||
|
||||
DESCRIPTION = _("Description")
|
||||
ORIGIN = _("Origin")
|
||||
IMAGE = _('Image')
|
||||
CAMERA = _('Camera')
|
||||
GPS = _('GPS')
|
||||
ADVANCED = _("Advanced")
|
||||
|
||||
# All of the exiv2 tag reference...
|
||||
TAGS = [
|
||||
# Description subclass...
|
||||
(DESCRIPTION, 'Exif.Image.XPSubject', None, None),
|
||||
(DESCRIPTION, 'Exif.Image.Rating', None, None),
|
||||
(DESCRIPTION, 'Exif.Image.XPKeywords', None, None),
|
||||
(DESCRIPTION, 'Exif.Image.XPComment', None, None),
|
||||
|
||||
# Origin subclass...
|
||||
(ORIGIN, 'Exif.Image.Artist', None, None),
|
||||
(ORIGIN, 'Exif.Photo.DateTimeOriginal', None, _format_datetime),
|
||||
(ORIGIN, 'Exif.Photo.DateTimeDigitized', None, _format_datetime),
|
||||
(ORIGIN, 'Exif.Image.Software', None, None),
|
||||
(ORIGIN, 'Xmp.MicrosoftPhoto.DateAcquired', None, None),
|
||||
(ORIGIN, 'Exif.Image.Copyright', None, None),
|
||||
(ORIGIN, 'Exif.Image.TimeZoneOffset', None, None),
|
||||
(ORIGIN, 'Exif.Image.SubjectDistance', None, None),
|
||||
|
||||
# Image subclass...
|
||||
(IMAGE, 'Exif.Image.ImageDescription', None, None),
|
||||
(IMAGE, 'Exif.Photo.DateTimeOriginal', None, _format_datetime),
|
||||
(IMAGE, 'Exif.Photo.PixelXDimension', None, None),
|
||||
(IMAGE, 'Exif.Photo.PixelYDimension', None, None),
|
||||
(IMAGE, 'Exif.Image.Compression', None, None),
|
||||
(IMAGE, 'Exif.Image.DocumentName', None, None),
|
||||
(IMAGE, 'Exif.Image.Orientation', None, None),
|
||||
(IMAGE, 'Exif.Image.ImageID', None, None),
|
||||
(IMAGE, 'Exif.Photo.ExifVersion', None, None),
|
||||
|
||||
# Camera subclass...
|
||||
(CAMERA, 'Exif.Image.Make', None, None),
|
||||
(CAMERA, 'Exif.Image.Model', None, None),
|
||||
(CAMERA, 'Exif.Photo.FNumber', None, None),
|
||||
(CAMERA, 'Exif.Photo.ExposureTime', None, None),
|
||||
(CAMERA, 'Exif.Photo.ISOSpeedRatings', None, None),
|
||||
(CAMERA, 'Exif.Photo.FocalLength', None, None),
|
||||
(CAMERA, 'Exif.Photo.MeteringMode', None, None),
|
||||
(CAMERA, 'Exif.Photo.Flash', None, None),
|
||||
(CAMERA, 'Exif.Image.SelfTimerMode', None, None),
|
||||
(CAMERA, 'Exif.Image.CameraSerialNumber', None, None),
|
||||
|
||||
# GPS subclass...
|
||||
(GPS, 'Exif.GPSInfo.GPSLatitude',
|
||||
'Exif.GPSInfo.GPSLatitudeRef', _format_gps),
|
||||
(GPS, 'Exif.GPSInfo.GPSLongitude',
|
||||
'Exif.GPSInfo.GPSLongitudeRef', _format_gps),
|
||||
(GPS, 'Exif.GPSInfo.GPSAltitude',
|
||||
'Exif.GPSInfo.GPSAltitudeRef', None),
|
||||
(GPS, 'Exif.Image.GPSTag', None, None),
|
||||
(GPS, 'Exif.GPSInfo.GPSTimeStamp', None, _format_gps),
|
||||
(GPS, 'Exif.GPSInfo.GPSSatellites', None, None),
|
||||
|
||||
# Advanced subclass...
|
||||
(ADVANCED, 'Xmp.MicrosoftPhoto.LensManufacturer', None, None),
|
||||
(ADVANCED, 'Xmp.MicrosoftPhoto.LensModel', None, None),
|
||||
(ADVANCED, 'Xmp.MicrosoftPhoto.FlashManufacturer', None, None),
|
||||
(ADVANCED, 'Xmp.MicrosoftPhoto.FlashModel', None, None),
|
||||
(ADVANCED, 'Xmp.MicrosoftPhoto.CameraSerialNumber', None, None),
|
||||
(ADVANCED, 'Exif.Photo.Contrast', None, None),
|
||||
(ADVANCED, 'Exif.Photo.LightSource', None, None),
|
||||
(ADVANCED, 'Exif.Photo.ExposureProgram', None, None),
|
||||
(ADVANCED, 'Exif.Photo.Saturation', None, None),
|
||||
(ADVANCED, 'Exif.Photo.Sharpness', None, None),
|
||||
(ADVANCED, 'Exif.Photo.WhiteBalance', None, None),
|
||||
(ADVANCED, 'Exif.Image.ExifTag', None, None),
|
||||
(ADVANCED, 'Exif.Image.BatteryLevel', None, None) ]
|
||||
|
||||
# set up Exif keys for Image Exif metadata keypairs...
|
||||
_DATAMAP = {
|
||||
"Xmp.xmp.Label" : "ExifLabel",
|
||||
"Exif.Image.ImageDescription" : "Description",
|
||||
"Exif.Image.DateTime" : "Modified",
|
||||
"Exif.Image.Artist" : "Artist",
|
||||
"Exif.Image.Copyright" : "Copyright",
|
||||
"Exif.Photo.DateTimeOriginal" : "Original",
|
||||
"Exif.Photo.DateTimeDigitized" : "Digitized",
|
||||
"Xmp.xmp.ModifyDate" : "ModifyDate",
|
||||
"Exif.GPSInfo.GPSLatitudeRef" : "LatitudeRef",
|
||||
"Exif.GPSInfo.GPSLatitude" : "Latitude",
|
||||
"Exif.GPSInfo.GPSLongitudeRef" : "LongitudeRef",
|
||||
@ -158,9 +212,6 @@ _DATAMAP.update( (val, key) for key, val in _DATAMAP.items() )
|
||||
# define tooltips for all data entry fields...
|
||||
_TOOLTIPS = {
|
||||
|
||||
# Exif Label/ Title...
|
||||
"ExifLabel" : _("This is equivalent to the Title field in the media object editor."),
|
||||
|
||||
# Description...
|
||||
"Description" : _("Provide a short descripion for this image."),
|
||||
|
||||
@ -179,18 +230,17 @@ _TOOLTIPS = {
|
||||
"Original" : _("The original date/ time when the image was first created/ taken as in a photograph.\n"
|
||||
"Example: 1830-01-1 09:30:59"),
|
||||
|
||||
# GPS Latitude Coordinates...
|
||||
"Latitude" : _("Enter the Latitude GPS Coordinates for this image,\n"
|
||||
# GPS Latitude coordinates...
|
||||
"Latitude" : _("Enter the Latitude GPS coordinates for this image,\n"
|
||||
"Example: 43.722965, 43 43 22 N, 38° 38′ 03″ N, 38 38 3"),
|
||||
|
||||
# GPS Longitude Coordinates...
|
||||
"Longitude" : _("Enter the Longitude GPS Coordinates for this image,\n"
|
||||
# GPS Longitude coordinates...
|
||||
"Longitude" : _("Enter the Longitude GPS coordinates for this image,\n"
|
||||
"Example: 10.396378, 10 23 46 E, 105° 6′ 6″ W, -105 6 6"),
|
||||
|
||||
# GPS Altitude (in meters)...
|
||||
"Altitude" : _("This is the measurement of Above or Below Sea Level. It is measured in meters."
|
||||
"Example: 200.558, -200.558") }
|
||||
|
||||
_TOOLTIPS = dict( (key, tooltip) for key, tooltip in _TOOLTIPS.items() )
|
||||
|
||||
# define tooltips for all buttons...
|
||||
@ -246,14 +296,11 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
vbox = self.__build_gui()
|
||||
self.connect_signal("Media", self.update)
|
||||
self.connect_signal("media-update", self.update)
|
||||
|
||||
self.gui.get_container_widget().remove(self.gui.textview)
|
||||
self.gui.get_container_widget().add_with_viewport(vbox)
|
||||
|
||||
# display all button tooltips only...
|
||||
# 1st argument is for Fields, 2nd argument is for Buttons...
|
||||
self._setup_widget_tips([False, True])
|
||||
|
||||
def __build_gui(self):
|
||||
"""
|
||||
will display all exif metadata and all buttons.
|
||||
@ -350,12 +397,11 @@ class EditExifMetadata(Gramplet):
|
||||
hed_box.add( self.__create_button(
|
||||
"Edit", False, [self.display_edit_window], gtk.STOCK_EDIT) )
|
||||
|
||||
if EXIV2_FOUND_:
|
||||
# Delete All Metadata button...
|
||||
hed_box.add(self.__create_button(
|
||||
"Delete", False, [self.__wipe_dialog], gtk.STOCK_DELETE) )
|
||||
# Delete All Metadata button...
|
||||
hed_box.add(self.__create_button(
|
||||
"Delete", False, [self.__wipe_dialog], gtk.STOCK_DELETE) )
|
||||
|
||||
new_vbox = self.build_shaded_display()
|
||||
new_vbox = self.__build_shaded_display()
|
||||
main_vbox.pack_start(new_vbox, expand =False, fill =False, padding =10)
|
||||
|
||||
# number of key/value pairs shown...
|
||||
@ -378,12 +424,18 @@ class EditExifMetadata(Gramplet):
|
||||
*** disable all buttons at first, then activate as needed...
|
||||
# Help will never be disabled...
|
||||
"""
|
||||
|
||||
db = self.dbstate.db
|
||||
|
||||
# display all button tooltips only...
|
||||
# 1st argument is for Fields, 2nd argument is for Buttons...
|
||||
self._setup_widget_tips(fields =False, buttons =True)
|
||||
|
||||
# clears all labels and display area...
|
||||
for widgetname_ in ["MediaLabel", "MimeType", "ImageSize", "MessageArea", "Total"]:
|
||||
self.exif_widgets[widgetname_].set_text("")
|
||||
self.model.clear()
|
||||
self.sections = {}
|
||||
|
||||
# deactivate Convert and ImageType buttons...
|
||||
self.deactivate_buttons(["Convert", "ImageType"])
|
||||
@ -408,19 +460,16 @@ class EditExifMetadata(Gramplet):
|
||||
self.set_has_data(False)
|
||||
return
|
||||
|
||||
# display file description/ title...
|
||||
self.exif_widgets["MediaLabel"].set_text(_html_escape(self.orig_image.get_description() ) )
|
||||
|
||||
# Mime type information...
|
||||
mime_type = self.orig_image.get_mime_type()
|
||||
self.exif_widgets["MimeType"].set_text("%s, %s" % (
|
||||
mime_type, gen.mime.get_description(mime_type) ) )
|
||||
|
||||
# get dirpath/ basename, and extension...
|
||||
self.basename, self.extension = os.path.splitext(self.image_path)
|
||||
|
||||
# remove the extension out of the list of convertible image types...
|
||||
# What would make sense to be able to convert to your current image type?
|
||||
PILConvert = _validconvert
|
||||
if self.extension in PILConvert:
|
||||
PILConvert.remove(self.extension)
|
||||
self._VCONVERTMAP = dict( (index, imgtype_) for index, imgtype_ in enumerate(PILConvert) )
|
||||
|
||||
for imgtype_ in self._VCONVERTMAP.values():
|
||||
self.exif_widgets["ImageType"].append_text(imgtype_)
|
||||
self.exif_widgets["ImageType"].set_active(0)
|
||||
self._filepath_fname, self.extension = os.path.splitext(self.image_path)
|
||||
|
||||
# check image read privileges...
|
||||
_readable = os.access(self.image_path, os.R_OK)
|
||||
@ -436,28 +485,30 @@ class EditExifMetadata(Gramplet):
|
||||
"You will NOT be able to save Exif metadata...."))
|
||||
self.deactivate_buttons(["Edit"])
|
||||
|
||||
# Mime type information...
|
||||
mime_type = self.orig_image.get_mime_type()
|
||||
self.exif_widgets["MimeType"].set_text(gen.mime.get_description(mime_type))
|
||||
# if image file type is not an Exiv2 acceptable image type, offer to convert it....
|
||||
if self.extension not in _VALIDIMAGEMAP.values():
|
||||
|
||||
# if image file type is not an Exiv2 acceptable image type,
|
||||
# offer to convert it....
|
||||
if self.extension not in _VTYPEMAP.values():
|
||||
# remove the extension out of the list of convertible image types...
|
||||
# What would make sense to be able to convert to your current image type?
|
||||
PILConvert = _validconvert
|
||||
if self.extension in PILConvert:
|
||||
PILConvert.remove(self.extension)
|
||||
self._VCONVERTMAP = dict( (index, imgtype_) for index, imgtype_ in enumerate(PILConvert) )
|
||||
|
||||
for imgtype_ in self._VCONVERTMAP.values():
|
||||
self.exif_widgets["ImageType"].append_text(imgtype_)
|
||||
self.exif_widgets["ImageType"].set_active(0)
|
||||
self.activate_buttons(["ImageType"])
|
||||
|
||||
# determine if it is a mime image object?
|
||||
if mime_type:
|
||||
if mime_type.startswith("image"):
|
||||
|
||||
# display file description/ title...
|
||||
self.exif_widgets["MediaLabel"].set_text(_html_escape(
|
||||
self.orig_image.get_description() ) )
|
||||
|
||||
# creates, and reads the plugin image instance...
|
||||
self.plugin_image = self.setup_image(self.image_path)
|
||||
if self.plugin_image:
|
||||
|
||||
if LesserVersion: # prior to pyexiv2-0.2.0
|
||||
if OLD_API: # prior to pyexiv2-0.2.0
|
||||
try:
|
||||
ttype, tdata = self.plugin_image.getThumbnailData()
|
||||
width, height = tdata.dimensions
|
||||
@ -474,6 +525,11 @@ class EditExifMetadata(Gramplet):
|
||||
except (IOError, OSError):
|
||||
thumbnail = False
|
||||
|
||||
# get image width and height...
|
||||
self.exif_widgets["ImageSize"].show()
|
||||
width, height = self.plugin_image.dimensions
|
||||
self.exif_widgets["ImageSize"].set_text(_("Image Size : %04d x %04d pixels") % (width, height))
|
||||
|
||||
# if a thumbnail exists, then activate the buttton?
|
||||
if thumbnail:
|
||||
self.activate_buttons(["Thumbnail"])
|
||||
@ -482,12 +538,7 @@ class EditExifMetadata(Gramplet):
|
||||
self.activate_buttons(["Edit"])
|
||||
|
||||
# display all exif metadata...
|
||||
mediadatatags = _get_exif_keypairs(self.plugin_image)
|
||||
if mediadatatags:
|
||||
self.display_metadata(mediadatatags)
|
||||
else:
|
||||
# set Message Area to None...
|
||||
self.exif_widgets["MessageArea"].set_text(_("No Exif metadata for this image..."))
|
||||
self.display_metadata(self.orig_image)
|
||||
|
||||
# has mime, but not an image...
|
||||
else:
|
||||
@ -507,20 +558,19 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
# get convert image type and check it?
|
||||
ext_value = self.exif_widgets["ImageType"].get_active()
|
||||
if (self.extension not in _VTYPEMAP.values() and ext_value >= 1):
|
||||
if (self.extension not in _VALIDIMAGEMAP.values() and ext_value >= 1):
|
||||
|
||||
# if Convert button is not active, set it to active state
|
||||
# so that the user may convert this image?
|
||||
if not self.exif_widgets["Convert"].get_sensitive():
|
||||
self.activate_buttons(["Convert"])
|
||||
|
||||
def _setup_widget_tips(self, _ttypes):
|
||||
def _setup_widget_tips(self, fields =None, buttons =None):
|
||||
"""
|
||||
set up widget tooltips...
|
||||
* data fields
|
||||
* buttons
|
||||
"""
|
||||
fields, buttons = _ttypes
|
||||
|
||||
# if True, setup tooltips for all Data Entry Fields...
|
||||
if fields:
|
||||
@ -540,7 +590,7 @@ class EditExifMetadata(Gramplet):
|
||||
* setup the tooltips for the buttons,
|
||||
"""
|
||||
|
||||
if LesserVersion: # prior to pyexiv2-0.2.0
|
||||
if OLD_API: # prior to pyexiv2-0.2.0
|
||||
metadata = pyexiv2.Image(full_path)
|
||||
try:
|
||||
metadata.readMetadata()
|
||||
@ -576,7 +626,7 @@ class EditExifMetadata(Gramplet):
|
||||
if not os.path.isfile(full_path):
|
||||
return False
|
||||
|
||||
if LesserVersion: # prior to pyexiv2-0.2.0
|
||||
if OLD_API: # prior to pyexiv2-0.2.0
|
||||
metadata = pyexiv2.Image(full_path)
|
||||
try:
|
||||
metadata.readMetadata()
|
||||
@ -597,69 +647,81 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
return False
|
||||
|
||||
def display_metadata(self, mediadatatags_ =None):
|
||||
def display_metadata(self, media):
|
||||
"""
|
||||
displays all of the image's Exif metadata in a grey-shaded tree view...
|
||||
"""
|
||||
|
||||
# clear display area...
|
||||
self.model.clear()
|
||||
|
||||
# get All Exif metadata...
|
||||
metadatatags_ = _get_exif_keypairs(self.plugin_image)
|
||||
if not metadatatags_:
|
||||
self.exif_widgets["MessageArea"].set_text(_("No Exif metadata to display..."))
|
||||
self.exif_widgets["MessageArea"].set_text(_("No Exif metadata for this image..."))
|
||||
self.set_has_data(False)
|
||||
return
|
||||
|
||||
# clear display area...
|
||||
self.model.clear()
|
||||
|
||||
# set Message Area to Display...
|
||||
self.exif_widgets["MessageArea"].set_text(_("Displaying all Exif metadata keypairs..."))
|
||||
|
||||
if not LesserVersion: # pyexiv2-0.2.0 and above...
|
||||
# pylint: disable-msg=E1101
|
||||
full_path = Utils.media_path_full(self.dbstate.db, media.get_path())
|
||||
|
||||
if OLD_API: # prior to v0.2.0
|
||||
try:
|
||||
metadata = pyexiv2.Image(full_path)
|
||||
except IOError:
|
||||
self.set_has_data(False)
|
||||
return
|
||||
|
||||
# image Dimensions...
|
||||
self.exif_widgets["ImageSize"].show()
|
||||
width, height = self.plugin_image.dimensions
|
||||
self.exif_widgets["ImageSize"].set_text(_("Image Size : %04d x %04d pixels") % (width, height))
|
||||
metadata.readMetadata()
|
||||
for section, key, key2, func in TAGS:
|
||||
if key in metadata.exifKeys():
|
||||
if section not in self.sections:
|
||||
node = self.model.add([section, ''])
|
||||
self.sections[section] = node
|
||||
else:
|
||||
node = self.sections[section]
|
||||
label = metadata.tagDetails(key)[0]
|
||||
if func:
|
||||
human_value = func(metadata[key])
|
||||
else:
|
||||
human_value = metadata.interpretedExifValue(key)
|
||||
if key2:
|
||||
human_value += ' ' + metadata.interpretedExifValue(key2)
|
||||
self.model.add((label, human_value), node =node)
|
||||
self.model.tree.expand_all()
|
||||
|
||||
# Activate Delete button if ImageMagick or jhead is found?...
|
||||
else: # v0.2.0 and above
|
||||
metadata = pyexiv2.ImageMetadata(full_path)
|
||||
try:
|
||||
metadata.read()
|
||||
except IOError:
|
||||
self.set_has_data(False)
|
||||
return
|
||||
|
||||
for section, key, key2, func in TAGS:
|
||||
if key in metadatatags_:
|
||||
if section not in self.sections:
|
||||
node = self.model.add([section, ''])
|
||||
self.sections[section] = node
|
||||
else:
|
||||
node = self.sections[section]
|
||||
tag = metadata[key]
|
||||
if func:
|
||||
human_value = func(tag.value)
|
||||
else:
|
||||
human_value = tag.human_value
|
||||
if key2:
|
||||
human_value += ' ' + metadata[key2].human_value
|
||||
self.model.add((tag.label, human_value), node=node)
|
||||
self.model.tree.expand_all()
|
||||
|
||||
self.set_has_data(self.model.count > 0)
|
||||
|
||||
# activate Delete button...
|
||||
self.activate_buttons(["Delete"])
|
||||
|
||||
for keytag_ in metadatatags_:
|
||||
if LesserVersion: # prior to pyexiv2-0.2.0
|
||||
label = metadata.tagDetails(keytag_)[0]
|
||||
|
||||
# if keytag_ is one of the dates, display as the user wants it in preferences
|
||||
if keytag_ in [_DATAMAP["Modified"], _DATAMAP["Original"], _DATAMAP["Digitized"] ]:
|
||||
human_value = _format_datetime(self.plugin_image[keytag_])
|
||||
else:
|
||||
human_value = self.plugin_image.interpretedExifValue(keytag_)
|
||||
|
||||
else: # pyexiv2-0.2.0 and above
|
||||
tag = self.plugin_image[keytag_]
|
||||
|
||||
# if keytag_ is one of the dates, display as the user wants it in preferences
|
||||
if keytag_ in [_DATAMAP["Modified"], _DATAMAP["Original"], _DATAMAP["Digitized"] ]:
|
||||
_value = self._get_value(keytag_)
|
||||
if _value:
|
||||
label = tag.label
|
||||
human_value = _format_datetime(_value)
|
||||
else:
|
||||
human_value = False
|
||||
|
||||
elif ("Xmp" in keytag_ or "Iptc" in keytag_):
|
||||
label = self.plugin_image[keytag_]
|
||||
human_value = self._get_value(keytag_)
|
||||
|
||||
else:
|
||||
label = tag.label
|
||||
human_value = tag.human_value
|
||||
|
||||
if human_value:
|
||||
|
||||
# add to model for display...
|
||||
self.model.add((label, human_value))
|
||||
|
||||
self.set_has_data(self.model.count > 0)
|
||||
self.exif_widgets["Total"].set_text(_("Number of Key/ Value pairs : %04d") % self.model.count)
|
||||
|
||||
def __create_button(self, pos, text, callback =[], icon =False, sensitive =False):
|
||||
@ -708,7 +770,7 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
return label
|
||||
|
||||
def build_shaded_display(self):
|
||||
def __build_shaded_display(self):
|
||||
"""
|
||||
Build the GUI interface.
|
||||
"""
|
||||
@ -716,7 +778,7 @@ class EditExifMetadata(Gramplet):
|
||||
top = gtk.TreeView()
|
||||
titles = [(_('Key'), 1, 180),
|
||||
(_('Value'), 2, 310)]
|
||||
self.model = ListModel(top, titles)
|
||||
self.model = ListModel(top, titles, list_mode="tree")
|
||||
|
||||
return top
|
||||
|
||||
@ -725,13 +787,33 @@ class EditExifMetadata(Gramplet):
|
||||
will allow a display area for a thumbnail pop-up window.
|
||||
"""
|
||||
|
||||
dirpath, filename = os.path.split(self.image_path)
|
||||
tip = _("Click Close to close this Thumbnail View Area.")
|
||||
|
||||
if LesserVersion: # prior to pyexiv2-0.2.0
|
||||
self.tbarea = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
self.tbarea.tooltip = tip
|
||||
self.tbarea.set_title(_("Thumbnail View Area"))
|
||||
self.tbarea.set_default_size((width + 40), (height + 40))
|
||||
self.tbarea.set_border_width(10)
|
||||
self.tbarea.connect('destroy', lambda w: self.tbarea.destroy() )
|
||||
|
||||
pbloader, width, height = self.__get_thumbnail_data()
|
||||
|
||||
new_vbox = self.build_thumbnail_gui(pbloader, width, height)
|
||||
self.tbarea.add(new_vbox)
|
||||
self.tbarea.show()
|
||||
|
||||
def __get_thumbnail_data(self):
|
||||
"""
|
||||
returns the thumbnail width and height from the active media object if there is any?
|
||||
"""
|
||||
|
||||
dirpath, filename = os.path.split(self.image_path)
|
||||
pbloader, width, height = [False]*3
|
||||
|
||||
if OLD_API: # prior to pyexiv2-0.2.0
|
||||
try:
|
||||
ttype, tdata = self.plugin_image.getThumbnailData()
|
||||
width, height = tdata.dimensions
|
||||
|
||||
except (IOError, OSError):
|
||||
print(_('Error: %s does not contain an EXIF thumbnail.') % filename)
|
||||
self.close_window(self.tbarea)
|
||||
@ -747,30 +829,18 @@ class EditExifMetadata(Gramplet):
|
||||
print(_('Error: %s does not contain an EXIF thumbnail.') % filename)
|
||||
self.close_window(self.tbarea)
|
||||
|
||||
# Get the largest preview available...
|
||||
preview = previews[-1]
|
||||
width, height = preview.dimensions
|
||||
except (IOError, OSError):
|
||||
print(_('Error: %s does not contain an EXIF thumbnail.') % filename)
|
||||
self.close_window(self.tbarea)
|
||||
|
||||
# Get the largest preview available...
|
||||
preview = previews[-1]
|
||||
width, height = preview.dimensions
|
||||
|
||||
# Create a GTK pixbuf loader to read the thumbnail data
|
||||
pbloader = gtk.gdk.PixbufLoader()
|
||||
pbloader.write(preview.data)
|
||||
|
||||
tip = _("Click Close to close this Thumbnail Viewing Area.")
|
||||
|
||||
self.tbarea = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
self.tbarea.tooltip = tip
|
||||
self.tbarea.set_title(_("Thumbnail Viewing Area"))
|
||||
self.tbarea.set_default_size((width + 40), (height + 40))
|
||||
self.tbarea.set_border_width(10)
|
||||
self.tbarea.connect('destroy', lambda w: self.tbarea.destroy() )
|
||||
|
||||
new_vbox = self.build_thumbnail_gui(pbloader, width, height)
|
||||
self.tbarea.add(new_vbox)
|
||||
self.tbarea.show()
|
||||
return pbloader, width, height
|
||||
|
||||
def build_thumbnail_gui(self, pbloader, width, height):
|
||||
"""
|
||||
@ -815,7 +885,7 @@ class EditExifMetadata(Gramplet):
|
||||
full_path = self.image_path
|
||||
|
||||
# get image filepath and its filename...
|
||||
filepath, basename = os.path.split(self.basename)
|
||||
filepath, basename = os.path.split(self._filepath_fname)
|
||||
|
||||
# get extension selected for converting this image...
|
||||
ext_type = self.exif_widgets["ImageType"].get_active()
|
||||
@ -830,7 +900,7 @@ class EditExifMetadata(Gramplet):
|
||||
im.save(dest_file)
|
||||
|
||||
# identify pyexiv2 source image file...
|
||||
if LesserVersion: # prior to pyexiv2-0.2.0...
|
||||
if OLD_API: # prior to pyexiv2-0.2.0...
|
||||
src_meta = pyexiv2.Image(full_path)
|
||||
src_meta.readMetadata()
|
||||
else:
|
||||
@ -840,7 +910,7 @@ class EditExifMetadata(Gramplet):
|
||||
# check to see if source image file has any Exif metadata?
|
||||
if _get_exif_keypairs(src_meta):
|
||||
|
||||
if LesserVersion:
|
||||
if OLD_API:
|
||||
# Identify the destination image file...
|
||||
dest_meta = pyexiv2.Image(dest_file)
|
||||
dest_meta.readMetadata()
|
||||
@ -895,10 +965,6 @@ class EditExifMetadata(Gramplet):
|
||||
self.exif_widgets["MessageArea"].set_text(_("There was an error in "
|
||||
"deleting the original file. You will need to delete it yourself!"))
|
||||
|
||||
# force an update once completed in converting, deleting, and
|
||||
# updating media object's path...
|
||||
self.update()
|
||||
|
||||
def __convert_only(self, full_path =None):
|
||||
"""
|
||||
This will only convert the file and update the media object path.
|
||||
@ -917,10 +983,6 @@ class EditExifMetadata(Gramplet):
|
||||
self.exif_widgets["MessageArea"].set_text(_("There was an error "
|
||||
"in converting your image file."))
|
||||
|
||||
# force an update once completed in converting and updating the media
|
||||
# object's path, no deleting of original file...
|
||||
self.update()
|
||||
|
||||
def update_media_path(self, newfilepath =None):
|
||||
"""
|
||||
update the media object's media path.
|
||||
@ -1038,14 +1100,14 @@ class EditExifMetadata(Gramplet):
|
||||
"Copy" : _("Re -display the data fields that were cleared from the Edit Area."),
|
||||
|
||||
# Convert 2 Decimal button...
|
||||
"Decimal" : _("Convert GPS Latitude/ Longitude Coordinates to Decimal representation."),
|
||||
"Decimal" : _("Convert GPS Latitude/ Longitude coordinates to Decimal representation."),
|
||||
|
||||
# Convert 2 Degrees, Minutes, Seconds button...
|
||||
"DMS" : _("Convert GPS Latitude/ Longitude Coordinates to "
|
||||
"DMS" : _("Convert GPS Latitude/ Longitude coordinates to "
|
||||
"(Degrees, Minutes, Seconds) Representation.") }.items() )
|
||||
|
||||
# True, True -- all data fields and button tooltips will be displayed...
|
||||
self._setup_widget_tips([True, True])
|
||||
self._setup_widget_tips(fields =True, buttons = True)
|
||||
|
||||
# display all data fields and their values...
|
||||
self.EditArea(self.plugin_image)
|
||||
@ -1074,7 +1136,6 @@ class EditExifMetadata(Gramplet):
|
||||
new_vbox.show()
|
||||
|
||||
for widget, text in [
|
||||
("ExifLabel", _("Exif Label :") ),
|
||||
("Description", _("Description :") ),
|
||||
("Artist", _("Artist :") ),
|
||||
("Copyright", _("Copyright :") ) ]:
|
||||
@ -1142,8 +1203,8 @@ class EditExifMetadata(Gramplet):
|
||||
if self.exif_widgets["Modified"].get_text():
|
||||
self.exif_widgets["Modified"].set_editable(False)
|
||||
|
||||
# GPS Coordinates...
|
||||
latlong_frame = gtk.Frame(_("Latitude/ Longitude/ Altitude GPS Coordinates"))
|
||||
# GPS coordinates...
|
||||
latlong_frame = gtk.Frame(_("Latitude/ Longitude/ Altitude GPS coordinates"))
|
||||
latlong_frame.set_size_request(550, 125)
|
||||
main_vbox.pack_start(latlong_frame, expand =False, fill =False, padding =0)
|
||||
latlong_frame.show()
|
||||
@ -1284,7 +1345,7 @@ class EditExifMetadata(Gramplet):
|
||||
@param: keytag_ -- image metadata key
|
||||
"""
|
||||
|
||||
if LesserVersion:
|
||||
if OLD_API:
|
||||
keyvalue_ = self.plugin_image[keytag_]
|
||||
|
||||
else:
|
||||
@ -1320,7 +1381,7 @@ class EditExifMetadata(Gramplet):
|
||||
tagValue = self._get_value(keytag_)
|
||||
if tagValue:
|
||||
|
||||
if widgetname_ in ["ExifLabel", "Description", "Artist", "Copyright"]:
|
||||
if widgetname_ in ["Description", "Artist", "Copyright"]:
|
||||
self.exif_widgets[widgetname_].set_text(tagValue)
|
||||
|
||||
# Last Changed/ Modified...
|
||||
@ -1346,7 +1407,7 @@ class EditExifMetadata(Gramplet):
|
||||
# split longitude metadata into degrees, minutes, and seconds
|
||||
longdeg, longmin, longsec = rational_to_dms(longitude)
|
||||
|
||||
# check to see if we have valid GPS Coordinates?
|
||||
# check to see if we have valid GPS coordinates?
|
||||
latfail = any(coords == False for coords in [latdeg, latmin, latsec])
|
||||
longfail = any(coords == False for coords in [longdeg, longmin, longsec])
|
||||
if (not latfail and not longfail):
|
||||
@ -1357,11 +1418,11 @@ class EditExifMetadata(Gramplet):
|
||||
# Longitude Direction Reference
|
||||
LongRef = self._get_value(_DATAMAP["LongitudeRef"] )
|
||||
|
||||
# set display for Latitude GPS Coordinates
|
||||
# set display for Latitude GPS coordinates
|
||||
latitude = """%s° %s′ %s″ %s""" % (latdeg, latmin, latsec, LatRef)
|
||||
self.exif_widgets["Latitude"].set_text(latitude)
|
||||
|
||||
# set display for Longitude GPS Coordinates
|
||||
# set display for Longitude GPS coordinates
|
||||
longitude = """%s° %s′ %s″ %s""" % (longdeg, longmin, longsec, LongRef)
|
||||
self.exif_widgets["Longitude"].set_text(longitude)
|
||||
|
||||
@ -1397,7 +1458,7 @@ class EditExifMetadata(Gramplet):
|
||||
"""
|
||||
|
||||
tagclass_ = keytag_[0:4]
|
||||
if LesserVersion:
|
||||
if OLD_API:
|
||||
self.plugin_image[keytag_] = keyvalue_
|
||||
|
||||
else:
|
||||
@ -1420,10 +1481,10 @@ class EditExifMetadata(Gramplet):
|
||||
"""
|
||||
writes the Exif metadata to the image.
|
||||
|
||||
LesserVersion -- prior to pyexiv2-0.2.0
|
||||
OLD_API -- prior to pyexiv2-0.2.0
|
||||
-- pyexiv2-0.2.0 and above...
|
||||
"""
|
||||
if LesserVersion:
|
||||
if OLD_API:
|
||||
plugininstance.writeMetadata()
|
||||
|
||||
else:
|
||||
@ -1438,7 +1499,7 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
def convert_format(self, latitude, longitude, format):
|
||||
"""
|
||||
Convert GPS Coordinates into a specified format.
|
||||
Convert GPS coordinates into a specified format.
|
||||
"""
|
||||
|
||||
if (not latitude and not longitude):
|
||||
@ -1465,7 +1526,7 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
def __convert2decimal(self, latitude =False, longitude =False, display =False):
|
||||
"""
|
||||
will convert a decimal GPS Coordinates into decimal format.
|
||||
will convert a decimal GPS coordinates into decimal format.
|
||||
"""
|
||||
|
||||
if (not latitude and not longitude):
|
||||
@ -1480,9 +1541,9 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
return latitude, longitude
|
||||
|
||||
def __convert2dms(self, latitude =False, longitude =False, display =False):
|
||||
def __convert2dms(self, latitude =False, longitude =False, display =True):
|
||||
"""
|
||||
will convert a decimal GPS Coordinates into degrees, minutes, seconds
|
||||
will convert a decimal GPS coordinates into degrees, minutes, seconds
|
||||
for display only
|
||||
"""
|
||||
|
||||
@ -1511,7 +1572,7 @@ class EditExifMetadata(Gramplet):
|
||||
for widgetname_, widgetvalue_ in datatags_:
|
||||
|
||||
# Exif Label, Description, Artist, Copyright...
|
||||
if widgetname_ in ["ExifLabel", "Description", "Artist", "Copyright"]:
|
||||
if widgetname_ in ["Description", "Artist", "Copyright"]:
|
||||
self._set_value(_DATAMAP[widgetname_], widgetvalue_)
|
||||
|
||||
# Modify Date/ Time...
|
||||
@ -1534,7 +1595,7 @@ class EditExifMetadata(Gramplet):
|
||||
# modify the media object date if it is not already set?
|
||||
mediaobj_date = self.orig_image.get_date_object()
|
||||
if mediaobj_date.is_empty():
|
||||
objdate = Date()
|
||||
objdate = gen.lib.date.Date()
|
||||
try:
|
||||
objdate.set_yr_mon_day(widgetvalue_.get_year(),
|
||||
widgetvalue_.get_month(),
|
||||
@ -1563,27 +1624,28 @@ class EditExifMetadata(Gramplet):
|
||||
if (latitude.count(" ") == longitude.count(" ") == 0):
|
||||
latitude, longitude = self.__convert2dms(latitude, longitude)
|
||||
|
||||
if (latitude.count(":") == longitude.count(":") >= 1):
|
||||
# remove symbols before saving...
|
||||
latitude, longitude = _removesymbolsb4saving(latitude, longitude)
|
||||
|
||||
# remove symbols before saving...
|
||||
latitude, longitude = _removesymbolsb4saving(
|
||||
self.exif_widgets["Latitude"].get_text(),
|
||||
self.exif_widgets["Longitude"].get_text() )
|
||||
# split Latitude/ Longitude into its (d, m, s, dir)...
|
||||
latitude = coordinate_splitup(latitude)
|
||||
longitude = coordinate_splitup(longitude)
|
||||
|
||||
if "N" in latitude:
|
||||
latref = "N"
|
||||
if latitude[0] == "-":
|
||||
latitude = latitude.replace("-", '')
|
||||
latref = "S"
|
||||
elif "S" in latitude:
|
||||
latref = "S"
|
||||
latitude.remove(latref)
|
||||
|
||||
if "E" in longitude:
|
||||
longref = "E"
|
||||
if longitude[0] == "-":
|
||||
longitude = longitude.replace("-", '')
|
||||
longref = "W"
|
||||
elif "W" in longitude:
|
||||
longref = "W"
|
||||
longitude.remove(longref)
|
||||
|
||||
# convert Latitude/ Longitude into pyexiv2.Rational()...
|
||||
latitude = coords_to_rational(latitude)
|
||||
longitude = coords_to_rational(longitude)
|
||||
print(latitude, longitude)
|
||||
|
||||
# save LatitudeRef/ Latitude...
|
||||
self._set_value(_DATAMAP["LatitudeRef"], latref)
|
||||
@ -1595,18 +1657,18 @@ class EditExifMetadata(Gramplet):
|
||||
|
||||
# Altitude, and Altitude Reference...
|
||||
elif widgetname_ == "Altitude":
|
||||
altitude = widgetvalue_
|
||||
if altitude:
|
||||
if "-" in altitude:
|
||||
altitude = altitude.replace("-", "")
|
||||
if widgetvalue_:
|
||||
if "-" in widgetvalue_:
|
||||
widgetvalue_= widgetvalue_.replace("-", "")
|
||||
altituderef = "1"
|
||||
else:
|
||||
altituderef = "0"
|
||||
altitude = coords_to_rational(altitude)
|
||||
|
||||
# convert altitude to pyexiv2.Rational for saving...
|
||||
widgetvalue_ = altitude_to_rational(widgetvalue_)
|
||||
|
||||
self._set_value(_DATAMAP["AltitudeRef"], altituderef)
|
||||
self._set_value(_DATAMAP[widgetname_], altitude)
|
||||
self._set_value(_DATAMAP[widgetname_], widgetvalue_)
|
||||
|
||||
# writes all Exif Metadata to image even if the fields are all empty so as to remove the value...
|
||||
self.write_metadata(self.plugin_image)
|
||||
@ -1669,7 +1731,7 @@ def _get_exif_keypairs(plugin_image):
|
||||
if not plugin_image:
|
||||
return False
|
||||
|
||||
mediadatatags_ = [keytag_ for keytag_ in (plugin_image.exifKeys() if LesserVersion
|
||||
mediadatatags_ = [keytag_ for keytag_ in (plugin_image.exifKeys() if OLD_API
|
||||
else chain( plugin_image.exif_keys,
|
||||
plugin_image.xmp_keys,
|
||||
plugin_image.iptc_keys) ) ]
|
||||
@ -1712,50 +1774,50 @@ def string_to_rational(coordinate):
|
||||
else:
|
||||
return pyexiv2.Rational(int(coordinate), 1)
|
||||
|
||||
def coords_to_rational(Coordinates):
|
||||
def coordinate_splitup(coordinates):
|
||||
"""
|
||||
returns the rational equivalent for Latitude/ Longitude,
|
||||
and Altitude...
|
||||
will split up the coordinates into a list
|
||||
"""
|
||||
|
||||
# Latitude, Longitude...
|
||||
if " " in Coordinates:
|
||||
Coordinates = [string_to_rational(coordinate) for coordinate in Coordinates.split(" ")]
|
||||
if (":" in coordinates and coordinates.find(" ") == -1):
|
||||
return [(coordinate) for coordinate in coordinates.split(":")]
|
||||
|
||||
if ":" in Coordinates:
|
||||
Coordinates = [string_to_rational(coordinate) for coordinate in Coordinates.split(":")]
|
||||
elif (" " in coordinates and coordinates.find(":") == -1):
|
||||
return [(coordinate) for coordinate in coordinates.split(" ")]
|
||||
|
||||
# Altitude...
|
||||
else:
|
||||
Coordinates = [string_to_rational(Coordinates)]
|
||||
return None
|
||||
|
||||
return Coordinates
|
||||
def coords_to_rational(coordinates):
|
||||
"""
|
||||
returns the rational equivalent for (degrees, minutes, seconds)...
|
||||
"""
|
||||
|
||||
return [string_to_rational(coordinate) for coordinate in coordinates]
|
||||
|
||||
def altitude_to_rational(altitude):
|
||||
|
||||
return [string_to_rational(altitude)]
|
||||
|
||||
def convert_value(value):
|
||||
"""
|
||||
will take a value from the coordinates and return its value
|
||||
"""
|
||||
|
||||
if isinstance(value, (Fraction, pyexiv2.Rational)):
|
||||
return str((Decimal(value.numerator) / Decimal(value.denominator)))
|
||||
|
||||
def rational_to_dms(coords):
|
||||
def rational_to_dms(coordinates):
|
||||
"""
|
||||
takes a rational set of coordinates and returns (degrees, minutes, seconds)
|
||||
|
||||
[Fraction(40, 1), Fraction(0, 1), Fraction(1079, 20)]
|
||||
"""
|
||||
|
||||
# coordinates look like:
|
||||
# [Rational(38, 1), Rational(38, 1), Rational(150, 50)]
|
||||
# or [Fraction(38, 1), Fraction(38, 1), Fraction(318, 100)]
|
||||
if isinstance(coords, list):
|
||||
if len(coords) == 3:
|
||||
return [convert_value(coordinate) for coordinate in coords]
|
||||
|
||||
elif isinstance(coords, (Fraction, pyexiv2.Rational)):
|
||||
if len(coords) == 1:
|
||||
return convert_value(coords)
|
||||
|
||||
return [False]*3
|
||||
return [convert_value(coordinate) for coordinate in coordinates]
|
||||
|
||||
def _parse_datetime(value):
|
||||
"""
|
||||
@ -1794,18 +1856,3 @@ def _parse_datetime(value):
|
||||
time_part.tm_sec)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _format_datetime(value):
|
||||
"""
|
||||
Convert a python datetime object into a string for display, using the
|
||||
standard Gramps date format.
|
||||
"""
|
||||
if type(value) != datetime:
|
||||
return ''
|
||||
date_part = gen.lib.Date()
|
||||
date_part.set_yr_mon_day(value.year, value.month, value.day)
|
||||
date_str = _dd.display(date_part)
|
||||
time_str = _('%(hr)02d:%(min)02d:%(sec)02d') % {'hr': value.hour,
|
||||
'min': value.minute,
|
||||
'sec': value.second}
|
||||
return _('%(date)s %(time)s') % {'date': date_str, 'time': time_str}
|
||||
|
Loading…
Reference in New Issue
Block a user