diff --git a/Ficdown.Console/Program.cs b/Ficdown.Console/Program.cs index f927c1f..37158c5 100644 --- a/Ficdown.Console/Program.cs +++ b/Ficdown.Console/Program.cs @@ -15,6 +15,7 @@ string tempdir = null; string format = null; string author = null; + string images = null; var debug = false; if (args.Length == 1) @@ -45,6 +46,9 @@ case "--author": author = args[i + 1]; break; + case "--images": + images = args[i + 1]; + break; case "--debug": i--; debug = true; @@ -96,6 +100,12 @@ } } + if (!string.IsNullOrWhiteSpace(images) && !Directory.Exists(images)) + { + Console.WriteLine(@"Images directory {0} does not exist.", images); + return; + } + var parser = new FicdownParser(); var storyText = File.ReadAllText(infile); @@ -108,11 +118,7 @@ { case "html": Directory.CreateDirectory(output); - rend = (string.IsNullOrWhiteSpace(tempdir) - ? new HtmlRenderer() - : new HtmlRenderer(File.ReadAllText(Path.Combine(tempdir, "index.html")), - File.ReadAllText(Path.Combine(tempdir, "scene.html")), - File.ReadAllText(Path.Combine(tempdir, "styles.css")))); + rend = new HtmlRenderer(); break; case "epub": if (string.IsNullOrWhiteSpace(author)) @@ -120,17 +126,22 @@ Console.WriteLine(@"Epub format requires the --author argument."); return; } - rend = (string.IsNullOrWhiteSpace(tempdir) - ? new EpubRenderer(author) - : new EpubRenderer(author, File.ReadAllText(Path.Combine(tempdir, "index.html")), - File.ReadAllText(Path.Combine(tempdir, "scene.html")), - File.ReadAllText(Path.Combine(tempdir, "styles.css")))); + rend = new EpubRenderer(author); break; default: ShowHelp(); return; } + if (!string.IsNullOrWhiteSpace(tempdir)) + { + rend.IndexTemplate = File.ReadAllText(Path.Combine(tempdir, "index.html")); + rend.SceneTemplate = File.ReadAllText(Path.Combine(tempdir, "scene.html")); + rend.StylesTemplate = File.ReadAllText(Path.Combine(tempdir, "styles.css")); + }; + + if (!string.IsNullOrWhiteSpace(images)) rend.ImageDir = images; + Console.WriteLine(@"Rendering story..."); rend.Render(story, output, debug); @@ -138,6 +149,7 @@ Console.WriteLine(@"Done."); } + private static void ShowHelp() { Console.WriteLine( @@ -146,7 +158,8 @@ --in ""/path/to/source.md"" [--out ""/path/to/output""] [--template ""/path/to/template/dir""] - [--author ""Author Name"" + [--images ""/path/to/images/dir""] + [--author ""Author Name""] [--debug]"); } } diff --git a/Ficdown.Parser/Ficdown.Parser.csproj b/Ficdown.Parser/Ficdown.Parser.csproj index bc29e23..3290170 100644 --- a/Ficdown.Parser/Ficdown.Parser.csproj +++ b/Ficdown.Parser/Ficdown.Parser.csproj @@ -76,6 +76,7 @@ + True True diff --git a/Ficdown.Parser/Render/EpubRenderer.cs b/Ficdown.Parser/Render/EpubRenderer.cs index 6bcde19..458061a 100644 --- a/Ficdown.Parser/Render/EpubRenderer.cs +++ b/Ficdown.Parser/Render/EpubRenderer.cs @@ -15,11 +15,6 @@ _author = author; } - public EpubRenderer(string author, string index, string scene, string styles) : base(index, scene, styles) - { - _author = author; - } - public override void Render(Model.Parser.ResolvedStory story, string outPath, bool debug = false) { var temppath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); @@ -39,6 +34,18 @@ var epub = new Epub(Story.Name, _author, chapters); epub.AddResourceFile(new ResourceFile("styles.css", Path.Combine(temppath, "styles.css"), "text/css")); + if (!string.IsNullOrWhiteSpace(ImageDir)) + { + var dirname = ImageDir.Substring(ImageDir.LastIndexOf(Path.DirectorySeparatorChar) + 1); + var tempimgdir = Path.Combine(temppath, dirname); + foreach (var img in Directory.GetFiles(tempimgdir)) + { + var fname = Path.GetFileName(img); + epub.AddResourceFile(new ResourceFile(fname, + Path.Combine(tempimgdir, fname), MimeHelper.GetMimeType(img))); + } + } + var builder = new EPubBuilder(); var built = builder.Build(epub); diff --git a/Ficdown.Parser/Render/HtmlRenderer.cs b/Ficdown.Parser/Render/HtmlRenderer.cs index 35d2005..9fdd67d 100644 --- a/Ficdown.Parser/Render/HtmlRenderer.cs +++ b/Ficdown.Parser/Render/HtmlRenderer.cs @@ -11,25 +11,16 @@ { protected readonly Markdown Markdown; - private string _index; - private string _scene; - private string _styles; + public string IndexTemplate { get; set; } + public string SceneTemplate { get; set; } + public string StylesTemplate { get; set; } + public string ImageDir { get; set; } protected ResolvedStory Story { get; set; } public HtmlRenderer() { Markdown = new Markdown(); - _index = Template.Index; - _scene = Template.Scene; - _styles = Template.Styles; - } - - public HtmlRenderer(string index, string scene, string styles) - { - _index = index; - _scene = scene; - _styles = styles; } public virtual void Render(ResolvedStory story, string outPath, bool debug = false) @@ -46,7 +37,7 @@ protected void GenerateHtml(ResolvedStory story, string outPath, bool debug) { - var index = FillTemplate(_index, new Dictionary + var index = FillTemplate(IndexTemplate ?? Template.Index, new Dictionary { {"Title", story.Name}, {"Description", Markdown.Transform(story.Description)}, @@ -57,7 +48,7 @@ foreach (var page in story.Pages) { - File.WriteAllText(Path.Combine(outPath, "styles.css"), _styles); + File.WriteAllText(Path.Combine(outPath, "styles.css"), StylesTemplate ?? Template.Styles); var content = page.Content; foreach (var anchor in Utilities.ParseAnchors(page.Content)) @@ -71,7 +62,7 @@ string.Join("\n", page.ActiveToggles.Select(t => string.Format("- {0}", t)).ToArray())); } - var scene = FillTemplate(_scene, new Dictionary + var scene = FillTemplate(SceneTemplate ?? Template.Scene, new Dictionary { {"Title", story.Name}, {"Content", Markdown.Transform(content)} @@ -79,6 +70,22 @@ File.WriteAllText(Path.Combine(outPath, string.Format("{0}.html", page.Name)), scene); } + + if (!string.IsNullOrWhiteSpace(ImageDir)) + { + var dirname = ImageDir.Substring(ImageDir.LastIndexOf(Path.DirectorySeparatorChar) + 1); + Directory.CreateDirectory(Path.Combine(outPath, dirname)); + CopyFilesRecursively(ImageDir, Path.Combine(outPath, dirname)); + } + } + + private static void CopyFilesRecursively(string sourcePath, string destinationPath) + { + foreach (var dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories)) + Directory.CreateDirectory(dirPath.Replace(sourcePath, destinationPath)); + + foreach (var newPath in Directory.GetFiles(sourcePath, "*.*", SearchOption.AllDirectories)) + File.Copy(newPath, newPath.Replace(sourcePath, destinationPath)); } } } diff --git a/Ficdown.Parser/Render/IRenderer.cs b/Ficdown.Parser/Render/IRenderer.cs index e4c2d21..a19648e 100644 --- a/Ficdown.Parser/Render/IRenderer.cs +++ b/Ficdown.Parser/Render/IRenderer.cs @@ -1,9 +1,14 @@ namespace Ficdown.Parser.Render { + using System.Security.Cryptography.X509Certificates; using Model.Parser; public interface IRenderer { + string IndexTemplate { get; set; } + string SceneTemplate { get; set; } + string StylesTemplate { get; set; } + string ImageDir { get; set; } void Render(ResolvedStory story, string outPath, bool debug); } } diff --git a/Ficdown.Parser/Render/MimeHelper.cs b/Ficdown.Parser/Render/MimeHelper.cs new file mode 100644 index 0000000..fea84cb --- /dev/null +++ b/Ficdown.Parser/Render/MimeHelper.cs @@ -0,0 +1,25 @@ +namespace Ficdown.Parser.Render +{ + using System.Collections.Generic; + using System.IO; + + public static class MimeHelper + { + private static Dictionary _mimeTypes = new Dictionary + { + {".jpg", "image/jpeg"}, + {".jpeg", "image/jpeg"}, + {".png", "image/png"}, + {".gif", "image/gif"}, + {".bmp", "image/bmp"}, + {".tif", "image/tiff"}, + {".tiff", "image/tiff"} + }; + + public static string GetMimeType(string fileName) + { + var ext = Path.GetExtension(fileName).ToLower(); + return !_mimeTypes.ContainsKey(ext) ? "application/octet-stream" : _mimeTypes[ext]; + } + } +}