]> git.zarvox.org Git - wp3.git/commitdiff
Add batch photo import by timestamp and batch import preview.
authorDrew Fisher <drew.m.fisher@gmail.com>
Wed, 26 Aug 2009 00:52:34 +0000 (19:52 -0500)
committerDrew Fisher <drew.m.fisher@gmail.com>
Wed, 26 Aug 2009 00:52:34 +0000 (19:52 -0500)
A massive improvement to the "click-and-pray" netid-only importer.
This changeset provides a preview of the photos that will be imported,
allowing for review before committing all the changes, as well as
progress bars (since loading large photos is a time-consuming task).
In addition, we now support importing large sets of photos based on
relative timestamps.  This will work provided you have exactly the same
number of photos to import as you do people in the database without a
photo.

mergephotos.py

index b9c33a93bf5145ba7d35a6d996f95baa34557e17..02a9c46ce3bae04df04807bfaee34d97119c6112 100644 (file)
@@ -2,6 +2,38 @@ from PyQt4.QtCore import *
 from PyQt4.QtGui import *
 from PyQt4.QtSql import *
 
+class MergePreview(QDialog):
+       def __init__(self, parent=None):
+               QDialog.__init__(self, parent)
+               self.layout = QGridLayout()
+               self.okay = QPushButton("Import")
+               self.bad = QPushButton("Cancel")
+               self.scrollarea = QScrollArea()
+               self.scrollcontents = QWidget()
+               self.scrollcontents.resize(700,600)
+               self.innerlayout = QGridLayout()
+               self.scrollcontents.setLayout(self.innerlayout)
+               self.layout.addWidget(self.scrollarea, 0, 0, 1, 2)
+               self.layout.addWidget(self.okay, 1, 0 )
+               self.layout.addWidget(self.bad, 1, 1 )
+               self.scrollarea.setWidget(self.scrollcontents)
+               QObject.connect( self.okay, SIGNAL("clicked()"), self.accept )
+               QObject.connect( self.bad, SIGNAL("clicked()"), self.reject )
+               self.setLayout(self.layout)
+               self.resize(750,600)
+       def addToList(self, name, photo):
+               row = self.innerlayout.rowCount()
+               name_label = QLabel(name)
+               name_label.setAlignment(Qt.AlignCenter)
+               self.innerlayout.addWidget(name_label, row, 0)
+               pic_label = QLabel()
+               pic_label.setAlignment(Qt.AlignCenter)
+               pic_label.setPixmap(photo)
+               self.innerlayout.addWidget(pic_label, row, 1)
+       def doneAdding(self):
+               self.scrollcontents.resize(700, (self.innerlayout.rowCount()+1) * 300)
+
+
 class MergePhotos(QWidget):
        def __init__(self, parent=None, db=None):
                QWidget.__init__(self, parent)
@@ -29,18 +61,116 @@ class MergePhotos(QWidget):
                        dir = QDir(foldertext)
                        #dir.setNameFilters(["*.jpg", "*.JPG"])
                        q = QSqlQuery(self.db)
-                       q.exec_("SELECT id, netid FROM people WHERE photo IS NULL")
+                       q.exec_("SELECT id, netid, forename, surname FROM people WHERE photo IS NULL")
                        rec = q.record()
                        col_id = rec.indexOf("id")
                        col_netid = rec.indexOf("netid")
-                       while q.next():
-                               # if netid.jpg exists, load it, write it to a QByteArray, bind it, and update that row
-                               fileName = q.value(col_netid).toString() + QString(".jpg")
+                       col_forename = rec.indexOf("forename")
+                       col_surname = rec.indexOf("surname")
+                       people = [] # Tuples of (id, netid, name)
+                       while q.next(): # Fetch results
+                               people.append( (q.value(col_id).toString(), q.value(col_netid).toString(), q.value(col_forename).toString() + QString(" ") + q.value(col_surname).toString() ) )
+                       merging_people = [] # records that have matching photos
+                       filelist = [] # the corresponding photos
+                       for person in people:
+                               fileName = person[1] + QString(".jpg")
                                if not dir.exists(fileName):
-                                       fileName = q.value(col_netid).toString() + QString(".JPG")
+                                       fileName = person[1] + QString(".JPG")
                                if dir.exists(fileName):
+                                       merging_people.append(person)
+                                       filelist.append(fileName)
+                       # Generate preview
+                       preview = MergePreview(self)
+                       progress = QProgressDialog("Preparing preview...", "Cancel", 0, len(merging_people))
+                       progress.setWindowModality(Qt.WindowModal)
+                       for i in xrange(len(merging_people)):
+                               progress.setValue(i)
+                               if progress.wasCanceled():
+                                       progress.setValue(len(merging_people))
+                                       return
+                               image = QImage()
+                               image.load(dir.absoluteFilePath(filelist[i]))
+                               preview.addToList( merging_people[i][2] + QString("\n") + merging_people[i][1], QPixmap.fromImage(image.scaled(QSize(400,300), Qt.KeepAspectRatio)) )
+                       progress.setValue(len(merging_people))
+                       preview.doneAdding()
+
+                       if not preview.exec_():
+                               return
+
+                       # If preview accepted, proceed with the import
+                       progress = QProgressDialog("Importing photos...", "Can't cancel!", 0, len(merging_people))
+                       progress.setWindowModality(Qt.WindowModal)
+                       for i in xrange(len(merging_people)):
+                               progress.setValue(i)
+                               progress.setLabelText(QString("Importing photo for %1...").arg(merging_people[i][2]) )
+                               # if netid.jpg exists, load it, write it to a QByteArray, bind it, and update that row
+                               image = QImage()
+                               image.load(dir.absoluteFilePath(filelist[i]))
+                               ba = QByteArray()
+                               buffer = QBuffer(ba)
+                               buffer.open(QIODevice.WriteOnly)
+                               image.save(buffer, "JPG")
+                               buffer.close()
+                               update_q = QSqlQuery(self.db)
+                               update_q.prepare("UPDATE people SET photo=:photo WHERE id=:id")
+                               update_q.bindValue(":photo", QVariant(ba))
+                               update_q.bindValue(":id", merging_people[i][0])
+                               update_q.exec_()
+                               print "Auto-imported photo for", merging_people[i][2]
+                       progress.setValue(len(merging_people))
+                       self.done()
+
+       def beginMergeTimestamp(self):
+               foldertext = QFileDialog.getExistingDirectory( None, "Pick folder of photos", ".")
+               if not foldertext.isEmpty():
+                       print foldertext
+                       dir = QDir(foldertext)
+                       dir.setNameFilters(["*.jpg", "*.JPG"]) # Only import jpegs (for now)
+                       dir.setFilter(QDir.Files | QDir.Readable) # Don't list subdirectories
+                       dir.setSorting(QDir.Time) # Sort by mtime (should probably make this sort by ctime, or better, EXIF ctime, but in the general case this should work)
+                       q = QSqlQuery(self.db)
+                       q.exec_("SELECT id, forename, surname FROM people WHERE photo IS NULL ORDER BY createtime")
+                       rec = q.record()
+                       col_id = rec.indexOf("id")
+                       col_forename = rec.indexOf("forename")
+                       col_surname = rec.indexOf("surname")
+                       people = [] # List of tuples (id, name)
+                       while q.next():
+                               people.append( (q.value(col_id).toString(), q.value(col_forename).toString() + QString(" ") + q.value(col_surname).toString() ) )
+                       photofiles = dir.entryList()
+                       print len(people), "people without photos"
+                       print len(photofiles), "photo files provided"
+                       if len(people) == len(photofiles):
+                               print "merging by timestamp possible, generating preview"
+                               preview = MergePreview(self)
+                               # do some progress bar magic
+                               progress = QProgressDialog("Preparing preview...", "Cancel", 0, len(people) )
+                               progress.setWindowModality(Qt.WindowModal)
+                               for i in xrange(len(people)):
+                                       progress.setValue(i)
+                                       if progress.wasCanceled():
+                                               progress.setValue(len(people))
+                                               return
                                        image = QImage()
-                                       image.load(dir.absoluteFilePath(fileName))
+                                       image.load(dir.absoluteFilePath(photofiles[i]))
+                                       preview.addToList(people[i][1], QPixmap.fromImage(image.scaled(QSize(400,300), Qt.KeepAspectRatio)) )
+                               progress.setValue(len(people))
+                               preview.doneAdding()
+
+                               if not preview.exec_():
+                                       return
+
+                               # If preview accepted, proceed with the import
+                               progress = QProgressDialog("Importing photos...", "Abort", 0, len(people))
+                               progress.setWindowModality(Qt.WindowModal)
+                               for i in xrange(len(people)):
+                                       progress.setValue(i)
+                                       progress.setLabelText(QString("Importing photo for %1...").arg(people[i][1] ))
+                                       if progress.wasCanceled():
+                                               progress.setValue(len(people))
+                                               return
+                                       image = QImage()
+                                       image.load(dir.absoluteFilePath(photofiles[i]))
                                        ba = QByteArray()
                                        buffer = QBuffer(ba)
                                        buffer.open(QIODevice.WriteOnly)
@@ -49,14 +179,13 @@ class MergePhotos(QWidget):
                                        update_q = QSqlQuery(self.db)
                                        update_q.prepare("UPDATE people SET photo=:photo WHERE id=:id")
                                        update_q.bindValue(":photo", QVariant(ba))
-                                       update_q.bindValue(":id", q.value(col_id))
+                                       update_q.bindValue(":id", people[i][0])
                                        update_q.exec_()
-                                       print "Auto-imported photo for",q.value(col_netid).toString()
-                       self.done()
-
-       def beginMergeTimestamp(self):
-               print "merging by timestamp"
-               self.done()
+                                       print "Auto-imported photo for", people[i][1]
+                               progress.setValue(len(people))
+                               self.done()
+                       else:
+                               print "incorrect number of photos, can't merge"
 
        def done(self):
                self.emit(SIGNAL("done()") )