First patch for "Finding Duplicates" implementation
- From: Alvaro del Castillo <acs openshine com>
- To: F-Spot <f-spot-list gnome org>
- Subject: First patch for "Finding Duplicates" implementation
- Date: Wed, 22 Jun 2005 19:30:45 +0200
Hi guys!
Here goes the first patch that implements "Finding Duplicates" as I have
written in:
http://mail.gnome.org/archives/f-spot-list/2005-June/msg00031.html
To play with it:
1. Download F-Spot from CVS
2. cd "f-spot"
3. Save the patch attached to this email, "f-spot-duplicates.diff", in
the "f-spot" directory
4. patch -p0 < f-spot-duplicates.diff
5. Compile and install
6. Launch F-Spot and import some photos with duplicates
7. Go to Find->Find Duplicates
8. PLAY :)
9. Report experience to the list
I have to play more with my big collection of photos full of duplicates
in order to play with the UI and find the best way to help the user to
clean the duplicates, but I feel that the basics of the feature could be
the one in the patch.
The patch change the database schema so you will need to recreate your
database. I haven't done any effort to upgrade nicely the database from
earlier versions because in "README" we can read:
<<If things stop working after a CVS update, chances are that
the database format has changed. In that case you will have
to nuke your database (rm ~/.gnome2/f-spot/photos.db) and
start over, importing all your pictures again.>>
Cheers
-- Alvaro
Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.202
diff -u -b -B -p -u -r1.202 MainWindow.cs
--- src/MainWindow.cs 18 Jun 2005 22:07:10 -0000 1.202
+++ src/MainWindow.cs 22 Jun 2005 17:12:43 -0000
@@ -10,6 +10,9 @@ using System.Collections;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
+using System.IO;
+using System.Security.Cryptography;
+
using LibGPhoto2;
public class MainWindow {
@@ -17,6 +20,7 @@ public class MainWindow {
Db db;
+
TagSelectionWidget tag_selection_widget;
[Glade.Widget] Gtk.Window main_window;
[Glade.Widget] Gtk.VBox left_vbox;
@@ -1633,6 +1637,77 @@ public class MainWindow {
void HandleClearDateRange (object sender, EventArgs args) {
query.Range = null;
}
+
+ void HandleFindDuplicates (object sender, EventArgs args) {
+ Tag tag_duplicate = null;
+ foreach (Tag tag in db.Tags.RootCategory.Children) {
+ if (string.Compare (tag.Name, "Duplicates") == 0) {
+ tag_duplicate = tag;
+ break;
+ }
+ }
+ if (tag_duplicate == null) {
+ tag_duplicate = db.Tags.CreateTag (null, "Duplicates");
+ tag_duplicate.StockIconName = "f-spot-hidden.png";
+ tag_duplicate.SortPriority = -11;
+ db.Tags.Commit (tag_duplicate);
+ tag_selection_widget.Update ();
+ }
+ System.Console.WriteLine ("Looking for duplicates ...");
+ if (!PhotoSelectionActive()) {
+ icon_view.SelectAllCells ();
+ }
+
+ main_window.GdkWindow.Cursor = new Gdk.Cursor (Gdk.CursorType.Watch);
+ main_window.GdkWindow.Display.Sync ();
+
+ // A really simple implementation: Build hash table with MD5 of images
+ // and we later use it to find duplicates.
+ Hashtable photos_md5 = new Hashtable ();
+
+ foreach (int num in SelectedIds ()) {
+ Photo photo = query.Photos [num];
+ if (string.Compare(photo.MD5Sum, "") != 0) {
+ photos_md5.Add (num, photo.MD5Sum);
+ continue;
+ }
+ // Computing time is measured
+ long startTime = DateTime.Now.Ticks;
+ FileStream fs = new FileStream(photo.Path, FileMode.Open, FileAccess.Read);
+ MD5 md5ServiceProvider = new MD5CryptoServiceProvider();
+ byte[] md5 = md5ServiceProvider.ComputeHash(fs);
+
+ StringBuilder hash = new StringBuilder();
+ for (int pos = 0; pos < md5.Length; pos++) {
+ hash.Append(md5[pos].ToString("X2").ToLower());
+ }
+ long endTime = DateTime.Now.Ticks;
+ TimeSpan timeTaken = new TimeSpan(endTime - startTime);
+ Console.WriteLine("MD5 compute: {0}", timeTaken.ToString());
+
+ photos_md5.Add (num, hash);
+ photo.MD5Sum = hash.ToString ();
+ db.Photos.Commit (photo);
+ }
+
+ ICollection md5keys = photos_md5.Keys;
+ foreach (int num in SelectedIds ()) {
+ foreach (int key in md5keys) {
+ if (string.Compare(key.ToString(), num.ToString()) != 0 &&
+ string.Compare(photos_md5[num].ToString(), photos_md5[key].ToString()) == 0) {
+ Tag [] tags = new Tag [1];
+ tags [0] = tag_duplicate;
+ AddTagExtended (num, tags);
+ icon_view.ScrollTo(num);
+ break;
+ }
+ }
+ }
+ tag_selection_widget.Select (tag_duplicate);
+ UpdateQuery ();
+ SetViewMode (ModeType.IconView);
+ main_window.GdkWindow.Cursor = null;
+ }
// Version Id updates.
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/f-spot/src/Makefile.am,v
retrieving revision 1.31
diff -u -b -B -p -u -r1.31 Makefile.am
Index: src/PhotoStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoStore.cs,v
retrieving revision 1.67
diff -u -b -B -p -u -r1.67 PhotoStore.cs
--- src/PhotoStore.cs 28 May 2005 10:35:45 -0000 1.67
+++ src/PhotoStore.cs 22 Jun 2005 17:12:46 -0000
@@ -28,6 +28,7 @@ public class Photo : DbItem, IComparable
return Compare (this, photo);
}
+ // FIXME: With md5sum field this could be easy
public static int Compare (Photo photo1, Photo photo2)
{
int result = photo1.Id.CompareTo (photo2.Id);
@@ -134,6 +135,16 @@ public class Photo : DbItem, IComparable
}
}
+ private string md5sum;
+ public string MD5Sum {
+ get {
+ return md5sum;
+ }
+ set {
+ md5sum = value;
+ }
+ }
+
// Version management
public const int OriginalVersionId = 1;
private uint highest_version_id;
@@ -378,6 +389,7 @@ public class Photo : DbItem, IComparable
this.name = name;
description = "";
+ md5sum = "";
// Note that the original version is never stored in the photo_versions table in the
// database.
@@ -478,7 +490,8 @@ public class PhotoStore : DbStore {
" directory_path STRING NOT NULL, " +
" name STRING NOT NULL, " +
" description TEXT NOT NULL, " +
- " default_version_id INTEGER NOT NULL " +
+ " default_version_id INTEGER NOT NULL, " +
+ " md5sum STRING NOT NULL " +
")";
command.ExecuteNonQuery ();
@@ -529,8 +542,8 @@ public class PhotoStore : DbStore {
command.Connection = Connection;
command.CommandText = String.Format ("INSERT INTO photos (time, " +
- "directory_path, name, description, default_version_id) " +
- " VALUES ({0}, '{1}', '{2}', '', {3}) ",
+ "directory_path, name, description, default_version_id, md5sum) " +
+ " VALUES ({0}, '{1}', '{2}', '', {3},'')",
unix_time,
SqlString (System.IO.Path.GetDirectoryName (path)),
SqlString (System.IO.Path.GetFileName (path)),
@@ -718,7 +731,8 @@ public class PhotoStore : DbStore {
" directory_path, " +
" name, " +
" description, " +
- " default_version_id " +
+ " default_version_id, " +
+ " md5sum " +
" FROM photos " +
" WHERE id = {0} ",
id);
@@ -732,6 +746,7 @@ public class PhotoStore : DbStore {
photo.Description = reader[3].ToString ();
photo.DefaultVersionId = Convert.ToUInt32 (reader[4]);
+ photo.MD5Sum = reader[5].ToString ();
AddToCache (photo);
}
@@ -885,11 +900,13 @@ public class PhotoStore : DbStore {
SqliteCommand command = new SqliteCommand ();
command.Connection = Connection;
- command.CommandText = String.Format ("UPDATE photos SET description = '{0}', " +
- " default_version_id = {1} " +
- " WHERE id = {2}",
+ command.CommandText = String.Format ("UPDATE photos SET description = '{0}'," +
+ " default_version_id = {1}," +
+ " md5sum = '{2}'"+
+ " WHERE id = {3}",
SqlString (photo.Description),
photo.DefaultVersionId,
+ SqlString (photo.MD5Sum),
photo.Id);
command.ExecuteNonQuery ();
command.Dispose ();
@@ -994,6 +1011,7 @@ public class PhotoStore : DbStore {
photo.Description = reader[4].ToString ();
photo.DefaultVersionId = Convert.ToUInt32 (reader[5]);
+ photo.MD5Sum = reader[6].ToString ();
version_list.Add (photo);
}
@@ -1033,7 +1051,8 @@ public class PhotoStore : DbStore {
" photos.directory_path, " +
" photos.name, " +
" photos.description, " +
- " photos.default_version_id " +
+ " photos.default_version_id, " +
+ " photos.md5sum " +
" FROM photos " +
" WHERE directory_path = \"{0}\"", dir.FullName);
@@ -1073,7 +1092,8 @@ public class PhotoStore : DbStore {
" photos.directory_path, " +
" photos.name, " +
" photos.description, " +
- " photos.default_version_id " +
+ " photos.default_version_id, " +
+ " photos.md5sum " +
" FROM photos ");
if (range != null) {
Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.101
diff -u -b -B -p -u -r1.101 f-spot.glade
--- src/f-spot.glade 17 Jun 2005 16:11:25 -0000 1.101
+++ src/f-spot.glade 22 Jun 2005 17:13:17 -0000
@@ -7128,6 +7128,15 @@ Photo Details</property>
</child>
<child>
+ <widget class="GtkMenuItem" id="find_duplicates">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Find Duplicates</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="HandleFindDuplicates" last_modification_time="Tue, 10 Aug 2004 07:08:24 GMT"/>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkSeparatorMenuItem" id="separator15">
<property name="visible">True</property>
</widget>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]