Removed ImageMagick and Jhead dependencies as requested using PIL.Image, exiv2, and os.remove. Thank you, Nick Hall, John Ralls, Benny Malengier, and Brian Matherly.
svn: r17833
This commit is contained in:
parent
23967fae03
commit
04d9b96dc8
@ -28,7 +28,7 @@
|
|||||||
import os
|
import os
|
||||||
from datetime import datetime, date
|
from datetime import datetime, date
|
||||||
import calendar, time
|
import calendar, time
|
||||||
|
import subprocess
|
||||||
|
|
||||||
# abilty to escape certain characters from output...
|
# abilty to escape certain characters from output...
|
||||||
from xml.sax.saxutils import escape as _html_escape
|
from xml.sax.saxutils import escape as _html_escape
|
||||||
@ -39,7 +39,7 @@ from decimal import Decimal, getcontext
|
|||||||
getcontext().prec = 4
|
getcontext().prec = 4
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
|
|
||||||
import subprocess
|
from PIL import Image, ImageEnhance, ImageFilter
|
||||||
|
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
# GTK modules
|
# GTK modules
|
||||||
@ -62,7 +62,7 @@ import gen.mime
|
|||||||
import Utils
|
import Utils
|
||||||
from PlaceUtils import conv_lat_lon
|
from PlaceUtils import conv_lat_lon
|
||||||
|
|
||||||
from QuestionDialog import WarningDialog, QuestionDialog
|
from QuestionDialog import WarningDialog, QuestionDialog, OptionDialog
|
||||||
|
|
||||||
from gen.ggettext import gettext as _
|
from gen.ggettext import gettext as _
|
||||||
|
|
||||||
@ -107,55 +107,19 @@ if (software_version and (software_version < Min_VERSION)):
|
|||||||
WarningDialog(msg)
|
WarningDialog(msg)
|
||||||
raise Exception(msg)
|
raise Exception(msg)
|
||||||
|
|
||||||
# *******************************************************************
|
|
||||||
# Determine if we have access to outside Programs
|
|
||||||
#
|
|
||||||
# The programs are ImageMagick, and jhead
|
|
||||||
# * ImageMagick -- Convert and Delete all Exif metadata...
|
|
||||||
# * jhead -- re-initialize a jpeg, and other features...
|
|
||||||
# * del/ rm -- used to delete the original file after converting
|
|
||||||
# if requested...
|
|
||||||
#********************************************************************
|
|
||||||
# Windows 32bit systems
|
|
||||||
system_platform = os.sys.platform
|
|
||||||
MAGICK_FOUND_ = False
|
|
||||||
JHEAD_FOUND_ = False
|
|
||||||
if system_platform == "win32":
|
|
||||||
MAGICK_FOUND_ = "convert.exe" if Utils.search_for("convert.exe") else False
|
|
||||||
_JHEAD_FOUND_ = "jhead.exe" if Utils.search_for("jhead.exe") else False
|
|
||||||
DEL_FOUND_ = "del.exe" if Utils.search_for("del.exe") else False
|
|
||||||
|
|
||||||
elif system_platform == "linux2":
|
|
||||||
MAGICK_FOUND_ = "convert" if Utils.search_for("convert") else False
|
|
||||||
JHEAD_FOUND_ = "jhead" if Utils.search_for("jhead") else False
|
|
||||||
DEL_FOUND_ = "rm" if Utils.search_for("rm") else False
|
|
||||||
|
|
||||||
else:
|
|
||||||
MAGICK_FOUND_ = "convert" if Utils.search_for("convert") else False
|
|
||||||
JHEAD_FOUND_ = "jhead" if Utils.search_for("jhead") else False
|
|
||||||
DEL_FOUND_ = "del" if Utils.search_for("del") else False
|
|
||||||
|
|
||||||
# if external programs are not found, let the user know about
|
|
||||||
# the missing functionality?
|
|
||||||
if not MAGICK_FOUND_:
|
|
||||||
print(_("ImageMagick's convert program was not found "
|
|
||||||
"on this computer.\n You may download it from "
|
|
||||||
"here: %s...") % ("http://www.imagemagick.org/script/index.php"))
|
|
||||||
|
|
||||||
if not JHEAD_FOUND_:
|
|
||||||
print(_("Jhead program was not found on this computer.\n"
|
|
||||||
"You may download it from: %s...") % (
|
|
||||||
"http://www.sentex.net/~mwandel/jhead/"))
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
# Constants
|
# Constants
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
# available image types for exiv2 and pyexiv2
|
# available image types for exiv2 and pyexiv2
|
||||||
# ["jpeg", "jpg", "exv", "tiff", "dng", "nef", "pef", "pgf", "png", "psd", "jp2"]
|
# ["jpeg", "jpg", "exv", "tiff", "dng", "nef", "pef", "pgf", "png", "psd", "jp2"]
|
||||||
|
|
||||||
|
if os.sys.platform == "win32":
|
||||||
|
EXIV2_FOUND_ = "exiv2.exe" if Utils.search_for("exiv2.exe") else False
|
||||||
|
else:
|
||||||
|
EXIV2_FOUND_ = "exiv2" if Utils.search_for("exiv2") else False
|
||||||
|
|
||||||
# define tooltips for all entries
|
# define tooltips for all entries
|
||||||
_TOOLTIPS = {
|
_TOOLTIPS = {
|
||||||
|
|
||||||
# Description...
|
# Description...
|
||||||
"Description" : _("Provide a short descripion for this image."),
|
"Description" : _("Provide a short descripion for this image."),
|
||||||
|
|
||||||
@ -210,19 +174,14 @@ _BUTTONTIPS = {
|
|||||||
|
|
||||||
# Save Exif Metadata button...
|
# Save Exif Metadata button...
|
||||||
"Save" : _("Saves/ writes the Exif metadata to this image.\n"
|
"Save" : _("Saves/ writes the Exif metadata to this image.\n"
|
||||||
"WARNING: Exif metadata will be erased if you save a blank entry field...") }
|
"WARNING: Exif metadata will be erased if you save a blank entry field..."),
|
||||||
|
|
||||||
# if ImageMagick is installed on this computer then, add button
|
|
||||||
# tooltips for these two buttons...
|
|
||||||
if MAGICK_FOUND_:
|
|
||||||
_BUTTONTIPS.update( {
|
|
||||||
|
|
||||||
# Convert to .Jpeg button...
|
|
||||||
"Convert" : _("If your image is not a jpeg image, convert it to jpeg?"),
|
|
||||||
|
|
||||||
# Delete/ Erase/ Wipe Exif metadata button...
|
# Delete/ Erase/ Wipe Exif metadata button...
|
||||||
"Delete" : _("WARNING: This will completely erase all Exif metadata "
|
"Delete" : _("WARNING: This will completely erase all Exif metadata "
|
||||||
"from this image! Are you sure that you want to do this?") } )
|
"from this image! Are you sure that you want to do this?"),
|
||||||
|
|
||||||
|
# Convert to .Jpeg button...
|
||||||
|
"Convert" : _("If your image is not an exiv2 compatible image, convert it?") }
|
||||||
_BUTTONTIPS = dict( [widget, tooltip] for widget, tooltip in _BUTTONTIPS.items() )
|
_BUTTONTIPS = dict( [widget, tooltip] for widget, tooltip in _BUTTONTIPS.items() )
|
||||||
|
|
||||||
# ------------------------------------------------------------------------
|
# ------------------------------------------------------------------------
|
||||||
@ -304,12 +263,9 @@ class EditExifMetadata(Gramplet):
|
|||||||
ccc_box.add( self.__create_button(
|
ccc_box.add( self.__create_button(
|
||||||
"Clear", False, [self.clear_metadata], gtk.STOCK_CLEAR, False) )
|
"Clear", False, [self.clear_metadata], gtk.STOCK_CLEAR, False) )
|
||||||
|
|
||||||
# is ImageMagick installed?
|
# Convert button...
|
||||||
if MAGICK_FOUND_:
|
ccc_box.add( self.__create_button(
|
||||||
# Convert button...
|
"Convert", False, [self.__convert_dialog], gtk.STOCK_CONVERT, False) )
|
||||||
ccc_box.add( self.__create_button(
|
|
||||||
"Convert", False, [self.__convert_dialog],
|
|
||||||
gtk.STOCK_CONVERT, False) )
|
|
||||||
|
|
||||||
for items in [
|
for items in [
|
||||||
|
|
||||||
@ -360,10 +316,9 @@ class EditExifMetadata(Gramplet):
|
|||||||
"Save", False, [self.save_metadata, self.update, self.display_exif_tags, self.copyto],
|
"Save", False, [self.save_metadata, self.update, self.display_exif_tags, self.copyto],
|
||||||
gtk.STOCK_SAVE, False))
|
gtk.STOCK_SAVE, False))
|
||||||
|
|
||||||
if MAGICK_FOUND_:
|
# Delete All Metadata button...
|
||||||
# Delete All Metadata button...
|
hsd_box.add(self.__create_button(
|
||||||
hsd_box.add(self.__create_button(
|
"Delete", False, [self.__delete_dialog], gtk.STOCK_DELETE, False))
|
||||||
"Delete", False, [self.__delete_dialog], gtk.STOCK_DELETE, False))
|
|
||||||
|
|
||||||
# adds Exif Metadata Viewing Area
|
# adds Exif Metadata Viewing Area
|
||||||
vbox.pack_start(view, padding =10)
|
vbox.pack_start(view, padding =10)
|
||||||
@ -441,11 +396,7 @@ class EditExifMetadata(Gramplet):
|
|||||||
self.model.clear()
|
self.model.clear()
|
||||||
|
|
||||||
# De-activate the buttons except for Help...
|
# De-activate the buttons except for Help...
|
||||||
self.deactivate_buttons(["CopyTo", "Clear", "Save"])
|
self.deactivate_buttons(["CopyTo", "Clear", "Save", "Convert", "Delete"])
|
||||||
|
|
||||||
# de-activate the Convert and Delete buttons...
|
|
||||||
if MAGICK_FOUND_:
|
|
||||||
self.deactivate_buttons(["Convert", "Delete"])
|
|
||||||
|
|
||||||
# Re-post initial image message...
|
# Re-post initial image message...
|
||||||
self.exif_widgets["Message:Area"].set_text(_("Select an "
|
self.exif_widgets["Message:Area"].set_text(_("Select an "
|
||||||
@ -499,12 +450,9 @@ class EditExifMetadata(Gramplet):
|
|||||||
# will create the image and read it...
|
# will create the image and read it...
|
||||||
self.setup_image(self.image_path, True)
|
self.setup_image(self.image_path, True)
|
||||||
|
|
||||||
# Checks to make sure that ImageMagick is installed on
|
self.basename, self.extension = os.path.splitext(self.image_path)
|
||||||
# this computer and the image is NOT a jpeg image...
|
if self.extension not in [".jpeg", ".jpg", ".jfif"]:
|
||||||
if MAGICK_FOUND_:
|
self.activate_buttons(["Convert"])
|
||||||
basename, self.extension = os.path.splitext(self.image_path)
|
|
||||||
if self.extension not in [".jpeg", ".jpg", ".jfif"]:
|
|
||||||
self.activate_buttons(["Convert"])
|
|
||||||
|
|
||||||
# displays the imge Exif metadata
|
# displays the imge Exif metadata
|
||||||
self.display_exif_tags()
|
self.display_exif_tags()
|
||||||
@ -566,16 +514,6 @@ class EditExifMetadata(Gramplet):
|
|||||||
|
|
||||||
return button
|
return button
|
||||||
|
|
||||||
def __convert_dialog(self, object):
|
|
||||||
"""
|
|
||||||
Handles the Convert question Dialog...
|
|
||||||
"""
|
|
||||||
|
|
||||||
# is ImageMagick installled?
|
|
||||||
if MAGICK_FOUND_:
|
|
||||||
QuestionDialog(_("Edit Image Exif Metadata"), _("Convert this "
|
|
||||||
"image to a .jpeg image?"), _("Convert"), self.convert2Jpeg)
|
|
||||||
|
|
||||||
def __delete_dialog(self, object):
|
def __delete_dialog(self, object):
|
||||||
"""
|
"""
|
||||||
Handles the Delete Dialog...
|
Handles the Delete Dialog...
|
||||||
@ -585,6 +523,82 @@ class EditExifMetadata(Gramplet):
|
|||||||
"about to completely delete the Exif metadata from this image?"),
|
"about to completely delete the Exif metadata from this image?"),
|
||||||
_("Delete"), self.strip_metadata)
|
_("Delete"), self.strip_metadata)
|
||||||
|
|
||||||
|
def __convert_dialog(self, object):
|
||||||
|
"""
|
||||||
|
Handles the Convert question Dialog...
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Convert and delete original file...
|
||||||
|
if EXIV2_FOUND_:
|
||||||
|
OptionDialog(_("Edit Image Exif Metadata"), _("WARNING: You are "
|
||||||
|
"about to convert this image into an .tiff image. Tiff "
|
||||||
|
"images are the industry standard for lossless compression.\n\n"
|
||||||
|
"Are you sure that you want to do this?"), _("Convert and Delete"),
|
||||||
|
self.__convert_delete, _("Convert"), self.__convert_file)
|
||||||
|
|
||||||
|
def __convert_file(self, full_path =None):
|
||||||
|
"""
|
||||||
|
Will attempt to convert an image to jpeg if it is not?
|
||||||
|
"""
|
||||||
|
|
||||||
|
if full_path is None:
|
||||||
|
full_path = self.image_path
|
||||||
|
|
||||||
|
basename, oldext = os.path.splitext(full_path)
|
||||||
|
filepath, basename = os.path.split(basename)
|
||||||
|
basename += ".tiff"
|
||||||
|
|
||||||
|
dest_file = os.path.join(filepath, basename)
|
||||||
|
|
||||||
|
# Convert the file based upon file suffix
|
||||||
|
im = Image.open(full_path)
|
||||||
|
im.save(dest_file)
|
||||||
|
|
||||||
|
if LesserVersion: # prior to pyexiv2-0.2.0...
|
||||||
|
src_meta = pyexiv2.Image(full_path)
|
||||||
|
|
||||||
|
# Copy the image metadata...
|
||||||
|
dest_meta = pyexiv2.Image(dest_file)
|
||||||
|
dest_meta.readMetadata()
|
||||||
|
src_meta.readMetadata()
|
||||||
|
src_meta.copy(dest_meta, comment =False)
|
||||||
|
dest_meta.writeMetadata()
|
||||||
|
|
||||||
|
else: # pyexiv2-0.2.0 and above...
|
||||||
|
src_meta = pyexiv2.ImageMetadata(full_path)
|
||||||
|
|
||||||
|
# Copy the image metadata...
|
||||||
|
dest_meta = pyexiv2.ImageMetadata(dest_file)
|
||||||
|
src_meta.read()
|
||||||
|
dest_meta.read()
|
||||||
|
src_meta.copy(dest_meta, comment =False)
|
||||||
|
dest_meta.write()
|
||||||
|
|
||||||
|
def __convert_delete(self, full_path =None):
|
||||||
|
"""
|
||||||
|
will convert an image file and delete original non-jpeg image.
|
||||||
|
"""
|
||||||
|
self.db = self.dbstate.db
|
||||||
|
|
||||||
|
if full_path is None:
|
||||||
|
full_path = self.image_path
|
||||||
|
|
||||||
|
# Convert image and copy over it's Exif metadata (if any?)
|
||||||
|
self.__convert_file(full_path)
|
||||||
|
|
||||||
|
# delete original file from this computer...
|
||||||
|
try:
|
||||||
|
os.remove(full_path)
|
||||||
|
delete_results = True
|
||||||
|
except (IOError, OSError):
|
||||||
|
delete_results = False
|
||||||
|
|
||||||
|
if delete_results:
|
||||||
|
filepath, __basename = os.path.split(self.basename)
|
||||||
|
|
||||||
|
self.exif_widgets["Message:Area"].set_text(_("Your image has been "
|
||||||
|
"converted and the original file has been deleted..."))
|
||||||
|
|
||||||
def setup_image(self, full_path, createimage =False):
|
def setup_image(self, full_path, createimage =False):
|
||||||
"""
|
"""
|
||||||
will return an image instance and read the Exif metadata.
|
will return an image instance and read the Exif metadata.
|
||||||
@ -717,7 +731,7 @@ class EditExifMetadata(Gramplet):
|
|||||||
self.set_has_data(True)
|
self.set_has_data(True)
|
||||||
|
|
||||||
# Activate Clear and Save buttons...
|
# Activate Clear and Save buttons...
|
||||||
self.activate_buttons(["Clear", "Save", "CopyTo"])
|
self.activate_buttons(["Clear", "Save", "CopyTo", "Delete"])
|
||||||
|
|
||||||
# set Message Area to Display...
|
# set Message Area to Display...
|
||||||
self.exif_widgets["Message:Area"].set_text(_("Displaying image "
|
self.exif_widgets["Message:Area"].set_text(_("Displaying image "
|
||||||
@ -822,9 +836,6 @@ class EditExifMetadata(Gramplet):
|
|||||||
# enable Save button after metadata has been "Copied to Edit Area"...
|
# enable Save button after metadata has been "Copied to Edit Area"...
|
||||||
self.activate_buttons(["Save"])
|
self.activate_buttons(["Save"])
|
||||||
|
|
||||||
if MAGICK_FOUND_:
|
|
||||||
self.activate_buttons(["Delete"])
|
|
||||||
|
|
||||||
# Clear the Message Area...
|
# Clear the Message Area...
|
||||||
self.exif_widgets["Message:Area"].set_text("")
|
self.exif_widgets["Message:Area"].set_text("")
|
||||||
|
|
||||||
@ -850,28 +861,6 @@ class EditExifMetadata(Gramplet):
|
|||||||
else:
|
else:
|
||||||
self.exif_widgets["DateTime"].set_text("")
|
self.exif_widgets["DateTime"].set_text("")
|
||||||
|
|
||||||
def convert2Jpeg(self):
|
|
||||||
"""
|
|
||||||
Will attempt to convert an image to jpeg if it is not?
|
|
||||||
"""
|
|
||||||
|
|
||||||
# if ImageMagick's convert is installed...
|
|
||||||
if MAGICK_FOUND_:
|
|
||||||
|
|
||||||
filepath, basename = os.path.split(self.image_path)
|
|
||||||
basename, oldext = os.path.splitext(self.image_path)
|
|
||||||
newextension = ".jpeg"
|
|
||||||
|
|
||||||
convert = subprocess.check_call(["convert", self.image_path,
|
|
||||||
os.path.join(filepath, basename + newextension) ] )
|
|
||||||
if str(convert):
|
|
||||||
|
|
||||||
# set Message Area to Convert...
|
|
||||||
self.exif_widgets["Message:Area"].set_text(_("Converting image,\n"
|
|
||||||
"You will need to delete the original image file..."))
|
|
||||||
|
|
||||||
self.deactivate_buttons(["Convert"])
|
|
||||||
|
|
||||||
def _set_exif_keytag(self, keytag, KeyValue):
|
def _set_exif_keytag(self, keytag, KeyValue):
|
||||||
"""
|
"""
|
||||||
sets the value for the metadata keytags
|
sets the value for the metadata keytags
|
||||||
@ -1080,9 +1069,7 @@ class EditExifMetadata(Gramplet):
|
|||||||
# writes all Exif Metadata to image even if the fields are all empty.
|
# writes all Exif Metadata to image even if the fields are all empty.
|
||||||
self.write_metadata(self.plugin_image)
|
self.write_metadata(self.plugin_image)
|
||||||
|
|
||||||
# Activate Delete button...
|
self.activate_buttons(["Delete"])
|
||||||
if MAGICK_FOUND_:
|
|
||||||
self.activate_buttons(["Delete"])
|
|
||||||
|
|
||||||
def __process_lat_long(self, latitude, longitude):
|
def __process_lat_long(self, latitude, longitude):
|
||||||
"""
|
"""
|
||||||
@ -1163,43 +1150,48 @@ class EditExifMetadata(Gramplet):
|
|||||||
self._set_exif_keytag(_DATAMAP["Longitude"], longitude)
|
self._set_exif_keytag(_DATAMAP["Longitude"], longitude)
|
||||||
self._set_exif_keytag(_DATAMAP["LongitudeRef"], longituderef)
|
self._set_exif_keytag(_DATAMAP["LongitudeRef"], longituderef)
|
||||||
|
|
||||||
def strip_metadata(self, erase_results =None):
|
def strip_metadata(self, mediadatatags =None):
|
||||||
"""
|
"""
|
||||||
Will completely and irrevocably erase all Exif metadata from this image.
|
Will completely and irrevocably erase all Exif metadata from this image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if MAGICK_FOUND_:
|
# make sure the image has Exif metadata...
|
||||||
erase = subprocess.check_call( ["convert", self.image_path,
|
mediadatatags_ = _get_exif_keypairs(self.plugin_image)
|
||||||
"-strip", self.image_path] )
|
if not mediadatatags_:
|
||||||
erase_results = str(erase)
|
return
|
||||||
|
|
||||||
|
if EXIV2_FOUND_:
|
||||||
|
try:
|
||||||
|
erase = subprocess.check_call( [EXIV2_FOUND_, "delete", self.image_path] )
|
||||||
|
erase_results = str(erase)
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
erase_results = False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
mediadatatags_ = _get_exif_keypairs(self.plugin_image)
|
|
||||||
if mediadatatags_:
|
if mediadatatags_:
|
||||||
for keytag in mediadatatags_:
|
for keytag_ in mediadatatags_:
|
||||||
del self.plugin_image[keytag]
|
del self.plugin_image[keytag_]
|
||||||
erase_results = True
|
erase_results = True
|
||||||
|
|
||||||
# write wiped metadata to image...
|
# write wiped metadata to image...
|
||||||
self.write_metadata(self.plugin_image)
|
self.write_metadata(self.plugin_image)
|
||||||
|
|
||||||
if erase_results:
|
if erase_results:
|
||||||
# Clear the Display and Edit Areas
|
|
||||||
self.clear_metadata(self.plugin_image)
|
for widget in ["Media:Label", "Mime:Type", "Message:Area"]:
|
||||||
|
self.exif_widgets[widget].set_text("")
|
||||||
|
|
||||||
|
# Clear the Viewing Area...
|
||||||
self.model.clear()
|
self.model.clear()
|
||||||
|
|
||||||
# Notify the User...
|
self.exif_widgets["Message:Area"].set_text(_("All Exif metadata "
|
||||||
self.exif_widgets["Message:Area"].set_text(_("All Exif metadata has been "
|
"has been deleted from this image..."))
|
||||||
"deleted from this image..."))
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
# re- initialize the image...
|
else:
|
||||||
if (JHEAD_FOUND_ and self.extension in [".jpg", ".jpeg", ".jfif"]):
|
self.exif_widgets["Message:Area"].set_text(_("There was an error "
|
||||||
QuestionDialog(_("Edit Image Exif Metadata"),
|
"in stripping the Exif metadata from this image..."))
|
||||||
_("Using -purejpg -- Delete all JPEG sections that aren't "
|
|
||||||
"necessary for rendering the image. Strips any metadata "
|
|
||||||
"that various applications may have left in the image..."),
|
|
||||||
_("Re- initialize"), self.__reinitialize_jpeg)
|
|
||||||
|
|
||||||
def __reinitialize_jpeg(self):
|
def __reinitialize_jpeg(self):
|
||||||
"""
|
"""
|
||||||
|
Loading…
Reference in New Issue
Block a user