diff options
Diffstat (limited to 'trunk/dimbola/plugins/import_plugin.py')
-rw-r--r-- | trunk/dimbola/plugins/import_plugin.py | 213 |
1 files changed, 213 insertions, 0 deletions
diff --git a/trunk/dimbola/plugins/import_plugin.py b/trunk/dimbola/plugins/import_plugin.py new file mode 100644 index 0000000..e66da88 --- /dev/null +++ b/trunk/dimbola/plugins/import_plugin.py @@ -0,0 +1,213 @@ +# Copyright (C) 2009 Lars Wirzenius <liw@liw.fi> +# +# 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 3 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, see <http://www.gnu.org/licenses/>. + + +# This is necessary for running under Python 2.5, which we need to +# do on Debian, for now. +from __future__ import with_statement + + +import datetime +import hashlib +import os +import subprocess + +import gtk +import pyexiv2 + +import dimbola + + +class ImportResult(dimbola.BackgroundStatus): + + def __init__(self, action, description, foldername, basename, + thumbnail, preview, exifs, sha1): + dimbola.BackgroundStatus.__init__(self, action, description) + self.foldername = foldername + self.basename = basename + self.thumbnail = thumbnail + self.preview = preview + self.exifs = exifs + self.sha1 = sha1 + + def process_result(self, mwc): + db = mwc.db + with db: + folderid = db.find_folder(self.foldername) + if not folderid: + folderid = db.add_folder(self.foldername) + + photoid = db.add_photo(folderid, self.basename, 0, 0) + db.set_sha1(photoid, self.sha1) + for exifname, exifvalue in self.exifs.iteritems(): + assert type(exifvalue) == str + exifid = db.find_exifname(exifname) + if not exifid: + exifid = db.add_exifname(exifname) + db.add_exif(photoid, exifid, exifvalue) + + db.add_thumbnail(photoid, self.thumbnail) + db.add_preview(photoid, self.preview) + + mwc.emit('db-changed') + + +class PreviewMaker(object): + + '''Create a JPEG preview of an image file.''' + + def __init__(self): + self.dtc = dimbola.DcrawTypeCache() + + def make_preview(self, filename): + if self.dtc.supported(filename): + return self.from_raw(filename) + else: + return self.from_other(filename) + + def from_raw(self, filename): + p = subprocess.Popen(['dcraw', '-c', filename], stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + ppm, stderr = p.communicate('') + if p.returncode: + raise Exception('dcraw failed: exit code %s:\n%s' % + (p.returncode, stderr)) + return dimbola.image_data_to_image_data(ppm, 'jpeg', + { 'quality': '50' }) + + def from_other(self, filename): + pixbuf = gtk.gdk.pixbuf_new_from_file(filename) + return dimbola.pixbuf_to_image_data(pixbuf, 'jpeg', + { 'quality': '50' }) + + +class ThumbnailMaker(object): + + '''Create a thumbnail from a preview.''' + + def make_thumbnail(self, preview_jpeg): + pixbuf = dimbola.image_data_to_pixbuf(preview_jpeg) + pixbuf = dimbola.scale_pixbuf(pixbuf, 200, 200) + return dimbola.pixbuf_to_image_data(pixbuf, 'jpeg', {'quality':'50'}) + + +class ImportPhoto(dimbola.BackgroundJob): + + exifs = ['Exif.Image.Make', + 'Exif.Image.Model', + 'Exif.Image.Orientation', + 'Exif.Image.DateTime', + 'Exif.Photo.ExposureTime', + 'Exif.Photo.FNumber', + 'Exif.Photo.ISOSpeedRatings', + 'Exif.Photo.ShutterSpeedValue', + 'Exif.Photo.ApertureValue', + 'Exif.Photo.ExposureBiasValue', + 'Exif.Photo.FocalLength', + 'Exif.Photo.WhiteBalance'] + + def __init__(self, pathname): + self.pathname = pathname + self.description = 'Importing %s' % pathname + + def run(self): + self.send_status(dimbola.BackgroundStatus('start', + 'Importing %s' % os.path.basename(self.pathname))) + + preview_maker = PreviewMaker() + preview = preview_maker.make_preview(self.pathname) + + thumbnail_maker = ThumbnailMaker() + thumbnail = thumbnail_maker.make_thumbnail(preview) + + image = pyexiv2.Image(self.pathname) + image.readMetadata() + + foldername = os.path.dirname(os.path.abspath(self.pathname)) + basename = os.path.basename(self.pathname) + + exifs = dict() + for exifname in image.exifKeys(): + if exifname not in self.exifs: + continue + exifs[exifname] = self.get_encoded(image, exifname) + assert type(exifs[exifname]) == str + + return ImportResult('stop', 'Imported %s' % basename, + foldername, basename, thumbnail, preview, exifs, + dimbola.sha1(self.pathname)) + + def get_encoded(self, image, key): + s = image.interpretedExifValue(key) + assert type(s) == str + return s + + +class ImportFiles(dimbola.Plugin): + + '''Import into database using background jobs.''' + + def __init__(self, mwc): + self.mwc = mwc + self.mwc.connect('setup-widgets', self.setup_widgets) + + def setup_widgets(self, mwc): + self.chooser = mwc.widgets['import_filechooserdialog'] + self.chooser.set_transient_for(mwc.widgets['window']) + self.dtc = dimbola.DcrawTypeCache() + + photo_filter = gtk.FileFilter() + photo_filter.set_name('All images') + photo_filter.add_pixbuf_formats() + photo_filter.add_custom(gtk.FILE_FILTER_FILENAME | + gtk.FILE_FILTER_MIME_TYPE, + self.filter_dcraw_known, + None) + self.chooser.add_filter(photo_filter) + + raw_filter = gtk.FileFilter() + raw_filter.set_name('RAW photos') + raw_filter.add_custom(gtk.FILE_FILTER_FILENAME | + gtk.FILE_FILTER_MIME_TYPE, + self.filter_dcraw_known, + None) + self.chooser.add_filter(raw_filter) + + all_filter = gtk.FileFilter() + all_filter.set_name('All files') + all_filter.add_pattern('*') + self.chooser.add_filter(all_filter) + + + def enable(self): + self.mwc.add_to_menu('file_menu', 'import_menuitem', + 'Import photos') + + def disable(self): + self.mwc.remove_from_menu('file_menu', 'import_menuitem') + + def on_import_menuitem_activate(self, *args): + self.chooser.show() + response = self.chooser.run() + self.chooser.hide() + if response == gtk.RESPONSE_OK: + for pathname in self.chooser.get_filenames(): + job = ImportPhoto(pathname) + self.mwc.add_bgjob(job) + + def filter_dcraw_known(self, filter_info, data): + pathname, uri, display_name, mime_type = filter_info + return self.dtc.supported(pathname) + |