[f-spot] Cleaned up the FSpot.Exporters.Folder project



commit bb7b7dfe2466c2b40175a2fbf3ca6383dcc588d0
Author: Stephen Shaw <sshaw decriptor com>
Date:   Sat Dec 3 00:55:05 2011 -0700

    Cleaned up the FSpot.Exporters.Folder project
    
    This is the start to cleaning things up and adding
    unit tests to each project.

 .../FSpot.Exporters.Folder.csproj                  |    3 +
 .../FSpot.Exporters.Folder/FolderExport.cs         | 1053 +-------------------
 .../FSpot.Exporters.Folder/FolderGallery.cs        |  262 +++++
 .../FSpot.Exporters.Folder/HtmlGallery.cs          |  764 ++++++++++++++
 .../FSpot.Exporters.Folder/OriginalGallery.cs      |  182 ++++
 .../Exporters/FSpot.Exporters.Folder/Makefile.am   |    6 +-
 6 files changed, 1223 insertions(+), 1047 deletions(-)
---
diff --git a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder.csproj b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder.csproj
index d4f28c9..7ae2848 100644
--- a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder.csproj
+++ b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder.csproj
@@ -32,6 +32,9 @@
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <ItemGroup>
     <Compile Include="FSpot.Exporters.Folder\FolderExport.cs" />
+    <Compile Include="FSpot.Exporters.Folder\FolderGallery.cs" />
+    <Compile Include="FSpot.Exporters.Folder\OriginalGallery.cs" />
+    <Compile Include="FSpot.Exporters.Folder\HtmlGallery.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="Resources\f-spot.js">
diff --git a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderExport.cs b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderExport.cs
index 3e1ebfb..270f228 100644
--- a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderExport.cs
+++ b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderExport.cs
@@ -72,8 +72,10 @@ using FSpot.Widgets;
 using FSpot.Utils;
 using FSpot.UI.Dialog;
 
-namespace FSpot.Exporters.Folder {
-	public class FolderExport : FSpot.Extensions.IExporter {
+namespace FSpot.Exporters.Folder
+{
+	public class FolderExport : FSpot.Extensions.IExporter
+	{
 		IBrowsableCollection selection;
 
 		[GtkBeans.Builder.Object] Gtk.Dialog dialog;
@@ -219,10 +221,10 @@ namespace FSpot.Exporters.Folder {
 				}
 
 				if (exportTags)
-					gallery.SetExportTags ();
+					gallery.ExportTags = true;
 
 				if (exportTagIcons)
-					gallery.SetExportTagIcons ();
+					gallery.ExportTagIcons = true;
 
 				gallery.Description = description;
 				gallery.GenerateLayout ();
@@ -309,9 +311,8 @@ namespace FSpot.Exporters.Folder {
 
 		private void Progress (long current_num_bytes, long total_num_bytes)
 		{
-			if (total_num_bytes > 0) {
+			if (total_num_bytes > 0)
 				progress_dialog.Fraction = current_num_bytes / (double)total_num_bytes;
-			}
 		}
 
 		private void HandleResponse (object sender, Gtk.ResponseArgs args)
@@ -396,1044 +397,4 @@ namespace FSpot.Exporters.Folder {
 			}
 		}
 	}
-
-	internal class FolderGallery
-	{
-		protected IBrowsableCollection collection;
-		protected string gallery_name;
-		protected string gallery_path;
-		protected bool scale;
-		protected int size;
-		protected bool exportTags;
-		protected bool exportTagIcons;
-		protected string description;
-		protected string language;
-		protected System.Uri destination;
-
-		protected ScaleRequest [] requests;
-
-		protected string [] pixbuf_keys = { "quality", null };
-		protected string [] pixbuf_values = { "95", null };
-
-		protected struct ScaleRequest {
-			public string Name;
-			public int Width;
-			public int Height;
-			public bool Skip;
-			public bool CopyExif;
-
-			public ScaleRequest (string name, int width, int height, bool skip) : this (name, width, height, skip, false) {}
-
-			public ScaleRequest (string name, int width, int height, bool skip, bool exif)
-			{
-				this.Name = name != null ? name : String.Empty;
-				this.Width = width;
-				this.Height = height;
-				this.Skip = skip;
-				this.CopyExif = exif;
-			}
-
-			public static ScaleRequest Default = new ScaleRequest (String.Empty, 0, 0, false);
-
-			public bool AvoidScale (int size) {
-				return (size < this.Width && size < this.Height && this.Skip);
-			}
-		}
-
-		internal FolderGallery (IBrowsableCollection selection, string path, string gallery_name)
-		{
-			this.collection = selection;
-			this.gallery_name = gallery_name;
-			this.gallery_path = Path.Combine (path, gallery_name);
-			this.requests = new ScaleRequest [] { ScaleRequest.Default };
-		}
-
-		public virtual void GenerateLayout ()
-		{
-			MakeDir (gallery_path);
-
-		}
-
-		protected virtual string ImageName (int image_num)
-		{
-            var uri = collection [image_num].DefaultVersion.Uri;
-            var dest_uri = new SafeUri (gallery_path);
-
-            // Find an unused name
-            int i = 1;
-            var dest = dest_uri.Append (uri.GetFilename ());
-            var file = GLib.FileFactory.NewForUri (dest);
-            while (file.Exists) {
-                var filename = uri.GetFilenameWithoutExtension ();
-                var extension = uri.GetExtension ();
-                dest = dest_uri.Append (String.Format ("{0}-{1}{2}", filename, i++, extension));
-                file = GLib.FileFactory.NewForUri (dest);
-            }
-
-            return dest.GetFilename ();
-		}
-
-		public void ProcessImage (int image_num, FilterSet filter_set)
-		{
-			IPhoto photo = collection [image_num];
-			string path;
-			ScaleRequest req;
-
-			req = requests [0];
-
-			MakeDir (SubdirPath (req.Name));
-			path = SubdirPath (req.Name, ImageName (image_num));
-
-			using (FilterRequest request = new FilterRequest (photo.DefaultVersion.Uri)) {
-				filter_set.Convert (request);
-				if (request.Current.LocalPath == path)
-					request.Preserve(request.Current);
-				else
-					System.IO.File.Copy (request.Current.LocalPath, path, true);
-
-				if (photo != null && photo is Photo && App.Instance.Database != null) {
-					App.Instance.Database.Exports.Create ((photo as Photo).Id, (photo as Photo).DefaultVersionId,
-								      ExportStore.FolderExportType,
-								      // FIXME this is wrong, the final path is the one
-								      // after the Xfer.
-								      new SafeUri (path).ToString ());
-				}
-
-				for (int i = 1; i < requests.Length; i++) {
-
-					req = requests [i];
-					if (scale && req.AvoidScale (size))
-						continue;
-
-					FilterSet req_set = new FilterSet ();
-					req_set.Add (new ResizeFilter ((uint)Math.Max (req.Width, req.Height)));
-
-					bool sharpen;
-					try {
-						sharpen = Preferences.Get<bool> (FolderExport.SHARPEN_KEY);
-					} catch (NullReferenceException) {
-						sharpen = true;
-						Preferences.Set (FolderExport.SHARPEN_KEY, true);
-					}
-
-					if (sharpen) {
-						if (req.Name == "lq")
-							req_set.Add (new SharpFilter (0.1, 2, 4));
-						if (req.Name == "thumbs")
-							req_set.Add (new SharpFilter (0.1, 2, 5));
-					}
-					using (FilterRequest tmp_req = new FilterRequest (photo.DefaultVersion.Uri)) {
-						req_set.Convert (tmp_req);
-						MakeDir (SubdirPath (req.Name));
-						path = SubdirPath (req.Name, ImageName (image_num));
-						System.IO.File.Copy (tmp_req.Current.LocalPath, path, true);
-					}
-				}
-			}
-		}
-
-		protected string MakeDir (string path)
-		{
-			try {
-				Directory.CreateDirectory (path);
-			} catch {
-				Log.ErrorFormat ("Error in creating directory \"{0}\"", path);
-			}
-			return path;
-		}
-
-		protected string SubdirPath (string subdir)
-		{
-			return SubdirPath (subdir, null);
-		}
-
-		protected string SubdirPath (string subdir, string file)
-		{
-			string path = Path.Combine (gallery_path, subdir);
-			if (file != null)
-				path = Path.Combine (path, file);
-
-			return path;
-		}
-
-		public string GalleryPath {
-			get {
-				return gallery_path;
-			}
-		}
-
-		public string Description {
-			get {
-				return description;
-			}
-			set {
-				description = value;
-			}
-		}
-
-		public string Language {
-			get {
-				if (language == null)
-					language=GetLanguage();
-				return language;
-			}
-		}
-
-		public Uri Destination {
-			get {
-				return destination;
-			}
-			set {
-				this.destination = value;
-			}
-		}
-
-		public void SetScale (int size) {
-			this.scale = true;
-			this.size = size;
-			requests [0].Width = size;
-			requests [0].Height = size;
-		}
-
-		public void SetExportTags () {
-			this.exportTags = true;
-		}
-
-		public void SetExportTagIcons () {
-			this.exportTagIcons = true;
-		}
-
-		private string GetLanguage()
-		{
-			string language;
-
-			if ((language = Environment.GetEnvironmentVariable ("LC_ALL")) == null)
-				if ((language = Environment.GetEnvironmentVariable ("LC_MESSAGES")) == null)
-					if ((language = Environment.GetEnvironmentVariable ("LANG")) == null)
-						language = "en";
-
-			if (language.IndexOf('.') >= 0)
-				language = language.Substring(0,language.IndexOf('.'));
-			if (language.IndexOf('@') >= 0)
-				language = language.Substring(0,language.IndexOf('@'));
-			language = language.Replace('_','-');
-
-			return language;
-		}
-	}
-
-	class OriginalGallery : FolderGallery
-	{
-		public OriginalGallery (IBrowsableCollection selection, string path, string name) : base (selection, path, name)
-		{
-			requests = new ScaleRequest [] { new ScaleRequest ("hq", 0, 0, false),
-							 new ScaleRequest ("mq", 800, 600, true),
-							 new ScaleRequest ("lq", 640, 480, false, true),
-							 new ScaleRequest ("thumbs", 120, 120, false) };
-		}
-
-		public override void GenerateLayout ()
-		{
-			base.GenerateLayout ();
-			MakeDir (SubdirPath ("comments"));
-			CreateHtaccess();
-			CreateInfo();
-			SetTime ();
-		}
-
-		protected override string ImageName (int photo_index)
-		{
-			return String.Format ("img-{0}.jpg", photo_index + 1);
-		}
-
-		private void SetTime ()
-		{
-			try {
-				for (int i = 0; i < collection.Count; i++)
-					CreateComments (collection [i].DefaultVersion.Uri.LocalPath, i);
-
-				Directory.SetLastWriteTimeUtc(gallery_path, collection [0].Time);
-			} catch (System.Exception e) {
-				Log.Error (e.ToString ());
-			}
-		}
-
-		internal void CreateZip ()
-		{
-			MakeDir (SubdirPath ("zip"));
-			try {
-				if (System.IO.Directory.Exists (SubdirPath ("mq")))
-				    CreateZipFile("mq");
-
-				if (System.IO.Directory.Exists (SubdirPath ("hq")))
-				    CreateZipFile("hq");
-
-			} catch (System.Exception e) {
-				Log.Error (e.ToString ());
-			}
-		}
-
-		private void CreateComments(string photo_path, int photo_index)
-		{
-			StreamWriter comment = File.CreateText(SubdirPath  ("comments", photo_index + 1 + ".txt"));
-			comment.Write("<span>photo " + (photo_index + 1) + "</span> ");
-			comment.Write (collection [photo_index].Description + Environment.NewLine);
-			comment.Close();
-		}
-
-		private void CreateZipFile(string img_quality)
-		{
-			string[] filenames = Directory.GetFiles(SubdirPath (img_quality));
-			Crc32 crc = new Crc32();
-			ZipOutputStream s = new ZipOutputStream(File.Create(SubdirPath ("zip", img_quality + ".zip")));
-
-			s.SetLevel(0);
-			foreach (string file in filenames) {
-				FileStream fs = File.OpenRead(file);
-
-				byte[] buffer = new byte[fs.Length];
-				fs.Read(buffer, 0, buffer.Length);
-				ZipEntry entry = new ZipEntry(Path.GetFileName(file));
-
-				entry.DateTime = DateTime.Now;
-
-				// set Size and the crc, because the information
-				// about the size and crc should be stored in the header
-				// if it is not set it is automatically written in the footer.
-				// (in this case size == crc == -1 in the header)
-				// Some ZIP programs have problems with zip files that don't store
-				// the size and crc in the header.
-				entry.Size = fs.Length;
-				fs.Close();
-
-				crc.Reset();
-				crc.Update(buffer);
-
-				entry.Crc  = crc.Value;
-
-				s.PutNextEntry(entry);
-
-				s.Write(buffer, 0, buffer.Length);
-
-			}
-
-			s.Finish();
-			s.Close();
-		}
-
-		private void CreateHtaccess()
-		{
-			StreamWriter htaccess = File.CreateText(Path.Combine (gallery_path,".htaccess"));
-			htaccess.Write("<Files info.txt>" + Environment.NewLine + "\tdeny from all" + Environment.NewLine+ "</Files>" + Environment.NewLine);
-			htaccess.Close();
-		}
-
-		private void CreateInfo()
-		{
-			StreamWriter info = File.CreateText(Path.Combine (gallery_path, "info.txt"));
-			info.WriteLine("name|" + gallery_name);
-			info.WriteLine("date|" + collection [0].Time.Date.ToString ("dd.MM.yyyy"));
-			info.WriteLine("description|" + description);
-			info.Close();
-		}
-	}
-
-	class HtmlGallery : FolderGallery
-	{
-		int perpage = 16;
-		string stylesheet = "f-spot-simple.css";
-		string altstylesheet = "f-spot-simple-white.css";
-		string javascript = "f-spot.js";
-
-		//Note for translators: light as clear, opposite as dark
-		static string light = Catalog.GetString("Light");
-		static string dark = Catalog.GetString("Dark");
-
-		List<string> allTagNames = new List<string> ();
-		Dictionary<string,Tag> allTags = new Dictionary<string, Tag> ();
-		Dictionary<string, List<int>> tagSets = new Dictionary<string, List<int>> ();
-
-		public HtmlGallery (IBrowsableCollection selection, string path, string name) : base (selection, path, name)
-		{
-			requests = new ScaleRequest [] { new ScaleRequest ("hq", 0, 0, false),
-							 new ScaleRequest ("mq", 480, 320, false),
-							 new ScaleRequest ("thumbs", 120, 90, false) };
-		}
-
-		protected override string ImageName (int photo_index)
-		{
-			return String.Format ("img-{0}.jpg", photo_index + 1);
-		}
-
-		public override void GenerateLayout ()
-		{
-			if (collection.Count == 0)
-				return;
-
-			base.GenerateLayout ();
-
-			IPhoto [] photos = collection.Items;
-
-			int i;
-			for (i = 0; i < photos.Length; i++)
-				SavePhotoHtmlIndex (i);
-
-			for (i = 0; i < PageCount; i++)
-				SaveHtmlIndex (i);
-
-			if (exportTags) {
-				// identify tags present in these photos
-				i = 0;
-				foreach (IPhoto photo in photos) {
-					foreach (var tag in photo.Tags) {
-						if (!tagSets.ContainsKey (tag.Name)) {
-							tagSets.Add (tag.Name, new List<int> ());
-							allTags.Add (tag.Name, tag);
-						}
-						tagSets [tag.Name].Add (i);
-					}
-					i++;
-				}
-				allTagNames = new List<string> (tagSets.Keys);
-				allTagNames.Sort ();
-
-				// create tag pages
-				SaveTagsPage ();
-				foreach (string tag in allTagNames) {
-					for (i = 0; i < TagPageCount (tag); i++)
-						SaveTagIndex (tag, i);
-				}
-			}
-
-			if (exportTags && exportTagIcons) {
-				SaveTagIcons ();
-			}
-
-			MakeDir (SubdirPath ("style"));
-			System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
-			using (Stream s = assembly.GetManifestResourceStream (stylesheet)) {
-				using (Stream fs = System.IO.File.Open (SubdirPath ("style", stylesheet), System.IO.FileMode.Create)) {
-
-					byte [] buffer = new byte [8192];
-					int n;
-					while ((n = s.Read (buffer, 0, buffer.Length)) != 0)
-						fs.Write (buffer, 0,  n);
-
-				}
-			}
-			/* quick and stupid solution
-			   this should have been iterated over an array of stylesheets, really
-			*/
-			using (Stream s = assembly.GetManifestResourceStream (altstylesheet)) {
-				using (Stream fs = System.IO.File.Open (SubdirPath ("style", altstylesheet), System.IO.FileMode.Create)) {
-
-					byte [] buffer = new byte [8192];
-					int n = 0;
-					while ((n = s.Read (buffer, 0, buffer.Length)) != 0)
-						fs.Write (buffer, 0,  n);
-
-				}
-			}
-
-			/* Javascript for persistant style change */
-			MakeDir (SubdirPath ("script"));
-			using (Stream s = assembly.GetManifestResourceStream (javascript)) {
-				using (Stream fs = System.IO.File.Open (SubdirPath ("script", javascript), System.IO.FileMode.Create)) {
-
-					byte [] buffer = new byte [8192];
-					int n = 0;
-					while ((n = s.Read (buffer, 0, buffer.Length)) != 0)
-						fs.Write (buffer, 0,  n);
-
-				}
-			}
-		}
-
-		public int PageCount {
-			get {
-				return 	(int) System.Math.Ceiling (collection.Items.Length / (double)perpage);
-			}
-		}
-
-		public int TagPageCount (string tag)
-		{
-			return (int) System.Math.Ceiling (tagSets [tag].Count / (double)perpage);
-		}
-
-		public string PhotoThumbPath (int item)
-		{
-			return System.IO.Path.Combine (requests [2].Name, ImageName (item));
-		}
-
-		public string PhotoWebPath (int item)
-		{
-			return System.IO.Path.Combine (requests [1].Name, ImageName (item));
-		}
-
-		public string PhotoOriginalPath (int item)
-		{
-			return System.IO.Path.Combine (requests [0].Name, ImageName (item));
-		}
-
-		public string PhotoIndexPath (int item)
-		{
-			return (System.IO.Path.GetFileNameWithoutExtension (ImageName (item)) + ".html");
-		}
-
-		public static void WritePageNav (System.Web.UI.HtmlTextWriter writer, string id, string url, string name)
-		{
-			writer.AddAttribute ("id", id);
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("href", url);
-			writer.RenderBeginTag ("a");
-			writer.Write (name);
-			writer.RenderEndTag ();
-
-			writer.RenderEndTag ();
-		}
-
-		public void SavePhotoHtmlIndex (int i)
-		{
-			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (PhotoIndexPath (i)));
-			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
-
-			//writer.Indent = 4;
-
-			//writer.Write ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
-			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
-			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
-			writer.AddAttribute ("xml:lang", this.Language);
-			writer.RenderBeginTag ("html");
-
-			WriteHeader (writer);
-
-			writer.AddAttribute ("onload", "checkForTheme()");
-			writer.RenderBeginTag ("body");
-
-			writer.AddAttribute ("class", "container1");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("class", "header");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("id", "title");
-			writer.RenderBeginTag ("div");
-			writer.Write (gallery_name);
-			writer.RenderEndTag ();
-
-			writer.AddAttribute ("class", "navi");
-			writer.RenderBeginTag ("div");
-
-			if (i > 0)
-				// Abbreviation of previous
-				WritePageNav (writer, "prev", PhotoIndexPath (i - 1), Catalog.GetString("Prev"));
-
-			WritePageNav (writer, "index", IndexPath (i / perpage), Catalog.GetString("Index"));
-
-			if (exportTags)
-				WritePageNav (writer, "tagpage", TagsIndexPath (), Catalog.GetString ("Tags"));
-
-			if (i < collection.Count -1)
-				WritePageNav (writer, "next", PhotoIndexPath (i + 1), Catalog.GetString("Next"));
-
-			writer.RenderEndTag (); //navi
-
-			writer.RenderEndTag (); //header
-
-			writer.AddAttribute ("class", "photo");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("href", PhotoOriginalPath (i));
-			writer.RenderBeginTag ("a");
-
-			writer.AddAttribute ("src", PhotoWebPath (i));
-			writer.AddAttribute ("alt", "#");
-			writer.AddAttribute ("class", "picture");
-			writer.RenderBeginTag ("img");
-			writer.RenderEndTag (); //img
-			writer.RenderEndTag (); //a
-
-			writer.AddAttribute ("id", "description");
-			writer.RenderBeginTag ("div");
-			writer.Write (collection [i].Description);
-			writer.RenderEndTag (); //div#description
-
-			writer.RenderEndTag (); //div.photo
-
-			WriteTagsLinks (writer, collection [i].Tags);
-
-			WriteStyleSelectionBox (writer);
-
-			writer.RenderEndTag (); //container1
-
-			WriteFooter (writer);
-
-			writer.RenderEndTag (); //body
-			writer.RenderEndTag (); // html
-
-			writer.Close ();
-			stream.Close ();
-		}
-
-		public static string IndexPath (int page_num)
-		{
-			if (page_num == 0)
-				return "index.html";
-			else
-				return String.Format ("index{0}.html", page_num);
-		}
-
-		public static string TagsIndexPath ()
-		{
-			return "tags.html";
-		}
-
-		public static string TagIndexPath (string tag, int page_num)
-		{
-			string name = "tag_"+tag;
-			name = name.Replace ("/", "_").Replace (" ","_");
-			if (page_num == 0)
-				return name + ".html";
-			else
-				return name + String.Format ("_{0}.html", page_num);
-		}
-
-		static string IndexTitle (int page)
-		{
-			return String.Format ("{0}", page + 1);
-		}
-
-		public void WriteHeader (System.Web.UI.HtmlTextWriter writer)
-		{
-			WriteHeader (writer, "");
-		}
-
-		public void WriteHeader (System.Web.UI.HtmlTextWriter writer, string titleExtension)
-		{
-			writer.RenderBeginTag ("head");
-			/* It seems HtmlTextWriter always uses UTF-8, unless told otherwise */
-			writer.Write ("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
-			writer.WriteLine ();
-			writer.RenderBeginTag ("title");
-			writer.Write (gallery_name + titleExtension);
-			writer.RenderEndTag ();
-
-			writer.Write ("<link type=\"text/css\" rel=\"stylesheet\" href=\"");
-			writer.Write (String.Format ("{0}", "style/" + stylesheet));
-			writer.Write ("\" title=\"" + dark + "\" media=\"screen\" />" + Environment.NewLine);
-
-			writer.Write ("<link type=\"text/css\" rel=\"prefetch ") ;
-			writer.Write ("alternate stylesheet\" href=\"");
-			writer.Write (String.Format ("{0}", "style/" + altstylesheet));
-			writer.Write ("\" title=\"" + light + "\" media=\"screen\" />" + Environment.NewLine);
-
-			writer.Write ("<script src=\"script/" + javascript + "\"");
-			writer.Write (" type=\"text/javascript\"></script>" + Environment.NewLine);
-
-			writer.RenderEndTag ();
-		}
-
-		public static void WriteFooter (System.Web.UI.HtmlTextWriter writer)
-		{
-			writer.AddAttribute ("class", "footer");
-			writer.RenderBeginTag ("div");
-
-			writer.Write (Catalog.GetString ("Gallery generated by") + " ");
-
-			writer.AddAttribute ("href", "http://f-spot.org";);
-			writer.RenderBeginTag ("a");
-			writer.Write (String.Format ("{0} {1}", FSpot.Core.Defines.PACKAGE, FSpot.Core.Defines.VERSION));
-			writer.RenderEndTag ();
-
-			writer.RenderEndTag ();
-		}
-
-		public static void WriteStyleSelectionBox (System.Web.UI.HtmlTextWriter writer)
-		{
-			//Style Selection Box
-			writer.AddAttribute ("id", "styleboxcontainer");
-			writer.RenderBeginTag ("div");
-			writer.AddAttribute ("id", "stylebox");
-			writer.AddAttribute ("style", "display: none;");
-			writer.RenderBeginTag ("div");
-			writer.RenderBeginTag ("ul");
-			writer.RenderBeginTag ("li");
-			writer.AddAttribute ("href", "#");
-			writer.AddAttribute ("title", dark);
-			writer.AddAttribute ("onclick", "setActiveStyleSheet('" + dark + "')");
-			writer.RenderBeginTag ("a");
-			writer.Write (dark);
-			writer.RenderEndTag (); //a
-			writer.RenderEndTag (); //li
-			writer.RenderBeginTag ("li");
-			writer.AddAttribute ("href", "#");
-			writer.AddAttribute ("title", light);
-			writer.AddAttribute ("onclick", "setActiveStyleSheet('" + light + "')");
-			writer.RenderBeginTag ("a");
-			writer.Write (light);
-			writer.RenderEndTag (); //a
-			writer.RenderEndTag (); //li
-			writer.RenderEndTag (); //ul
-			writer.RenderEndTag (); //div stylebox
-			writer.RenderBeginTag ("div");
-			writer.Write ("<span class=\"style_toggle\">");
-			writer.Write ("<a href=\"javascript:toggle_stylebox()\">");
-			writer.Write ("<span id=\"showlink\">" + Catalog.GetString("Show Styles") + "</span><span id=\"hidelink\" ");
-			writer.Write ("style=\"display:none;\">" + Catalog.GetString("Hide Styles") + "</span></a></span>" + Environment.NewLine);
-			writer.RenderEndTag (); //div toggle
-			writer.RenderEndTag (); //div styleboxcontainer
-		}
-
-		public void WriteTagsLinks (System.Web.UI.HtmlTextWriter writer, Tag[] tags)
-		{
-			List<Tag> tagsList = new List<Tag> (tags.Length);
-			foreach (var tag in tags) {
-				tagsList.Add (tag);
-			}
-			WriteTagsLinks (writer, tagsList);
-		}
-
-		public void WriteTagsLinks (System.Web.UI.HtmlTextWriter writer, System.Collections.ICollection tags)
-		{
-
-			// check if we should write tags
-			if (!exportTags && tags.Count>0)
-				return;
-
-			writer.AddAttribute ("id", "tagbox");
-			writer.RenderBeginTag ("div");
-			writer.RenderBeginTag ("h1");
-			writer.Write (Catalog.GetString ("Tags"));
-			writer.RenderEndTag (); //h1
-			writer.AddAttribute ("id", "innertagbox");
-			writer.RenderBeginTag ("ul");
-			foreach (Tag tag in tags) {
-				writer.AddAttribute ("class", "tag");
-				writer.RenderBeginTag ("li");
-				writer.AddAttribute ("href", TagIndexPath (tag.Name, 0));
-				writer.RenderBeginTag ("a");
-				if (exportTagIcons) {
-					writer.AddAttribute ("alt", tag.Name);
-					writer.AddAttribute ("longdesc", Catalog.GetString ("Tags: ")+tag.Name);
-					writer.AddAttribute ("title", Catalog.GetString ("Tags: ")+tag.Name);
-					writer.AddAttribute ("src", TagPath (tag));
-					writer.RenderBeginTag ("img");
-					writer.RenderEndTag ();
-				}
-				writer.Write(" ");
-				if (exportTagIcons)
-					writer.AddAttribute ("class", "tagtext-icon");
-				else
-					writer.AddAttribute ("class", "tagtext-noicon");
-				writer.RenderBeginTag ("span");
-				writer.Write (tag.Name);
-				writer.RenderEndTag (); //span.tagtext
-				writer.RenderEndTag (); //a href
-				writer.RenderEndTag (); //div.tag
-			}
-			writer.RenderEndTag (); //div#tagbox
-		}
-
-		public void SaveTagsPage ()
-		{
-			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (TagsIndexPath ()));
-			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
-
-			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
-			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
-			writer.AddAttribute ("xml:lang", this.Language);
-			writer.RenderBeginTag ("html");
-			string titleExtension = " " + Catalog.GetString ("Tags");
-			WriteHeader (writer, titleExtension);
-
-			writer.AddAttribute ("onload", "checkForTheme()");
-			writer.AddAttribute ("id", "tagpage");
-			writer.RenderBeginTag ("body");
-
-			writer.AddAttribute ("class", "container1");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("class", "header");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("id", "title");
-			writer.RenderBeginTag ("div");
-			writer.Write (gallery_name + titleExtension);
-			writer.RenderEndTag (); //title div
-
-			writer.AddAttribute ("class", "navi");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("class", "navipage");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("href", IndexPath (0));
-			writer.RenderBeginTag ("a");
-			writer.Write (Catalog.GetString ("Index"));
-			writer.RenderEndTag (); //a
-
-			writer.RenderEndTag (); //navipage
-			writer.RenderEndTag (); //navi
-			writer.RenderEndTag (); //header
-
-			WriteTagsLinks (writer, allTags.Values);
-
-			WriteStyleSelectionBox (writer);
-
-			writer.RenderEndTag (); //container1
-
-			WriteFooter (writer);
-
-			writer.RenderEndTag (); //body
-			writer.RenderEndTag (); //html
-
-			writer.Close ();
-			stream.Close ();
-		}
-
-		public void SaveTagIndex (string tag, int page_num)
-		{
-			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (TagIndexPath (tag, page_num)));
-			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
-
-			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
-			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
-			writer.AddAttribute ("xml:lang", this.Language);
-			writer.RenderBeginTag ("html");
-			string titleExtension = ": " + tag;
-			WriteHeader (writer, titleExtension);
-
-			writer.AddAttribute ("onload", "checkForTheme()");
-			writer.RenderBeginTag ("body");
-
-			writer.AddAttribute ("class", "container1");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("class", "header");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("id", "title");
-			writer.RenderBeginTag ("div");
-			writer.Write (gallery_name + titleExtension);
-			writer.RenderEndTag (); //title div
-
-			writer.AddAttribute ("class", "navi");
-			writer.RenderBeginTag ("div");
-
-			// link to all photos
-			writer.AddAttribute ("class", "navipage");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("href", IndexPath (0));
-			writer.RenderBeginTag ("a");
-			writer.Write ("Index");
-			writer.RenderEndTag (); //a
-
-			writer.RenderEndTag (); //navipage
-			// end link to all photos
-
-			// link to all tags
-			writer.AddAttribute ("class", "navipage");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("href", TagsIndexPath ());
-			writer.RenderBeginTag ("a");
-			writer.Write ("Tags");
-			writer.RenderEndTag (); //a
-
-			writer.RenderEndTag (); //navipage
-			// end link to all tags
-
-			writer.AddAttribute ("class", "navilabel");
-			writer.RenderBeginTag ("div");
-			writer.Write (Catalog.GetString ("Page:"));
-			writer.RenderEndTag (); //pages div
-
-			int i;
-			for (i = 0; i < TagPageCount (tag); i++) {
-				writer.AddAttribute ("class", i == page_num ? "navipage-current" : "navipage");
-				writer.RenderBeginTag ("div");
-
-				writer.AddAttribute ("href", TagIndexPath (tag, i));
-				writer.RenderBeginTag ("a");
-				writer.Write (IndexTitle (i));
-				writer.RenderEndTag (); //a
-
-				writer.RenderEndTag (); //navipage
-			}
-			writer.RenderEndTag (); //navi
-			writer.RenderEndTag (); //header
-
-			writer.AddAttribute ("class", "thumbs");
-			writer.RenderBeginTag ("div");
-
-			int start = page_num * perpage;
-			List<int> tagSet = tagSets [tag];
-			int end = Math.Min (start + perpage, tagSet.Count);
-			for (i = start; i < end; i++) {
-				writer.AddAttribute ("href", PhotoIndexPath ((int) tagSet [i]));
-				writer.RenderBeginTag ("a");
-
-				writer.AddAttribute  ("src", PhotoThumbPath ((int) tagSet [i]));
-				writer.AddAttribute  ("alt", "#");
-				writer.RenderBeginTag ("img");
-				writer.RenderEndTag ();
-
-				writer.RenderEndTag (); //a
-			}
-
-			writer.RenderEndTag (); //thumbs
-
-			writer.AddAttribute ("id", "gallery_description");
-			writer.RenderBeginTag ("div");
-			writer.Write (description);
-			writer.RenderEndTag (); //description
-
-			WriteStyleSelectionBox (writer);
-
-			writer.RenderEndTag (); //container1
-
-			WriteFooter (writer);
-
-			writer.RenderEndTag (); //body
-			writer.RenderEndTag (); //html
-
-			writer.Close ();
-			stream.Close ();
-		}
-
-		public void SaveTagIcons ()
-		{
-			MakeDir (SubdirPath ("tags"));
-			foreach (Tag tag in allTags.Values)
-				SaveTagIcon (tag);
-		}
-
-		public void SaveTagIcon (Tag tag) {
-			Gdk.Pixbuf icon = tag.Icon;
-			Gdk.Pixbuf scaled = null;
-			if (icon.Height != 52 || icon.Width != 52) {
-				scaled=icon.ScaleSimple(52,52,Gdk.InterpType.Bilinear);
-			} else
-				scaled=icon.Copy ();
-			scaled.Save (SubdirPath("tags",TagName(tag)), "png");
-			scaled.Dispose ();
-		}
-
-		public string TagPath (Tag tag)
-		{
-			return System.IO.Path.Combine("tags",TagName(tag));
-		}
-
-		public string TagName (Tag tag)
-		{
-			return "tag_"+ ((DbItem)tag).Id+".png";
-		}
-
-		public void SaveHtmlIndex (int page_num)
-		{
-			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (IndexPath (page_num)));
-			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
-
-			//writer.Indent = 4;
-
-			//writer.Write ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
-			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
-			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
-			writer.AddAttribute ("xml:lang", this.Language);
-			writer.RenderBeginTag ("html");
-			WriteHeader (writer);
-
-			writer.AddAttribute ("onload", "checkForTheme()");
-			writer.RenderBeginTag ("body");
-
-
-
-			writer.AddAttribute ("class", "container1");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("class", "header");
-			writer.RenderBeginTag ("div");
-
-			writer.AddAttribute ("id", "title");
-			writer.RenderBeginTag ("div");
-			writer.Write (gallery_name);
-			writer.RenderEndTag (); //title div
-
-			writer.AddAttribute ("class", "navi");
-			writer.RenderBeginTag ("div");
-
-			if (exportTags) {
-				// link to all tags
-				writer.AddAttribute ("class", "navipage");
-				writer.RenderBeginTag ("div");
-
-				writer.AddAttribute ("href", TagsIndexPath ());
-				writer.RenderBeginTag ("a");
-				writer.Write ("Tags");
-				writer.RenderEndTag (); //a
-
-				writer.RenderEndTag (); //navipage
-				// end link to all tags
-			}
-
-			writer.AddAttribute ("class", "navilabel");
-			writer.RenderBeginTag ("div");
-			writer.Write (Catalog.GetString ("Page:"));
-			writer.RenderEndTag (); //pages div
-
-			int i;
-			for (i = 0; i < PageCount; i++) {
-				writer.AddAttribute ("class", i == page_num ? "navipage-current" : "navipage");
-				writer.RenderBeginTag ("div");
-
-				writer.AddAttribute ("href", IndexPath (i));
-				writer.RenderBeginTag ("a");
-				writer.Write (IndexTitle (i));
-				writer.RenderEndTag (); //a
-
-				writer.RenderEndTag (); //navipage
-			}
-			writer.RenderEndTag (); //navi
-			writer.RenderEndTag (); //header
-
-			writer.AddAttribute ("class", "thumbs");
-			writer.RenderBeginTag ("div");
-
-			int start = page_num * perpage;
-			int end = Math.Min (start + perpage, collection.Count);
-			for (i = start; i < end; i++) {
-				writer.AddAttribute ("href", PhotoIndexPath (i));
-				writer.RenderBeginTag ("a");
-
-				writer.AddAttribute  ("src", PhotoThumbPath (i));
-				writer.AddAttribute  ("alt", "#");
-				writer.RenderBeginTag ("img");
-				writer.RenderEndTag ();
-
-				writer.RenderEndTag (); //a
-			}
-
-			writer.RenderEndTag (); //thumbs
-
-			writer.AddAttribute ("id", "gallery_description");
-			writer.RenderBeginTag ("div");
-			writer.Write (description);
-			writer.RenderEndTag (); //description
-
-			WriteStyleSelectionBox (writer);
-
-			writer.RenderEndTag (); //container1
-
-			WriteFooter (writer);
-
-			writer.RenderEndTag (); //body
-			writer.RenderEndTag (); //html
-
-			writer.Close ();
-			stream.Close ();
-		}
-
-	}
 }
diff --git a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderGallery.cs b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderGallery.cs
new file mode 100644
index 0000000..6774650
--- /dev/null
+++ b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/FolderGallery.cs
@@ -0,0 +1,262 @@
+//
+// FolderGallery.cs
+//
+// Author:
+//   Lorenzo Milesi <maxxer yetopen it>
+//   Stephane Delcroix <stephane delcroix org>
+//   Stephen Shaw <sshaw decriptor com>
+//
+// Copyright (C) 2008-2009 Novell, Inc.
+// Copyright (C) 2008 Lorenzo Milesi
+// Copyright (C) 2008-2009 Stephane Delcroix
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+/*
+ * Copyright (C) 2005 Alessandro Gervaso <gervystar gervystar net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+//This should be used to export the selected pics to an original gallery
+//located on a GIO location.
+
+using System;
+using System.IO;
+
+using Hyena;
+
+using FSpot;
+using FSpot.Core;
+using FSpot.Filters;
+
+namespace FSpot.Exporters.Folder
+{
+	internal class FolderGallery
+	{
+		protected struct ScaleRequest
+		{
+			public string Name;
+			public int Width;
+			public int Height;
+			public bool Skip;
+			public bool CopyExif;
+			public static ScaleRequest Default = new ScaleRequest (String.Empty, 0, 0, false);
+
+			public ScaleRequest (string name, int width, int height, bool skip, bool exif = false)
+			{
+				this.Name = name != null ? name : String.Empty;
+				this.Width = width;
+				this.Height = height;
+				this.Skip = skip;
+				this.CopyExif = exif;
+			}
+
+			public bool AvoidScale (int size)
+			{
+				return (size < this.Width && size < this.Height && this.Skip);
+			}
+		}
+
+		#region Variables
+		protected bool scale;
+		protected ScaleRequest[] requests;
+		#endregion
+
+		#region Constructor
+		internal FolderGallery (IBrowsableCollection selection, string path, string gallery_name)
+		{
+			if (null == selection)
+				throw new ArgumentNullException ("selection");
+
+			if (0 == selection.Count)
+				throw new ArgumentException ("selection can't be empty");
+
+			if (null == path)
+				throw new ArgumentNullException ("path");
+
+			if (null == gallery_name)
+				throw new ArgumentNullException ("gallery_name");
+
+			Collection = selection;
+			GalleryName = gallery_name;
+			GalleryPath = Path.Combine (path, GalleryName);
+			this.requests = new ScaleRequest [] { ScaleRequest.Default };
+		}
+		#endregion
+
+		#region Properties
+		public string GalleryName { get; protected set; }
+		public string GalleryPath { get; protected set; }
+		protected IBrowsableCollection Collection { get; set; }
+		public string Description { get; set; }
+		public Uri Destination { get; set; }
+		protected int Size { get; set; }
+		public bool ExportTags { get; set; }
+		public bool ExportTagIcons { get; set; }
+
+		string language = string.Empty;
+		public string Language {
+			get {
+				if (language == null) {
+					if ((language = Environment.GetEnvironmentVariable ("LC_ALL")) == null)
+						if ((language = Environment.GetEnvironmentVariable ("LC_MESSAGES")) == null)
+							if ((language = Environment.GetEnvironmentVariable ("LANG")) == null)
+								language = "en";
+
+					if (language.IndexOf ('.') >= 0)
+						language = language.Substring (0, language.IndexOf ('.'));
+					if (language.IndexOf ('@') >= 0)
+						language = language.Substring (0, language.IndexOf ('@'));
+					language = language.Replace ('_', '-');
+
+				}
+				return language;
+			}
+		}
+		#endregion
+
+		#region method
+		public virtual void GenerateLayout ()
+		{
+			MakeDir (GalleryPath);
+
+		}
+
+		protected virtual string ImageName (int image_num)
+		{
+			var uri = Collection [image_num].DefaultVersion.Uri;
+			var dest_uri = new SafeUri (GalleryPath);
+	
+			// Find an unused name
+			int i = 1;
+			var dest = dest_uri.Append (uri.GetFilename ());
+			var file = GLib.FileFactory.NewForUri (dest);
+			while (file.Exists) {
+				var filename = uri.GetFilenameWithoutExtension ();
+				var extension = uri.GetExtension ();
+				dest = dest_uri.Append (String.Format ("{0}-{1}{2}", filename, i++, extension));
+				file = GLib.FileFactory.NewForUri (dest);
+			}
+	
+			return dest.GetFilename ();
+		}
+
+		public void ProcessImage (int image_num, FilterSet filter_set)
+		{
+			IPhoto photo = Collection [image_num];
+			string path;
+			ScaleRequest req;
+
+			req = requests [0];
+
+			MakeDir (SubdirPath (req.Name));
+			path = SubdirPath (req.Name, ImageName (image_num));
+
+			using (FilterRequest request = new FilterRequest (photo.DefaultVersion.Uri)) {
+				filter_set.Convert (request);
+				if (request.Current.LocalPath == path)
+					request.Preserve (request.Current);
+				else
+					System.IO.File.Copy (request.Current.LocalPath, path, true);
+
+				if (photo != null && photo is Photo && App.Instance.Database != null)
+					App.Instance.Database.Exports.Create ((photo as Photo).Id, (photo as Photo).DefaultVersionId,
+								      ExportStore.FolderExportType,
+								      // FIXME this is wrong, the final path is the one
+								      // after the Xfer.
+								      new SafeUri (path).ToString ());
+
+				for (int i = 1; i < requests.Length; i++) {
+
+					req = requests [i];
+					if (scale && req.AvoidScale (Size))
+						continue;
+
+					FilterSet req_set = new FilterSet ();
+					req_set.Add (new ResizeFilter ((uint)Math.Max (req.Width, req.Height)));
+
+					bool sharpen;
+					try {
+						sharpen = Preferences.Get<bool> (FolderExport.SHARPEN_KEY);
+					} catch (NullReferenceException) {
+						sharpen = true;
+						Preferences.Set (FolderExport.SHARPEN_KEY, true);
+					}
+
+					if (sharpen) {
+						if (req.Name == "lq")
+							req_set.Add (new SharpFilter (0.1, 2, 4));
+						if (req.Name == "thumbs")
+							req_set.Add (new SharpFilter (0.1, 2, 5));
+					}
+					using (FilterRequest tmp_req = new FilterRequest (photo.DefaultVersion.Uri)) {
+						req_set.Convert (tmp_req);
+						MakeDir (SubdirPath (req.Name));
+						path = SubdirPath (req.Name, ImageName (image_num));
+						System.IO.File.Copy (tmp_req.Current.LocalPath, path, true);
+					}
+				}
+			}
+		}
+
+		protected string MakeDir (string path)
+		{
+			try {
+				Directory.CreateDirectory (path);
+			} catch {
+				Log.ErrorFormat ("Error in creating directory \"{0}\"", path);
+			}
+			return path;
+		}
+
+		protected string SubdirPath (string subdir, string file = null)
+		{
+			string path = Path.Combine (GalleryPath, subdir);
+			if (file != null)
+				path = Path.Combine (path, file);
+
+			return path;
+		}
+
+		public void SetScale (int size)
+		{
+			this.scale = true;
+			Size = size;
+			requests [0].Width = size;
+			requests [0].Height = size;
+		}
+		#endregion
+	}
+}
diff --git a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/HtmlGallery.cs b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/HtmlGallery.cs
new file mode 100644
index 0000000..b877ebe
--- /dev/null
+++ b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/HtmlGallery.cs
@@ -0,0 +1,764 @@
+//
+// HtmlGallery.cs
+//
+// Author:
+//   Lorenzo Milesi <maxxer yetopen it>
+//   Stephane Delcroix <stephane delcroix org>
+//   Stephen Shaw <sshaw decriptor com>
+//
+// Copyright (C) 2008-2009 Novell, Inc.
+// Copyright (C) 2008 Lorenzo Milesi
+// Copyright (C) 2008-2009 Stephane Delcroix
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+/*
+ * Copyright (C) 2005 Alessandro Gervaso <gervystar gervystar net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+//This should be used to export the selected pics to an original gallery
+//located on a GIO location.
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Generic;
+
+using Mono.Unix;
+
+using FSpot.Core;
+
+namespace FSpot.Exporters.Folder
+{
+	class HtmlGallery : FolderGallery
+	{
+		int perpage = 16;
+		string stylesheet = "f-spot-simple.css";
+		string altstylesheet = "f-spot-simple-white.css";
+		string javascript = "f-spot.js";
+
+		//Note for translators: light as clear, opposite as dark
+		static string light = Catalog.GetString("Light");
+		static string dark = Catalog.GetString("Dark");
+
+		List<string> allTagNames = new List<string> ();
+		Dictionary<string,Tag> allTags = new Dictionary<string, Tag> ();
+		Dictionary<string, List<int>> tagSets = new Dictionary<string, List<int>> ();
+
+		public HtmlGallery (IBrowsableCollection selection, string path, string name) : base (selection, path, name)
+		{
+			requests = new ScaleRequest [] { new ScaleRequest ("hq", 0, 0, false),
+							 new ScaleRequest ("mq", 480, 320, false),
+							 new ScaleRequest ("thumbs", 120, 90, false) };
+		}
+
+		protected override string ImageName (int photo_index)
+		{
+			return String.Format ("img-{0}.jpg", photo_index + 1);
+		}
+
+		public override void GenerateLayout ()
+		{
+			if (Collection.Count == 0)
+				return;
+
+			base.GenerateLayout ();
+
+			IPhoto [] photos = Collection.Items;
+
+			int i;
+			for (i = 0; i < photos.Length; i++)
+				SavePhotoHtmlIndex (i);
+
+			for (i = 0; i < PageCount; i++)
+				SaveHtmlIndex (i);
+
+			if (ExportTags) {
+				// identify tags present in these photos
+				i = 0;
+				foreach (IPhoto photo in photos) {
+					foreach (var tag in photo.Tags) {
+						if (!tagSets.ContainsKey (tag.Name)) {
+							tagSets.Add (tag.Name, new List<int> ());
+							allTags.Add (tag.Name, tag);
+						}
+						tagSets [tag.Name].Add (i);
+					}
+					i++;
+				}
+				allTagNames = new List<string> (tagSets.Keys);
+				allTagNames.Sort ();
+
+				// create tag pages
+				SaveTagsPage ();
+				foreach (string tag in allTagNames) {
+					for (i = 0; i < TagPageCount (tag); i++)
+						SaveTagIndex (tag, i);
+				}
+			}
+
+			if (ExportTags && ExportTagIcons) {
+				SaveTagIcons ();
+			}
+
+			MakeDir (SubdirPath ("style"));
+			System.Reflection.Assembly assembly = System.Reflection.Assembly.GetCallingAssembly ();
+			using (Stream s = assembly.GetManifestResourceStream (stylesheet)) {
+				using (Stream fs = System.IO.File.Open (SubdirPath ("style", stylesheet), System.IO.FileMode.Create)) {
+
+					byte [] buffer = new byte [8192];
+					int n;
+					while ((n = s.Read (buffer, 0, buffer.Length)) != 0)
+						fs.Write (buffer, 0,  n);
+
+				}
+			}
+			/* quick and stupid solution
+			   this should have been iterated over an array of stylesheets, really
+			*/
+			using (Stream s = assembly.GetManifestResourceStream (altstylesheet)) {
+				using (Stream fs = System.IO.File.Open (SubdirPath ("style", altstylesheet), System.IO.FileMode.Create)) {
+
+					byte [] buffer = new byte [8192];
+					int n = 0;
+					while ((n = s.Read (buffer, 0, buffer.Length)) != 0)
+						fs.Write (buffer, 0,  n);
+
+				}
+			}
+
+			/* Javascript for persistant style change */
+			MakeDir (SubdirPath ("script"));
+			using (Stream s = assembly.GetManifestResourceStream (javascript)) {
+				using (Stream fs = System.IO.File.Open (SubdirPath ("script", javascript), System.IO.FileMode.Create)) {
+
+					byte [] buffer = new byte [8192];
+					int n = 0;
+					while ((n = s.Read (buffer, 0, buffer.Length)) != 0)
+						fs.Write (buffer, 0,  n);
+
+				}
+			}
+		}
+
+		public int PageCount {
+			get {
+				return 	(int) System.Math.Ceiling (Collection.Items.Length / (double)perpage);
+			}
+		}
+
+		public int TagPageCount (string tag)
+		{
+			return (int) System.Math.Ceiling (tagSets [tag].Count / (double)perpage);
+		}
+
+		public string PhotoThumbPath (int item)
+		{
+			return System.IO.Path.Combine (requests [2].Name, ImageName (item));
+		}
+
+		public string PhotoWebPath (int item)
+		{
+			return System.IO.Path.Combine (requests [1].Name, ImageName (item));
+		}
+
+		public string PhotoOriginalPath (int item)
+		{
+			return System.IO.Path.Combine (requests [0].Name, ImageName (item));
+		}
+
+		public string PhotoIndexPath (int item)
+		{
+			return (System.IO.Path.GetFileNameWithoutExtension (ImageName (item)) + ".html");
+		}
+
+		public static void WritePageNav (System.Web.UI.HtmlTextWriter writer, string id, string url, string name)
+		{
+			writer.AddAttribute ("id", id);
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("href", url);
+			writer.RenderBeginTag ("a");
+			writer.Write (name);
+			writer.RenderEndTag ();
+
+			writer.RenderEndTag ();
+		}
+
+		public void SavePhotoHtmlIndex (int i)
+		{
+			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (PhotoIndexPath (i)));
+			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
+
+			//writer.Indent = 4;
+
+			//writer.Write ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
+			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
+			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
+			writer.AddAttribute ("xml:lang", this.Language);
+			writer.RenderBeginTag ("html");
+
+			WriteHeader (writer);
+
+			writer.AddAttribute ("onload", "checkForTheme()");
+			writer.RenderBeginTag ("body");
+
+			writer.AddAttribute ("class", "container1");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("class", "header");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("id", "title");
+			writer.RenderBeginTag ("div");
+			writer.Write (GalleryName);
+			writer.RenderEndTag ();
+
+			writer.AddAttribute ("class", "navi");
+			writer.RenderBeginTag ("div");
+
+			if (i > 0)
+				// Abbreviation of previous
+				WritePageNav (writer, "prev", PhotoIndexPath (i - 1), Catalog.GetString("Prev"));
+
+			WritePageNav (writer, "index", IndexPath (i / perpage), Catalog.GetString("Index"));
+
+			if (ExportTags)
+				WritePageNav (writer, "tagpage", TagsIndexPath (), Catalog.GetString ("Tags"));
+
+			if (i < Collection.Count -1)
+				WritePageNav (writer, "next", PhotoIndexPath (i + 1), Catalog.GetString("Next"));
+
+			writer.RenderEndTag (); //navi
+
+			writer.RenderEndTag (); //header
+
+			writer.AddAttribute ("class", "photo");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("href", PhotoOriginalPath (i));
+			writer.RenderBeginTag ("a");
+
+			writer.AddAttribute ("src", PhotoWebPath (i));
+			writer.AddAttribute ("alt", "#");
+			writer.AddAttribute ("class", "picture");
+			writer.RenderBeginTag ("img");
+			writer.RenderEndTag (); //img
+			writer.RenderEndTag (); //a
+
+			writer.AddAttribute ("id", "description");
+			writer.RenderBeginTag ("div");
+			writer.Write (Collection [i].Description);
+			writer.RenderEndTag (); //div#description
+
+			writer.RenderEndTag (); //div.photo
+
+			WriteTagsLinks (writer, Collection [i].Tags);
+
+			WriteStyleSelectionBox (writer);
+
+			writer.RenderEndTag (); //container1
+
+			WriteFooter (writer);
+
+			writer.RenderEndTag (); //body
+			writer.RenderEndTag (); // html
+
+			writer.Close ();
+			stream.Close ();
+		}
+
+		public static string IndexPath (int page_num)
+		{
+			if (page_num == 0)
+				return "index.html";
+			else
+				return String.Format ("index{0}.html", page_num);
+		}
+
+		public static string TagsIndexPath ()
+		{
+			return "tags.html";
+		}
+
+		public static string TagIndexPath (string tag, int page_num)
+		{
+			string name = "tag_"+tag;
+			name = name.Replace ("/", "_").Replace (" ","_");
+			if (page_num == 0)
+				return name + ".html";
+			else
+				return name + String.Format ("_{0}.html", page_num);
+		}
+
+		static string IndexTitle (int page)
+		{
+			return String.Format ("{0}", page + 1);
+		}
+
+		public void WriteHeader (System.Web.UI.HtmlTextWriter writer)
+		{
+			WriteHeader (writer, "");
+		}
+
+		public void WriteHeader (System.Web.UI.HtmlTextWriter writer, string titleExtension)
+		{
+			writer.RenderBeginTag ("head");
+			/* It seems HtmlTextWriter always uses UTF-8, unless told otherwise */
+			writer.Write ("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />");
+			writer.WriteLine ();
+			writer.RenderBeginTag ("title");
+			writer.Write (GalleryName + titleExtension);
+			writer.RenderEndTag ();
+
+			writer.Write ("<link type=\"text/css\" rel=\"stylesheet\" href=\"");
+			writer.Write (String.Format ("{0}", "style/" + stylesheet));
+			writer.Write ("\" title=\"" + dark + "\" media=\"screen\" />" + Environment.NewLine);
+
+			writer.Write ("<link type=\"text/css\" rel=\"prefetch ") ;
+			writer.Write ("alternate stylesheet\" href=\"");
+			writer.Write (String.Format ("{0}", "style/" + altstylesheet));
+			writer.Write ("\" title=\"" + light + "\" media=\"screen\" />" + Environment.NewLine);
+
+			writer.Write ("<script src=\"script/" + javascript + "\"");
+			writer.Write (" type=\"text/javascript\"></script>" + Environment.NewLine);
+
+			writer.RenderEndTag ();
+		}
+
+		public static void WriteFooter (System.Web.UI.HtmlTextWriter writer)
+		{
+			writer.AddAttribute ("class", "footer");
+			writer.RenderBeginTag ("div");
+
+			writer.Write (Catalog.GetString ("Gallery generated by") + " ");
+
+			writer.AddAttribute ("href", "http://f-spot.org";);
+			writer.RenderBeginTag ("a");
+			writer.Write (String.Format ("{0} {1}", FSpot.Core.Defines.PACKAGE, FSpot.Core.Defines.VERSION));
+			writer.RenderEndTag ();
+
+			writer.RenderEndTag ();
+		}
+
+		public static void WriteStyleSelectionBox (System.Web.UI.HtmlTextWriter writer)
+		{
+			//Style Selection Box
+			writer.AddAttribute ("id", "styleboxcontainer");
+			writer.RenderBeginTag ("div");
+			writer.AddAttribute ("id", "stylebox");
+			writer.AddAttribute ("style", "display: none;");
+			writer.RenderBeginTag ("div");
+			writer.RenderBeginTag ("ul");
+			writer.RenderBeginTag ("li");
+			writer.AddAttribute ("href", "#");
+			writer.AddAttribute ("title", dark);
+			writer.AddAttribute ("onclick", "setActiveStyleSheet('" + dark + "')");
+			writer.RenderBeginTag ("a");
+			writer.Write (dark);
+			writer.RenderEndTag (); //a
+			writer.RenderEndTag (); //li
+			writer.RenderBeginTag ("li");
+			writer.AddAttribute ("href", "#");
+			writer.AddAttribute ("title", light);
+			writer.AddAttribute ("onclick", "setActiveStyleSheet('" + light + "')");
+			writer.RenderBeginTag ("a");
+			writer.Write (light);
+			writer.RenderEndTag (); //a
+			writer.RenderEndTag (); //li
+			writer.RenderEndTag (); //ul
+			writer.RenderEndTag (); //div stylebox
+			writer.RenderBeginTag ("div");
+			writer.Write ("<span class=\"style_toggle\">");
+			writer.Write ("<a href=\"javascript:toggle_stylebox()\">");
+			writer.Write ("<span id=\"showlink\">" + Catalog.GetString("Show Styles") + "</span><span id=\"hidelink\" ");
+			writer.Write ("style=\"display:none;\">" + Catalog.GetString("Hide Styles") + "</span></a></span>" + Environment.NewLine);
+			writer.RenderEndTag (); //div toggle
+			writer.RenderEndTag (); //div styleboxcontainer
+		}
+
+		public void WriteTagsLinks (System.Web.UI.HtmlTextWriter writer, Tag[] tags)
+		{
+			List<Tag> tagsList = new List<Tag> (tags.Length);
+			foreach (var tag in tags) {
+				tagsList.Add (tag);
+			}
+			WriteTagsLinks (writer, tagsList);
+		}
+
+		public void WriteTagsLinks (System.Web.UI.HtmlTextWriter writer, System.Collections.ICollection tags)
+		{
+
+			// check if we should write tags
+			if (!ExportTags && tags.Count>0)
+				return;
+
+			writer.AddAttribute ("id", "tagbox");
+			writer.RenderBeginTag ("div");
+			writer.RenderBeginTag ("h1");
+			writer.Write (Catalog.GetString ("Tags"));
+			writer.RenderEndTag (); //h1
+			writer.AddAttribute ("id", "innertagbox");
+			writer.RenderBeginTag ("ul");
+			foreach (Tag tag in tags) {
+				writer.AddAttribute ("class", "tag");
+				writer.RenderBeginTag ("li");
+				writer.AddAttribute ("href", TagIndexPath (tag.Name, 0));
+				writer.RenderBeginTag ("a");
+				if (ExportTagIcons) {
+					writer.AddAttribute ("alt", tag.Name);
+					writer.AddAttribute ("longdesc", Catalog.GetString ("Tags: ")+tag.Name);
+					writer.AddAttribute ("title", Catalog.GetString ("Tags: ")+tag.Name);
+					writer.AddAttribute ("src", TagPath (tag));
+					writer.RenderBeginTag ("img");
+					writer.RenderEndTag ();
+				}
+				writer.Write(" ");
+				if (ExportTagIcons)
+					writer.AddAttribute ("class", "tagtext-icon");
+				else
+					writer.AddAttribute ("class", "tagtext-noicon");
+				writer.RenderBeginTag ("span");
+				writer.Write (tag.Name);
+				writer.RenderEndTag (); //span.tagtext
+				writer.RenderEndTag (); //a href
+				writer.RenderEndTag (); //div.tag
+			}
+			writer.RenderEndTag (); //div#tagbox
+		}
+
+		public void SaveTagsPage ()
+		{
+			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (TagsIndexPath ()));
+			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
+
+			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
+			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
+			writer.AddAttribute ("xml:lang", this.Language);
+			writer.RenderBeginTag ("html");
+			string titleExtension = " " + Catalog.GetString ("Tags");
+			WriteHeader (writer, titleExtension);
+
+			writer.AddAttribute ("onload", "checkForTheme()");
+			writer.AddAttribute ("id", "tagpage");
+			writer.RenderBeginTag ("body");
+
+			writer.AddAttribute ("class", "container1");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("class", "header");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("id", "title");
+			writer.RenderBeginTag ("div");
+			writer.Write (GalleryName + titleExtension);
+			writer.RenderEndTag (); //title div
+
+			writer.AddAttribute ("class", "navi");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("class", "navipage");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("href", IndexPath (0));
+			writer.RenderBeginTag ("a");
+			writer.Write (Catalog.GetString ("Index"));
+			writer.RenderEndTag (); //a
+
+			writer.RenderEndTag (); //navipage
+			writer.RenderEndTag (); //navi
+			writer.RenderEndTag (); //header
+
+			WriteTagsLinks (writer, allTags.Values);
+
+			WriteStyleSelectionBox (writer);
+
+			writer.RenderEndTag (); //container1
+
+			WriteFooter (writer);
+
+			writer.RenderEndTag (); //body
+			writer.RenderEndTag (); //html
+
+			writer.Close ();
+			stream.Close ();
+		}
+
+		public void SaveTagIndex (string tag, int page_num)
+		{
+			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (TagIndexPath (tag, page_num)));
+			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
+
+			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
+			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
+			writer.AddAttribute ("xml:lang", this.Language);
+			writer.RenderBeginTag ("html");
+			string titleExtension = ": " + tag;
+			WriteHeader (writer, titleExtension);
+
+			writer.AddAttribute ("onload", "checkForTheme()");
+			writer.RenderBeginTag ("body");
+
+			writer.AddAttribute ("class", "container1");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("class", "header");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("id", "title");
+			writer.RenderBeginTag ("div");
+			writer.Write (GalleryName + titleExtension);
+			writer.RenderEndTag (); //title div
+
+			writer.AddAttribute ("class", "navi");
+			writer.RenderBeginTag ("div");
+
+			// link to all photos
+			writer.AddAttribute ("class", "navipage");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("href", IndexPath (0));
+			writer.RenderBeginTag ("a");
+			writer.Write ("Index");
+			writer.RenderEndTag (); //a
+
+			writer.RenderEndTag (); //navipage
+			// end link to all photos
+
+			// link to all tags
+			writer.AddAttribute ("class", "navipage");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("href", TagsIndexPath ());
+			writer.RenderBeginTag ("a");
+			writer.Write ("Tags");
+			writer.RenderEndTag (); //a
+
+			writer.RenderEndTag (); //navipage
+			// end link to all tags
+
+			writer.AddAttribute ("class", "navilabel");
+			writer.RenderBeginTag ("div");
+			writer.Write (Catalog.GetString ("Page:"));
+			writer.RenderEndTag (); //pages div
+
+			int i;
+			for (i = 0; i < TagPageCount (tag); i++) {
+				writer.AddAttribute ("class", i == page_num ? "navipage-current" : "navipage");
+				writer.RenderBeginTag ("div");
+
+				writer.AddAttribute ("href", TagIndexPath (tag, i));
+				writer.RenderBeginTag ("a");
+				writer.Write (IndexTitle (i));
+				writer.RenderEndTag (); //a
+
+				writer.RenderEndTag (); //navipage
+			}
+			writer.RenderEndTag (); //navi
+			writer.RenderEndTag (); //header
+
+			writer.AddAttribute ("class", "thumbs");
+			writer.RenderBeginTag ("div");
+
+			int start = page_num * perpage;
+			List<int> tagSet = tagSets [tag];
+			int end = Math.Min (start + perpage, tagSet.Count);
+			for (i = start; i < end; i++) {
+				writer.AddAttribute ("href", PhotoIndexPath ((int) tagSet [i]));
+				writer.RenderBeginTag ("a");
+
+				writer.AddAttribute  ("src", PhotoThumbPath ((int) tagSet [i]));
+				writer.AddAttribute  ("alt", "#");
+				writer.RenderBeginTag ("img");
+				writer.RenderEndTag ();
+
+				writer.RenderEndTag (); //a
+			}
+
+			writer.RenderEndTag (); //thumbs
+
+			writer.AddAttribute ("id", "gallery_description");
+			writer.RenderBeginTag ("div");
+			writer.Write (Description);
+			writer.RenderEndTag (); //description
+
+			WriteStyleSelectionBox (writer);
+
+			writer.RenderEndTag (); //container1
+
+			WriteFooter (writer);
+
+			writer.RenderEndTag (); //body
+			writer.RenderEndTag (); //html
+
+			writer.Close ();
+			stream.Close ();
+		}
+
+		public void SaveTagIcons ()
+		{
+			MakeDir (SubdirPath ("tags"));
+			foreach (Tag tag in allTags.Values)
+				SaveTagIcon (tag);
+		}
+
+		public void SaveTagIcon (Tag tag) {
+			Gdk.Pixbuf icon = tag.Icon;
+			Gdk.Pixbuf scaled = null;
+			if (icon.Height != 52 || icon.Width != 52) {
+				scaled=icon.ScaleSimple(52,52,Gdk.InterpType.Bilinear);
+			} else
+				scaled=icon.Copy ();
+			scaled.Save (SubdirPath("tags",TagName(tag)), "png");
+			scaled.Dispose ();
+		}
+
+		public string TagPath (Tag tag)
+		{
+			return System.IO.Path.Combine("tags",TagName(tag));
+		}
+
+		public string TagName (Tag tag)
+		{
+			return "tag_"+ ((DbItem)tag).Id+".png";
+		}
+
+		public void SaveHtmlIndex (int page_num)
+		{
+			System.IO.StreamWriter stream = System.IO.File.CreateText (SubdirPath (IndexPath (page_num)));
+			System.Web.UI.HtmlTextWriter writer = new System.Web.UI.HtmlTextWriter (stream);
+
+			//writer.Indent = 4;
+
+			//writer.Write ("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
+			writer.WriteLine ("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
+			writer.AddAttribute ("xmlns", "http://www.w3.org/1999/xhtml";);
+			writer.AddAttribute ("xml:lang", this.Language);
+			writer.RenderBeginTag ("html");
+			WriteHeader (writer);
+
+			writer.AddAttribute ("onload", "checkForTheme()");
+			writer.RenderBeginTag ("body");
+
+
+
+			writer.AddAttribute ("class", "container1");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("class", "header");
+			writer.RenderBeginTag ("div");
+
+			writer.AddAttribute ("id", "title");
+			writer.RenderBeginTag ("div");
+			writer.Write (GalleryName);
+			writer.RenderEndTag (); //title div
+
+			writer.AddAttribute ("class", "navi");
+			writer.RenderBeginTag ("div");
+
+			if (ExportTags) {
+				// link to all tags
+				writer.AddAttribute ("class", "navipage");
+				writer.RenderBeginTag ("div");
+
+				writer.AddAttribute ("href", TagsIndexPath ());
+				writer.RenderBeginTag ("a");
+				writer.Write ("Tags");
+				writer.RenderEndTag (); //a
+
+				writer.RenderEndTag (); //navipage
+				// end link to all tags
+			}
+
+			writer.AddAttribute ("class", "navilabel");
+			writer.RenderBeginTag ("div");
+			writer.Write (Catalog.GetString ("Page:"));
+			writer.RenderEndTag (); //pages div
+
+			int i;
+			for (i = 0; i < PageCount; i++) {
+				writer.AddAttribute ("class", i == page_num ? "navipage-current" : "navipage");
+				writer.RenderBeginTag ("div");
+
+				writer.AddAttribute ("href", IndexPath (i));
+				writer.RenderBeginTag ("a");
+				writer.Write (IndexTitle (i));
+				writer.RenderEndTag (); //a
+
+				writer.RenderEndTag (); //navipage
+			}
+			writer.RenderEndTag (); //navi
+			writer.RenderEndTag (); //header
+
+			writer.AddAttribute ("class", "thumbs");
+			writer.RenderBeginTag ("div");
+
+			int start = page_num * perpage;
+			int end = Math.Min (start + perpage, Collection.Count);
+			for (i = start; i < end; i++) {
+				writer.AddAttribute ("href", PhotoIndexPath (i));
+				writer.RenderBeginTag ("a");
+
+				writer.AddAttribute  ("src", PhotoThumbPath (i));
+				writer.AddAttribute  ("alt", "#");
+				writer.RenderBeginTag ("img");
+				writer.RenderEndTag ();
+
+				writer.RenderEndTag (); //a
+			}
+
+			writer.RenderEndTag (); //thumbs
+
+			writer.AddAttribute ("id", "gallery_description");
+			writer.RenderBeginTag ("div");
+			writer.Write (Description);
+			writer.RenderEndTag (); //description
+
+			WriteStyleSelectionBox (writer);
+
+			writer.RenderEndTag (); //container1
+
+			WriteFooter (writer);
+
+			writer.RenderEndTag (); //body
+			writer.RenderEndTag (); //html
+
+			writer.Close ();
+			stream.Close ();
+		}
+
+	}
+}
diff --git a/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/OriginalGallery.cs b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/OriginalGallery.cs
new file mode 100644
index 0000000..5bf7787
--- /dev/null
+++ b/src/Extensions/Exporters/FSpot.Exporters.Folder/FSpot.Exporters.Folder/OriginalGallery.cs
@@ -0,0 +1,182 @@
+//
+// OriginalGallery.cs
+//
+// Author:
+//   Lorenzo Milesi <maxxer yetopen it>
+//   Stephane Delcroix <stephane delcroix org>
+//   Stephen Shaw <sshaw decriptor com>
+//
+// Copyright (C) 2008-2009 Novell, Inc.
+// Copyright (C) 2008 Lorenzo Milesi
+// Copyright (C) 2008-2009 Stephane Delcroix
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+/*
+ * Copyright (C) 2005 Alessandro Gervaso <gervystar gervystar net>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+//This should be used to export the selected pics to an original gallery
+//located on a GIO location.
+
+using System;
+using System.IO;
+
+using Hyena;
+
+using ICSharpCode.SharpZipLib.Checksums;
+using ICSharpCode.SharpZipLib.Zip;
+
+using FSpot.Core;
+
+namespace FSpot.Exporters.Folder
+{
+	class OriginalGallery : FolderGallery
+	{
+		public OriginalGallery (IBrowsableCollection selection, string path, string name) : base (selection, path, name)
+		{
+			requests = new ScaleRequest [] { new ScaleRequest ("hq", 0, 0, false),
+							 new ScaleRequest ("mq", 800, 600, true),
+							 new ScaleRequest ("lq", 640, 480, false, true),
+							 new ScaleRequest ("thumbs", 120, 120, false) };
+		}
+
+		public override void GenerateLayout ()
+		{
+			base.GenerateLayout ();
+			MakeDir (SubdirPath ("comments"));
+			CreateHtaccess();
+			CreateInfo();
+			SetTime ();
+		}
+
+		protected override string ImageName (int photo_index)
+		{
+			return String.Format ("img-{0}.jpg", photo_index + 1);
+		}
+
+		private void SetTime ()
+		{
+			try {
+				for (int i = 0; i < Collection.Count; i++)
+					CreateComments (Collection [i].DefaultVersion.Uri.LocalPath, i);
+
+				Directory.SetLastWriteTimeUtc(GalleryPath, Collection [0].Time);
+			} catch (System.Exception e) {
+				Log.Error (e.ToString ());
+			}
+		}
+
+		internal void CreateZip ()
+		{
+			MakeDir (SubdirPath ("zip"));
+			try {
+				if (System.IO.Directory.Exists (SubdirPath ("mq")))
+				    CreateZipFile("mq");
+
+				if (System.IO.Directory.Exists (SubdirPath ("hq")))
+				    CreateZipFile("hq");
+
+			} catch (System.Exception e) {
+				Log.Error (e.ToString ());
+			}
+		}
+
+		private void CreateComments(string photo_path, int photo_index)
+		{
+			StreamWriter comment = File.CreateText(SubdirPath  ("comments", photo_index + 1 + ".txt"));
+			comment.Write("<span>photo " + (photo_index + 1) + "</span> ");
+			comment.Write (Collection [photo_index].Description + Environment.NewLine);
+			comment.Close();
+		}
+
+		private void CreateZipFile(string img_quality)
+		{
+			string[] filenames = Directory.GetFiles(SubdirPath (img_quality));
+			Crc32 crc = new Crc32();
+			ZipOutputStream s = new ZipOutputStream(File.Create(SubdirPath ("zip", img_quality + ".zip")));
+
+			s.SetLevel(0);
+			foreach (string file in filenames) {
+				FileStream fs = File.OpenRead(file);
+
+				byte[] buffer = new byte[fs.Length];
+				fs.Read(buffer, 0, buffer.Length);
+				ZipEntry entry = new ZipEntry(Path.GetFileName(file));
+
+				entry.DateTime = DateTime.Now;
+
+				// set Size and the crc, because the information
+				// about the size and crc should be stored in the header
+				// if it is not set it is automatically written in the footer.
+				// (in this case size == crc == -1 in the header)
+				// Some ZIP programs have problems with zip files that don't store
+				// the size and crc in the header.
+				entry.Size = fs.Length;
+				fs.Close();
+
+				crc.Reset();
+				crc.Update(buffer);
+
+				entry.Crc  = crc.Value;
+
+				s.PutNextEntry(entry);
+
+				s.Write(buffer, 0, buffer.Length);
+
+			}
+
+			s.Finish();
+			s.Close();
+		}
+
+		private void CreateHtaccess()
+		{
+			StreamWriter htaccess = File.CreateText(Path.Combine (GalleryPath,".htaccess"));
+			htaccess.Write("<Files info.txt>" + Environment.NewLine + "\tdeny from all" + Environment.NewLine+ "</Files>" + Environment.NewLine);
+			htaccess.Close();
+		}
+
+		private void CreateInfo()
+		{
+			StreamWriter info = File.CreateText(Path.Combine (GalleryPath, "info.txt"));
+			info.WriteLine("name|" + GalleryName);
+			info.WriteLine("date|" + Collection [0].Time.Date.ToString ("dd.MM.yyyy"));
+			info.WriteLine("description|" + Description);
+			info.Close();
+		}
+	}
+}
diff --git a/src/Extensions/Exporters/FSpot.Exporters.Folder/Makefile.am b/src/Extensions/Exporters/FSpot.Exporters.Folder/Makefile.am
index 285637e..ffef00a 100644
--- a/src/Extensions/Exporters/FSpot.Exporters.Folder/Makefile.am
+++ b/src/Extensions/Exporters/FSpot.Exporters.Folder/Makefile.am
@@ -3,7 +3,11 @@ TARGET = library
 LINK = $(REF_FSPOT_EXTENSION_FOLDEREXPORT)
 INSTALL_DIR = $(EXTENSIONS_INSTALL_DIR)
 
-SOURCES = FSpot.Exporters.Folder/FolderExport.cs
+SOURCES =  \
+	FSpot.Exporters.Folder/FolderExport.cs \
+	FSpot.Exporters.Folder/FolderGallery.cs \
+	FSpot.Exporters.Folder/HtmlGallery.cs \
+	FSpot.Exporters.Folder/OriginalGallery.cs
 
 RESOURCES =  \
 	Resources/folder_export.ui \



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]