Пример #1
0
        public async Task GenerateEpubAsync(string epubDest, GenerateOptions options)
        {
            OpfFile opf = new OpfFile(new OpfMetadata
            {
                Title       = { Text = Title },
                Language    = { Text = Language },
                Description = { Text = Description },
                Creator     = { Text = Creator },
                Publisher   = { Text = Publisher }
            });

            string tmpDir  = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
            string epub    = Path.Combine(tmpDir, "EPUB");
            string metaInf = Path.Combine(tmpDir, "META-INF");

            Directory.CreateDirectory(tmpDir);
            Directory.CreateDirectory(epub);
            Directory.CreateDirectory(Path.Combine(epub, "covers"));
            Directory.CreateDirectory(Path.Combine(epub, "css"));
            Directory.CreateDirectory(Path.Combine(epub, "fonts"));
            Directory.CreateDirectory(Path.Combine(epub, "images"));

            Directory.CreateDirectory(metaInf);

            File.WriteAllText(Path.Combine(tmpDir, "mimetype"), "application/epub+zip");

            Container container = new Container();

            container.AddRootFile(new RootFile {
                FullPath = "EPUB/package.opf", MediaType = "application/oebps-package+xml"
            });
            container.Save(Path.Combine(metaInf, "container.xml"));

            if (!string.IsNullOrEmpty(CoverImage))
            {
                string    coverExt = Path.GetExtension(CoverImage);
                MediaType mType    = MediaType.FromExtension(coverExt);

                if (mType != MediaType.PngType && mType != MediaType.JpegType)
                {
                    throw new Exception("Invalid cover image extension!");
                }

                string coverImgFile = Path.GetFileName(CoverImage);
                string coverImg     = Path.Combine("covers", coverImgFile);

                Uri coverImgUri;

                if (Uri.TryCreate(CoverImage, UriKind.RelativeOrAbsolute, out coverImgUri))
                {
                    if (!coverImgUri.IsFile)
                    {
                        using (WebClient wc = new WebClient())
                            await wc.DownloadFileTaskAsync(CoverImage, Path.Combine(epub, coverImg));
                    }
                    else if (File.Exists(CoverImage))
                    {
                        File.Copy(CoverImage, Path.Combine(epub, coverImg));
                    }

                    OpfItem coverImageItem = new OpfItem(coverImg.Replace(@"\", "/"), Path.GetFileNameWithoutExtension(coverImg), mType)
                    {
                        Linear     = false,
                        Properties = "cover-image"
                    };

                    OpfItem coverItem = new OpfItem("cover.xhtml", "cover", MediaType.XHtmlType);
                    File.WriteAllText(Path.Combine(epub, "cover.xhtml"),
                                      RazorCompiler.Get(Templates[EBookTemplate.Cover], "cover", $"covers/{coverImgFile}"));

                    opf.AddItem(coverItem);
                    opf.AddItem(coverImageItem, false);
                }
            }

            TableOfContents toc = new TableOfContents {
                Title = Title
            };

            OpfItem navItem = new OpfItem("toc.xhtml", "toc", MediaType.XHtmlType)
            {
                Properties = "nav"
            };

            opf.AddItem(navItem);

            var parser = new HtmlParser();

            foreach (Chapter chapter in Chapters)
            {
                var doc = parser.Parse(chapter.Content);

                if (options.EmbedImages)
                {
                    await EmbedImagesAsync(doc, opf, chapter, Path.Combine(epub, "images"));
                }
                else
                {
                    chapter.Content = doc.QuerySelector("body").ChildNodes.ToHtml(new XmlMarkupFormatter());
                }

                string randomFile = Path.GetRandomFileName() + ".xhtml";

                OpfItem item = new OpfItem(randomFile, StringUtilities.GenerateRandomString(6), MediaType.XHtmlType);
                opf.AddItem(item);

                File.WriteAllText(Path.Combine(epub, randomFile),
                                  RazorCompiler.Get(Templates[EBookTemplate.Chapter], "chapter", chapter));

                toc.Sections.Add(new Section
                {
                    Name = chapter.Name,
                    Href = randomFile
                });
            }

            string tocFile = Path.Combine(epub, "toc.xhtml");

            File.WriteAllText(tocFile, RazorCompiler.Get(Templates[EBookTemplate.TableOfContents], "toc", toc));

            opf.Save(Path.Combine(epub, "package.opf"));

            if (File.Exists(epubDest))
            {
                File.Delete(epubDest);
            }

            using (FileStream fs = new FileStream(epubDest, FileMode.CreateNew))
                using (ZipArchive za = new ZipArchive(fs, ZipArchiveMode.Create))
                {
                    za.CreateEntryFromFile(Path.Combine(tmpDir, "mimetype"), "mimetype", CompressionLevel.NoCompression);

                    Zip(za, epub, "EPUB");
                    Zip(za, metaInf, "META-INF");
                }

            Directory.Delete(tmpDir, true);
        }
Пример #2
0
        protected virtual async Task EmbedImagesAsync(IHtmlDocument doc, OpfFile opfFile, Chapter chapter, string outputDir)
        {
            var tasks  = new List <Task>();
            var images = new Dictionary <Uri, string>();

            foreach (var img in doc.QuerySelectorAll("img"))
            {
                string src = img.GetAttribute("src");
                if (src.StartsWith("//"))
                {
                    src = src.Substring(2);

                    if (!(src.StartsWith("http://") || src.StartsWith("https://")))
                    {
                        src = "http://" + src;
                    }
                }

                Uri uri;
                if (!Uri.TryCreate(src, UriKind.RelativeOrAbsolute, out uri))
                {
                    continue;
                }

                UriBuilder ub = new UriBuilder(uri)
                {
                    Query = string.Empty
                };
                uri = ub.Uri;

                string fileName = $"{Path.GetRandomFileName()}.{Path.GetExtension(uri.ToString())}".ToValidFilePath();

                if (string.IsNullOrEmpty(fileName))
                {
                    return;
                }

                string path = Path.Combine(outputDir, fileName);

                if (!images.ContainsKey(uri))
                {
                    images.Add(uri, path);
                }

                string filePath = Path.Combine(new DirectoryInfo(outputDir).Name, Path.GetFileName(path)).Replace(@"\", "/");
                img.SetAttribute("src", filePath);
            }

            foreach (var img in images)
            {
                tasks.Add(Task.Run(async() =>
                {
                    Uri uri           = img.Key;
                    string path       = img.Value;
                    string outputPath = Path.Combine(new DirectoryInfo(outputDir).Name, Path.GetFileName(path)).Replace(@"\", "/");
                    string src        = uri.ToString();

                    if (uri.IsAbsoluteUri && !uri.IsFile)
                    {
                        try
                        {
                            using (HttpClient client = new HttpClient())
                            {
                                HttpResponseMessage resp = await client.GetAsync(src);
                                resp.EnsureSuccessStatusCode();

                                string mediaType = resp.Content.Headers.ContentType.MediaType.ToLower();

                                if (mediaType != MediaType.JpegType && mediaType != MediaType.PngType)
                                {
                                    return;
                                }

                                if (File.Exists(path))
                                {
                                    return;
                                }

                                using (FileStream fs = new FileStream(path, FileMode.CreateNew))
                                    await resp.Content.CopyToAsync(fs);
                            }
                        }
                        catch (Exception)
                        {
                            return;
                        }
                    }
                    else if (File.Exists(src))
                    {
                        File.Copy(src, path);
                    }

                    MediaType mType = MediaType.FromExtension(Path.GetExtension(path));

                    if (mType == null)
                    {
                        return;
                    }

                    opfFile.AddItem(new OpfItem(outputPath, StringUtilities.GenerateRandomString(),
                                                mType), false);
                }));
            }

            await Task.WhenAll(tasks.ToArray());

            chapter.Content = doc.QuerySelector("body").ChildNodes.ToHtml(new XmlMarkupFormatter());
        }