using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.ComponentModel; using PersistentObjects; using System.Windows.Forms; namespace FastGallery { /// /// Settings related to a web gallery. /// [Serializable] class Gallery : Persistent, ICloneable { /// /// A name for the gallery that will form part of the URL. /// public string Name { get { return name; } set { if (value == null || value.Equals(Path.GetFileName(value)))// check is nothing more than a valid filename { name = value; } else { throw new Exception("Invalid name"); } } } private string name; /// /// The full title for the gallery to appear on the page. /// /// If no title is specified the Name value will be used. public string Title { get { if (String.IsNullOrEmpty(title)) { return name; } else { return title; } } set { title = value; } } private string title; /// /// The directory on disk for the gallery working files. /// internal string Directory { get { return System.IO.Path.Combine(Program.GetTempPath(), Name); } } /// /// The URL of the index page. /// internal string IndexPage() { return System.IO.Path.Combine(Directory, "index.html"); } private string originalName; /// /// Build a gallery, using the program settings. /// public Gallery(Settings settings) { while (true) { settings.GalleryCounter++; // update counter settings.Save(Settings.Filename());// save straight away originalName = "Gallery " + settings.GalleryCounter; Name = originalName; if (!System.IO.Directory.Exists(Directory)) { System.IO.Directory.CreateDirectory(Directory); break; } } } /// /// A full list of the images included in the gallery. /// public List IncludedImages { get { return includedImages; } } List includedImages = new List(); /// /// The average dimensions of the edges of the thumbnails, in pixels. /// public int ThumbnailSize { get { return thumbnailSize; } set { thumbnailSize = value; } } private int thumbnailSize = 120; /// /// The number of thumbnails per line in the thumbnail page. /// public int ThumbnailsPerLine { get { return thumbnailsPerLine; } set { if (value < 1) { throw new Exception("Thumbnails per line must be at least one"); } thumbnailsPerLine = value; } } private int thumbnailsPerLine = 5; /// /// The maximum average dimensions of each edge of the full images. /// public int MaxImageWidth { get { return maxImageWidth; } set { maxImageWidth = value; } } private int maxImageWidth = 1024; /// /// The percentage quality to use in the saved Jpeg images /// public int JpegQuality { get { return jpegQuality; } set { if (value != jpegQuality) { if (value < 1 || value > 100) { throw new Exception("Jpeg Quality should be set between 1 and 100"); } jpegQuality = value; foreach (IncludedImage includedImage in IncludedImages) { includedImage.LastSavedAs = null; } } } } private int jpegQuality = 80; #region ICloneable Members /// /// Make a clone of the gallery /// public object Clone() { Gallery clone = (Gallery)MemberwiseClone(); clone.includedImages = new List(); foreach (IncludedImage includedImage in includedImages) { clone.IncludedImages.Add((IncludedImage)includedImage.Clone()); } return clone; } #endregion /// /// Build a gallery. /// internal void Generate(BackgroundWorker backgroundWorker) { try { StringBuilder errors = new StringBuilder(); Program.Settings.Save(Settings.Filename(), true); System.IO.Directory.CreateDirectory(Directory); System.IO.Directory.CreateDirectory(Path.Combine(Directory, @"images")); System.IO.Directory.CreateDirectory(Path.Combine(Directory, @"thumbs")); // copy text file from embedded resource to directory using (Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "Stylesheet.css")) { using (StreamReader streamReader = new StreamReader(s)) { using (TextWriter tw = new StreamWriter(System.IO.Path.Combine(Directory, "StyleSheet.css"))) { while (!streamReader.EndOfStream) { tw.WriteLine(streamReader.ReadLine()); } } } } // build gallery using (TextWriter tw = new StreamWriter(IndexPage())) { using (Stream s = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "GalleryHeader.htm")) { StreamReader streamReader = new StreamReader(s); while (!streamReader.EndOfStream) { string line = streamReader.ReadLine(); if (line.Contains("")) { tw.WriteLine(Title); } else if (line.Contains("")) { tw.WriteLine(errors); } else if (line.Contains("")) { int idx = 0; bool openRow = false; int thumbnailsSoFar = 0; tw.WriteLine(@""); foreach (IncludedImage includedImage in includedImages) { try { string useName = includedImage.Name; string extension = Path.GetExtension(useName).ToLower(); if (!extension.Equals(".jpg") && !extension.Equals(".gif") && !extension.Equals(".png")) // supported formats { useName = Path.ChangeExtension(useName, "jpg"); } string useNameThumbnail = Path.ChangeExtension(includedImage.Name, "jpg"); { backgroundWorker.ReportProgress((idx * 100) / includedImages.Count, "Building gallery (loading " + includedImage.Name + ")"); if (backgroundWorker.CancellationPending) { throw new CancelledException(); } string fullPath = Path.Combine(Directory, Path.Combine("images", useName)); Bitmap bitmap = null; // prepare main image if (!fullPath.Equals(includedImage.LastSavedAs) || !File.Exists(fullPath) || includedImage.LastSaveAsMaxWidth != MaxImageWidth || includedImage.LastSaveWithRotations != includedImage.Rotations) { backgroundWorker.ReportProgress((int)((0.2f + idx) * 100) / includedImages.Count, "Building gallery (sizing " + includedImage.Name + ")"); if (backgroundWorker.CancellationPending) { throw new CancelledException(); } Image output; Image resized = null; bitmap = includedImage.GetBitmap(); if (bitmap.Width > MaxImageWidth) { resized = ResizeBitmap(bitmap, MaxImageWidth); output = resized; } else { output = bitmap; } backgroundWorker.ReportProgress((int)((0.4f + idx) * 100) / includedImages.Count, "Building gallery (saving " + includedImage.Name + ")"); if (backgroundWorker.CancellationPending) { throw new CancelledException(); } ImageServices.SaveImage(output, fullPath, Program.Settings.Gallery.JpegQuality); if (resized != null) { resized.Dispose(); } includedImage.LastSavedAs = fullPath; includedImage.LastSaveAsMaxWidth = MaxImageWidth; includedImage.LastSaveWithRotations = includedImage.Rotations; } string fullPathThumbnail = Path.Combine(Directory, Path.Combine("thumbs", useNameThumbnail)); // prepare thumbnail image if (!fullPathThumbnail.Equals(includedImage.LastSavedAsThumbnail) || !File.Exists(fullPathThumbnail) || includedImage.LastSavedAsThumbnailSize != ThumbnailSize || includedImage.LastSaveWithRotationsThumbnail != includedImage.Rotations) { backgroundWorker.ReportProgress((int)((0.6f + idx) * 100) / includedImages.Count, "Building gallery (sizing thumbnail " + useName + ")"); if (backgroundWorker.CancellationPending) { throw new CancelledException(); } if (bitmap == null) { bitmap = includedImage.GetBitmap(); } float scale = (float)Math.Sqrt((double)(ThumbnailSize * ThumbnailSize) / (bitmap.Width * bitmap.Height)); using (Bitmap output = ScaleBitmap(bitmap, scale)) { backgroundWorker.ReportProgress((int)((0.8f + idx) * 100) / includedImages.Count, "Building gallery (saving thumbnail " + useName + ")"); if (backgroundWorker.CancellationPending) { throw new CancelledException(); } ImageServices.SaveImage(output, fullPathThumbnail, Program.Settings.Gallery.JpegQuality); } } includedImage.LastSavedAsThumbnailSize = ThumbnailSize; includedImage.LastSavedAsThumbnail = fullPathThumbnail; includedImage.LastSaveWithRotationsThumbnail = includedImage.Rotations; if (bitmap != null) { bitmap.Dispose(); } } if (!openRow) { tw.WriteLine(@""); openRow = true; } tw.WriteLine(""); thumbnailsSoFar++; if (thumbnailsSoFar == ThumbnailsPerLine) { tw.WriteLine(@""); openRow = false; thumbnailsSoFar = 0; } } catch (CancelledException exception) { throw exception; } catch (Exception e) { errors.AppendLine(@"
" + includedImage.Name + @":
"); errors.AppendLine(@"
" + e.ToString() + @":
"); } idx++; } if (openRow) { tw.WriteLine(@""); } tw.WriteLine(@"
"); } else { tw.WriteLine(line); } } } } } catch (CancelledException cancelledException) { throw cancelledException; } catch (InvalidOperationException) { // this is collection collision .. benign so just cancel throw new CancelledException(); } catch (Exception exception) { MessageBox.Show(exception.Message, "Error building gallery"); throw new CancelledException(); } //tw.Close(); } /// /// A utility function to rescale bitmaps. /// /// The source image. /// The average edge dimensions of the resized image. /// The resized image. private static Bitmap ResizeBitmap(Bitmap image, int newWidth) { float scale = (float)newWidth / image.Width; return ScaleBitmap(image, scale); } /// /// A utility function to rescale bitmaps. /// /// The source image. /// The fraction to scale the image by. /// The resized image. private static Bitmap ScaleBitmap(Bitmap image, float scale) { return (Bitmap)ImageServices.ResizeImage(image, (int)(scale * image.Width), (int)(scale * image.Height)); } /// /// Exception for cancelled builds. /// public class CancelledException : SystemException { } /// /// Current version. Alter to invalidate old saves. /// /// The current version number. public override int CurrentVersion() { return 207; } } }