Пример #1
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());
        }
Пример #2
-1
        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);
        }