1
0
mirror of https://github.com/gryf/pygtktalog.git synced 2025-12-18 12:00:21 +01:00

* Lots of changes, code cleanup, import/export in GUI.

This commit is contained in:
2008-12-15 20:40:24 +00:00
parent c2926c96d6
commit 0adcdaba8d
20 changed files with 195 additions and 243 deletions

1214
src/lib/EXIF.py Normal file

File diff suppressed because it is too large Load Diff

25
src/lib/__init__.py Normal file
View File

@@ -0,0 +1,25 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------

92
src/lib/device_helper.py Normal file
View File

@@ -0,0 +1,92 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------
import os
def volname(mntp):
"""read volume name from cd/dvd"""
dev = mountpoint_to_dev(mntp)
if dev != None:
try:
disk = open(dev, "rb")
disk.seek(32808)
label = disk.read(32).strip()
disk.close()
except IOError:
return None
return label
return None
def volmount(mntp):
"""mount device, return 'ok' or error message"""
_in, _out, _err = os.popen3("mount %s" % mntp)
inf = _err.readlines()
if len(inf) > 0:
return inf[0].strip()
else:
return 'ok'
def volumount(mntp):
"""mount device, return 'ok' or error message"""
_in, _out, _err = os.popen3("umount %s" % mntp)
inf = _err.readlines()
if len(inf) > 0:
return inf[0].strip()
return 'ok'
def check_mount(dev):
"""Refresh the entries from fstab or mount."""
mounts = os.popen('mount')
for line in mounts.readlines():
parts = line.split()
device = parts
if device[0] == dev:
return True
return False
def mountpoint_to_dev(mntp):
"""guess device name by mountpoint from fstab"""
fstab = open("/etc/fstab")
device = None
for line in fstab.readlines():
output = line.split()
# lengtht of single valid fstab line is at least 5
if len(output) > 5 and output[1] == mntp and output[0][0] != '#':
device = output[0]
fstab.close()
return device
def eject_cd(eject_app, cdrom):
"""mount device, return 'ok' or error message"""
if len(eject_app) > 0:
_in, _out, _err = os.popen3("%s %s" % (eject_app, cdrom))
inf = _err.readlines()
if len(inf) > 0 and inf[0].strip() != '':
return inf[0].strip()
return 'ok'
return "Eject program not specified"

41
src/lib/globs.py Normal file
View File

@@ -0,0 +1,41 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------
import os.path
import sys
if sys.argv[0]:
top_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
else:
top_dir = "."
# ----------------------------------------------------------------------
TOPDIR = top_dir
RESOURCES_DIR = os.path.join(TOPDIR, "resources")
GLADE_DIR = os.path.join(RESOURCES_DIR, "glade")
STYLES_DIR = os.path.join(RESOURCES_DIR, "styles")
APPL_SHORT_NAME = "pygtktalog2"
APPL_VERSION = (1, 0, 1)
# ----------------------------------------------------------------------

82
src/lib/gthumb.py Normal file
View File

@@ -0,0 +1,82 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------
from xml.dom import minidom
import gzip
import os
from datetime import date
class GthumbCommentParser(object):
def __init__(self, image_path, image_filename):
self.path = image_path
self.filename = image_filename
def parse(self):
"""Return dictionary with apropriate fields, or None if no comment
available"""
try:
gf = gzip.open(os.path.join(self.path,
'.comments', self.filename + '.xml'))
except:
return None
try:
xml = gf.read()
gf.close()
except:
gf.close()
return None
if not xml:
return None
retval = {}
doc = minidom.parseString(xml)
try:
retval['note'] = doc.getElementsByTagName('Note').item(0)
retval['note'] = retval['note'].childNodes.item(0).data
except: retval['note'] = None
try:
retval['place'] = doc.getElementsByTagName('Place').item(0)
retval['place'] = retval['place'].childNodes.item(0).data
except: retval['place'] = None
try:
d = doc.getElementsByTagName('Time').item(0).childNodes
d = d.item(0).data
if int(d) > 0: retval['date'] = date.fromtimestamp(int(d))
else: retval['date'] = None
except: retval['date'] = None
try:
retval['keywords'] = doc.getElementsByTagName('Keywords').item(0)
retval['keywords'] = retval['keywords'].childNodes.item(0)
retval['keywords'] = retval['keywords'].data.split(',')
except: pass
if len(retval) > 0: return retval
else: return None

78
src/lib/img.py Normal file
View File

@@ -0,0 +1,78 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------
from shutil import copy
from os import path
from hashlib import sha512
import Image
class Img(object):
def __init__(self, filename, base=''):
self.root = 'images'
self.x = 160
self.y = 160
self.filename = filename
self.base = base
f = open(filename, "r")
self.sha512 = sha512(f.read()).hexdigest()
f.close()
def save(self):
"""Save image and asociated thumbnail into specific directory structure
returns filename for image"""
image_filename = path.join(self.base, self.sha512)
thumbnail = path.join(self.base, self.sha512 + "_t")
# check wheter image already exists
if path.exists(image_filename) and path.exists(thumbnail):
if __debug__:
print "image", self.filename, "with hash",
print self.sha512, "already exist"
return self.sha512
if not path.exists(thumbnail):
im = self.__scale_image()
im.save(thumbnail, "JPEG")
# copy image
if not path.exists(image_filename):
copy(self.filename, image_filename)
return self.sha512
# private class functions
def __scale_image(self):
"""create thumbnail. returns image object or None"""
try:
im = Image.open(self.filename).convert('RGB')
except:
return None
x, y = im.size
if x > self.x or y > self.y:
im.thumbnail((self.x, self.y), Image.ANTIALIAS)
return im

2397
src/lib/no_thumb.py Normal file

File diff suppressed because it is too large Load Diff

117
src/lib/parse_exif.py Normal file
View File

@@ -0,0 +1,117 @@
import re
import EXIF
class ParseExif(object):
def __init__(self, exif_dict=None, exif_file=None):
self.camera = None
self.date = None
self.aperture = None
self.exposure_program = None
self.exposure_bias = None
self.iso = None
self.focal_length = None
self.subject_distance = None
self.metering_mode = None
self.flash = None
self.light_source = None
self.resolution = None
self.orientation = None
self.exif_dict = exif_dict
if not self.exif_dict:
try:
f = open(exif_file, 'rb')
e = EXIF.process_file(f)
if len(e.keys()) >0:
self.exif_dict = e
f.close()
except:
pass
def parse(self):
try:
self.camera = "%s" % self.exif_dict['Image Make']
self.camera = self.camera.strip()
except: pass
try:
model = "%s" % self.exif_dict['Image Model']
self.camera += ", " + model.strip()
except: pass
try:
self.date = "%s" % self.exif_dict['EXIF DateTimeOriginal']
p = re.compile('[\d,:]+')
if not p.match(self.date):
self.date = None
except: pass
try:
self.aperture = "%s" % self.exif_dict['EXIF FNumber']
if len(self.aperture.split("/")) == 2:
self.aperture += '.'
self.aperture = "%.1f" % eval(self.aperture)
self.aperture = "f/%.1f" % float(self.aperture)
self.aperture = self.aperture.replace('.',',')
except: pass
try: self.exposure_program = "%s" % \
self.exif_dict['EXIF ExposureProgram']
except: pass
try:
self.exposure_bias = "%s" % \
self.exif_dict['EXIF ExposureBiasValue']
if len(self.exposure_bias.split("/")) == 2:
self.exposure_bias += '.'
self.exposure_bias = "%.1f" % eval(self.exposure_bias)
self.exposure_bias = "%.1f" % float(self.exposure_bias)
self.exposure_bias = self.exposure_bias.replace('.',',')
except: pass
try: self.iso = "%s" % self.exif_dict['EXIF ISOSpeedRatings']
except: pass
try:
self.focal_length = "%s" % self.exif_dict['EXIF FocalLength']
if len(self.focal_length.split("/")) == 2:
self.focal_length += '.'
self.focal_length = "%.2f" % eval(self.focal_length)
self.focal_length = "%.2f mm" % float(self.focal_length)
self.focal_length = self.focal_length.replace('.',',')
except: pass
try:
self.subject_distance = "%s" % \
self.exif_dict['EXIF SubjectDistance']
if len(self.subject_distance.split("/")) == 2:
self.subject_distance += '.'
self.subject_distance = "%.3f" % eval(self.subject_distance)
self.subject_distance = "%.3f m" % float(self.subject_distance)
self.subject_distance = self.subject_distance.replace('.',',')
except: pass
try: self.metering_mode = "%s" % self.exif_dict['EXIF MeteringMode']
except: pass
try: self.flash = "%s" % self.exif_dict['EXIF Flash']
except: pass
try: self.light_source = "%s" % self.exif_dict['EXIF LightSource']
except: pass
try: self.resolution = "%s" % self.exif_dict['Image XResolution']
except: pass
try: self.resolution = self.resolution + " x %s" % \
self.exif_dict['Image YResolution']
except: pass
try: self.resolution = self.resolution + " (%s)" % \
self.exif_dict['Image ResolutionUnit']
except: pass
try: self.orientation = "%s" % self.exif_dict['Image Orientation']
except: pass
return (self.camera, self.date, self.aperture, self.exposure_program,
self.exposure_bias, self.iso, self.focal_length,
self.subject_distance, self.metering_mode, self.flash,
self.light_source, self.resolution, self.orientation)

116
src/lib/thumbnail.py Normal file
View File

@@ -0,0 +1,116 @@
# This Python file uses the following encoding: utf-8
#
# Author: Roman 'gryf' Dobosz gryf@elysium.pl
#
# Copyright (C) 2007 by Roman 'gryf' Dobosz
#
# This file is part of pyGTKtalog.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# -------------------------------------------------------------------------
from tempfile import mkstemp
from hashlib import sha512
from shutil import move
from os import path
import sys
from lib import EXIF
import Image
class Thumbnail(object):
"""Class for generate/extract thumbnail from image file"""
def __init__(self, filename=None, base=''):
self.thumb_x = 160
self.thumb_y = 160
self.filename = filename
self.base = base
self.sha512 = sha512(open(filename).read()).hexdigest()
self.thumbnail_path = path.join(self.base, self.sha512 + "_t")
def save(self):
"""Save thumbnail into specific directory structure
return filename base and exif object or None"""
exif = {}
orientations = {2: Image.FLIP_LEFT_RIGHT, # Mirrored horizontal
3: Image.ROTATE_180, # Rotated 180
4: Image.FLIP_TOP_BOTTOM, # Mirrored vertical
5: Image.ROTATE_90, # Mirrored horizontal then
# rotated 90 CCW
6: Image.ROTATE_270, # Rotated 90 CW
7: Image.ROTATE_270, # Mirrored horizontal then
# rotated 90 CW
8: Image.ROTATE_90} # Rotated 90 CCW
flips = {7: Image.FLIP_LEFT_RIGHT, 5: Image.FLIP_LEFT_RIGHT}
image_file = open(self.filename, 'rb')
try:
exif = EXIF.process_file(image_file)
except:
if __debug__:
print "exception", sys.exc_info()[0], "raised with file:"
print self.filename
finally:
image_file.close()
if path.exists(self.thumbnail_path):
if __debug__:
print "file", self.filename, "with hash", self.sha512, "exists"
return self.sha512, exif
if 'JPEGThumbnail' in exif:
if __debug__:
print self.filename, "exif thumb"
exif_thumbnail = exif['JPEGThumbnail']
thumb_file = open(self.thumbnail_path, 'wb')
thumb_file.write(exif_thumbnail)
thumb_file.close()
if 'Image Orientation' in exif:
orient = exif['Image Orientation'].values[0]
if orient > 1 and orient in orientations:
temp_image_path = mkstemp()[1]
thumb_image = Image.open(self.thumbnail_path)
tmp_thumb_img = thumb_image.transpose(orientations[orient])
if orient in flips:
tmp_thumb_img = tmp_thumb_img.transpose(flips[orient])
if tmp_thumb_img:
tmp_thumb_img.save(temp_image_path, 'JPEG')
move(temp_image_path, self.thumbnail_path)
return self.sha512, exif
else:
if __debug__:
print self.filename, "no exif thumb"
thumb = self.__scale_image()
if thumb:
thumb.save(self.thumbnail_path, "JPEG")
return self.sha512, exif
return None, exif
def __scale_image(self):
"""create thumbnail. returns image object or None"""
try:
image_thumb = Image.open(self.filename).convert('RGB')
except:
return None
it_x, it_y = image_thumb.size
if it_x > self.thumb_x or it_y > self.thumb_y:
image_thumb.thumbnail((self.thumb_x, self.thumb_y), Image.ANTIALIAS)
return image_thumb