From a25f3b57843fd81490f281175f469b2d1d8663fe Mon Sep 17 00:00:00 2001 From: avan06 Date: Thu, 21 Jul 2022 17:48:36 +0800 Subject: [PATCH] Added font options for EpubAozora of GenerateView. 1. Implement the display page number feature in GenerateView (need to be enabled in options). 2. New TextFont options: TextFontSize: Determine the font size of Epub or Aozora eBooks displayed in GenerateView (Default 30). TextFontName: Determine the font of Epub or Aozora eBooks displayed in GenerateView (Default "[FontFamily: Name=Microsoft Sans Serif]"). TextFontBold: Determines whether the font style of Epub or Aozora eBooks in GenerateView is bold (Default true). TextFontItalic: Determines whether the font style of Epub or Aozora eBooks in GenerateView is italic (Default false). 3. New WebViewStyle options: WebViewLineHeight: Determine the line-height style of Epub or Aozora eBooks in GenerateView's WebView (Default 200%). WebViewFontSize: Determine the font-size style of Epub or Aozora eBooks in GenerateView's WebView (Default 140%). --- NovelTool/Config.cs | 293 ---------------------- NovelTool/GenerateView.cs | 215 ++++++++++------ NovelTool/Main.cs | 68 +++-- NovelTool/NovelTool.csproj | 15 +- NovelTool/Option.cs | 10 +- NovelTool/Properties/AssemblyInfo.cs | 4 +- NovelTool/Properties/Settings.Designer.cs | 79 ++++++ NovelTool/Properties/Settings.settings | 18 ++ NovelTool/app.config | 8 + NovelTool/lib/OptionTreeView.dll | Bin 25600 -> 27136 bytes README.md | 15 +- 11 files changed, 308 insertions(+), 417 deletions(-) delete mode 100644 NovelTool/Config.cs diff --git a/NovelTool/Config.cs b/NovelTool/Config.cs deleted file mode 100644 index 75338b7..0000000 --- a/NovelTool/Config.cs +++ /dev/null @@ -1,293 +0,0 @@ -//using System; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; - -//namespace NovelTool -//{ -// class Config -// { -// //InputPath 輸入來源位置 -// public string InputPath { get; set; } -// //InputDirectionVertical 輸入文字方向為垂直,true: 上至下右至左,false: 左至右上至下 -// public bool InputDirectionVertical { get; set; } - -// //OutputFolder 輸出目標位置 -// public string OutputFolder { get; set; } -// //OutputWidth 輸出圖片寬度設定 -// public int OutputWidth { get; set; } -// //OutputHeight 輸出圖片高度設定 -// public int OutputHeight { get; set; } -// //OutputBGColor 輸出圖片底色設定 -// public string OutputBGColor { get; set; } -// //OutputImgFormat 設定輸出格式,jpg、png、gif、bmp -// public string OutputImgFormat { get; set; } - -// //OffsetWhite 白色的偏移量 -// public byte OffsetWhite { get; set; } -// //DefineWhite 解析圖片時,判定為白色區域的設定(ex. 245~255) -// public byte DefineWhite { get; set; } -// //DefineBlack 解析圖片時,判定非白色區域自動色彩加深(ex. 0~244 自動減30) -// public byte DefineBlack { get; set; } - -// //MarginLeft 輸出圖片左側邊距 -// public int MarginLeft { get; set; } -// //MarginRight 輸出圖片右側邊距 -// public int MarginRight { get; set; } -// //MarginTop 輸出圖片上側邊距 -// public int MarginTop { get; set; } -// //MarginBottom 輸出圖片下側邊距 -// public int MarginBottom { get; set; } - -// //IsShowAnalysisImg Encode bodyRects to image file -// public bool IsShowAnalysisImg { get; set; } -// //IsHighContrast 是否提升文字圖形對比 -// public bool IsHighContrast { get; set; } - -// //DrawHead 是否輸出表頭 -// public bool DrawHead { get; set; } -// //MarginHead 輸出圖片表頭邊距 -// public int MarginHead { get; set; } -// //DrawFooter 是否輸出頁尾 -// public bool DrawFooter { get; set; } -// //MarginFooter 輸出圖片頁尾邊距 -// public int MarginFooter { get; set; } -// //LeadingSize 輸出圖片時,重整文字圖片的每行邊距設定 -// public int LeadingSize { get; set; } -// //ExporScale 輸出圖片時,重整文字圖片的字體放大倍率,設定為零則以 MaxFontWidth 來自動判斷放大率 -// public double ExporScale { get; set; } -// //MaxFontWidth 輸出圖片的文字最大寬度 -// public int MaxFontWidth { get; set; } -// //IsFColorInversion 是否反轉前景顏色 -// public bool IsFColorInversion { get; set; } -// //IsBColorInversion 是否反轉背景顏色 -// public bool IsBColorInversion { get; set; } - -// //IllustrationMinWidth Minimum graphic width -// public int IllustrationMinWidth { get; set; } -// //IllustrationhMinHeight Minimum graphic height -// public int IllustrationhMinHeight { get; set; } -// //IllustrationRate proportion of grap -// public double IllustrationRate { get; set; } - -// //HeadMinRate Minimum proportion of Head -// public double HeadMinRate { get; set; } -// //FooterMinRate Minimum proportion of Footer -// public double FooterMinRate { get; set; } - -// //ContextMinRate Minimum proportion of context -// public double ContextMinRate { get; set; } -// //ContextMaxRate Maximum proportion of context -// public double ContextMaxRate { get; set; } -// //RubyMinRate Minimum proportion of ruby -// public double RubyMinRate { get; set; } -// //RubyMaxRate Maximum proportion of ruby -// public double RubyMaxRate { get; set; } -// //SymbolMinRate Minimum proportion of symbol -// public double SymbolMinRate { get; set; } -// //SymbolMaxRate Maximum proportion of symbol -// public double SymbolMaxRate { get; set; } - -// //SplitMaxNonBlank Allow non-blank maximum limit when splitting -// public int SplitMaxNonBlank { get; set; } -// //SplitMinRate Minimum proportion for split word -// public double SplitMinRate { get; set; } -// //SplitMaxRate Maximum proportion for split word -// public double SplitMaxRate { get; set; } - -// //AddPageNumber 是否輸出顯示頁數 -// public bool AddPageNumber { get; set; } -// //AddSourcePageNumber 是否輸出顯示來源檔名稱, -// public bool AddSourceName { get; set; } -// //PageNumberPosition TopLeft、TopRight、BottomLeft、BottomRight -// public PositionType PageNumberPosition { get; set; } - -// //IsAnalysisCenter 是否從中間位置切圖 -// public bool IsAnalysisCenter { get; set; } -// //IsAnalysisHorizon 是否從水平面切圖 -// public bool IsAnalysisHorizon { get; set; } -// //IsEdgeBlankRemove 從中間位置切圖時,是否移除邊緣空白 -// public bool IsEdgeBlankRemove { get; set; } -// //CenterDetectorRata 從中間位置切圖時,偵測中間範圍佔 X 軸的比例 -// public double CenterDetectorRata { get; set; } - -// //IsConfirmIllustrationByCount 是否使用非白色數量大小來辨識插圖(辨識錯誤時改為false) -// public bool IsConfirmIllustrationByCount { get; set; } -// //ConfirmIllustrationMinCount 檢測為插圖的非白色最小數量(超過此值判定為插圖) -// public int ConfirmIllustrationMinCount { get; set; } - -// //ConfirmHeadGap 檢測頁面的表頭離主體之間的空隙大小 -// public int ConfirmHeadGap { get; set; } -// //ConfirmFooterGap 檢測頁面的頁尾離主體之間的空隙大小 -// public int ConfirmFooterGap { get; set; } - -// //IgnoreMinDetectYSize 偵測圖片 Head、Footer 之最小高度 -// public int IgnoreMinDetectYSize { get; set; } -// //IgnoreEdgeSize 偵測圖片時忽略外測邊緣處的大小,0:不忽略 -// public int IgnoreEdgeSize { get; set; } - -// //IsNewLineForENDtoHEADSymbol 原稿文字連續的兩行,頭尾為符號時,輸出時是否需要換行 -// public bool IsNewLineForENDtoHEADSymbol { get; set; } - -// //EndBoundaryMinCount 統計整體底端位置時,忽略少於最小次數的值 -// public int EndBoundaryMinCount { get; set; } - -// //StartAnalysIndex 開始分析圖片的起始位置,將小於此索引數的來源檔案列為Illustration圖片 -// public int StartAnalysIndex { get; set; } - -// //isCalOuterGreaterContext 當寬度大於常規寬度(可能為標題欄位),是否依據外圍重新計算每字寬度,否則直接用最寬的寬度 -// public bool isCalOuterGreaterContext { get; set; } - -// //for freetype -// //public double TextDpi { get; set; } -// //public string TextFont { get; set; } //msjh.ttc、meiryo.ttc、msgothic.ttc -// //public string TextFontBold { get; set; } //msjhbd.ttc、meiryob.ttc、msgothic.ttc -// //public double TextSize { get; set; } -// //public double TextSpacing { get; set; } -// //public font.Hinting Hinting { get; set; } //0:HintingNone、1:HintingVertical、2:HintingFull - -// public Config InitOption() -// { -// Config config = new Config -// { -// //InputDirectionVertical 輸入文字方向為垂直,true: 上至下右至左,false: 左至右上至下 -// InputDirectionVertical = true, - -// //OutputName 輸出目標位置, -// OutputFolder = @"output\", -// //OutputWidth 輸出圖片寬度設定, -// OutputWidth = 1125, -// //OutputHeight 輸出圖片高度設定, -// OutputHeight = 1600, -// //OutputBGColor 輸出圖片底色設定, -// OutputBGColor = "#fff", -// //OutputImgFormat 設定輸出格式,jpg、png、gif、bmp -// OutputImgFormat = "png", - -// //OffsetWhite 白色的偏移量 -// OffsetWhite = 0, -// //DefineWhite 解析圖片時,判定為白色區域的設定(ex. 245~255), -// DefineWhite = 245, -// //DefineBlack 解析圖片時,判定非白色區域自動色彩加深(ex. 0~244 自動減30), -// DefineBlack = 50, - -// //MarginLeft 輸出圖片左側邊距, -// MarginLeft = 30, -// //MarginRight 輸出圖片右側邊距, -// MarginRight = 30, -// //MarginTop 輸出圖片上側邊距, -// MarginTop = 30, -// //MarginBottom 輸出圖片下側邊距, -// MarginBottom = 30, - -// //IsShowAnalysisImg Encode bodyRects to image file, -// IsShowAnalysisImg = true, -// //IsHighContrast 是否提升文字圖形對比, -// IsHighContrast = true, - -// //DrawHead 是否輸出表頭, -// DrawHead = false, -// //MarginHead 輸出圖片表頭邊距, -// MarginHead = 40 + MarginTop, -// //DrawFooter 是否輸出頁尾, -// DrawFooter = false, -// //MarginFooter 輸出圖片頁尾邊距, -// MarginFooter = 40 + MarginBottom, -// //LeadingSize 輸出圖片時,重整文字圖片的每行邊距設定, -// LeadingSize = 30, -// //ExporScale 輸出圖片時,重整文字圖片的字體放大倍率,設定為零則以 MaxFontWidth 來自動判斷放大率, -// ExporScale = 0, -// //MaxFontWidth 輸出圖片的文字最大寬度, -// MaxFontWidth = 40, -// //IsFColorInversion 是否反轉前景顏色, -// IsFColorInversion = false, -// //IsBColorInversion 是否反轉背景顏色, -// IsBColorInversion = false, - -// //IllustrationMinWidth Minimum graphic width, -// IllustrationMinWidth = 100, -// //IllustrationhMinHeight Minimum graphic height, -// IllustrationhMinHeight = 100, -// //IllustrationRate proportion of grap -// IllustrationRate = 3, - -// //HeadMinRate Minimum proportion of Head -// HeadMinRate = 0.1, -// //FooterMinRate Minimum proportion of Footer -// FooterMinRate = 0.9, - -// //ContextMinRate Minimum proportion of context -// ContextMinRate = 0.9, -// //ContextMaxRate Maximum proportion of context -// ContextMaxRate = 1.1, -// //RubyMinRate Minimum proportion of ruby -// RubyMinRate = 0.5, -// //RubyMaxRate Maximum proportion of ruby, -// RubyMaxRate = 0.7, -// //SymbolMinRate Minimum proportion of symbol -// SymbolMinRate = 0.2, -// //SymbolMaxRate Maximum proportion of symbol -// SymbolMaxRate = 0.5, - -// //SplitMaxNonBlank Allow non-blank maximum limit when splitting -// SplitMaxNonBlank = 4, -// //SplitMinRate Minimum proportion for split word -// SplitMinRate = 0.85, -// //SplitMaxRate Maximum proportion for split word -// SplitMaxRate = 1.5, - -// //AddPageNumber 是否輸出顯示頁數, -// AddPageNumber = true, -// //AddSourcePageNumber 是否輸出顯示來源檔名稱, -// AddSourceName = true, -// //PageNumberPosition TopLeft、TopRight、BottomLeft、BottomRight, -// PageNumberPosition = PositionType.BottomLeft, - -// //IsAnalysisCenter 是否從中間位置切圖, -// IsAnalysisCenter = false, -// //IsAnalysisHorizon 是否從水平面切圖, -// IsAnalysisHorizon = false, -// //IsEdgeBlankRemove 從中間位置切圖時,是否移除邊緣空白, -// IsEdgeBlankRemove = false, -// //CenterDetectorRata 從中間位置切圖時,偵測中間範圍佔 X 軸的比例, -// CenterDetectorRata = 0.1, - -// //IsConfirmIllustrationByCount 是否使用非白色數量大小來辨識插圖(辨識錯誤時改為false) -// IsConfirmIllustrationByCount = true, -// //ConfirmIllustrationMinCount 檢測為插圖的非白色最小數量(超過此值判定為插圖) -// ConfirmIllustrationMinCount = 390000, - -// //ConfirmHeadGap 檢測頁面的表頭離主體之間的空隙大小 -// ConfirmHeadGap = 15, -// //ConfirmFooterGap 檢測頁面的頁尾離主體之間的空隙大小 -// ConfirmFooterGap = 15, - -// //IgnoreMinDetectYSize 偵測圖片 Head、Footer 之最小高度 -// IgnoreMinDetectYSize = 3, -// //IgnoreEdgeSize 偵測圖片時忽略外測邊緣處的大小,0:不忽略 -// IgnoreEdgeSize = 3, - -// //IsNewLineForENDtoHEADSymbol 原稿文字連續的兩行,頭尾為符號時,輸出時是否需要換行 -// IsNewLineForENDtoHEADSymbol = false, - -// //EndBoundaryMinCount 統計整體底端位置時,忽略少於最小次數的值 -// EndBoundaryMinCount = 3, - -// //StartAnalysIndex 開始分析圖片的起始位置,將小於此索引數的來源檔案列為Illustration圖片 -// StartAnalysIndex = 0, - -// //isCalOuterGreaterContext 當寬度大於常規寬度(可能為標題欄位),是否依據外圍重新計算每字寬度,否則直接用最寬的寬度 -// isCalOuterGreaterContext = true, - -// //for TextContext *freetype.Context, -// //TextDpi = 72, -// //TextFont = "meiryo.ttc", //msgothic.ttc、msjhbd.ttc、meiryo.ttc -// //TextFontBold = "meiryob.ttc", //msjhbd.ttc、meiryob.ttc、msgothic.ttc -// //TextSize = 40, //option.MaxFontWidth -// //TextSpacing = 1.5, -// //Hinting = font.HintingFull, -// }; -// return config; -// } -// } -//} diff --git a/NovelTool/GenerateView.cs b/NovelTool/GenerateView.cs index 7bb772d..388f567 100644 --- a/NovelTool/GenerateView.cs +++ b/NovelTool/GenerateView.cs @@ -42,6 +42,13 @@ public partial class GenerateView : Form private Color OutputForeColor; private float ForeColorRate; + private float TextFontSize; + private FontFamily TextFontFamily; + private FontStyle FontTextStyle; + + private string WebViewLineHeight; + private string WebViewFontSize; + #region Event #region OutputView @@ -113,9 +120,11 @@ private void ToolStripSaveAll_Click(object sender, EventArgs e) } using (Bitmap outputImage = new Bitmap(result.Width, result.Height)) using (Graphics graphics = Graphics.FromImage(outputImage)) - using (SolidBrush backBrush = new SolidBrush(OutputBackColor)) { - if (!(result.Tag is bool)) graphics.FillRectangle(backBrush, 0, 0, result.Width, result.Height); + if (!(result.Tag is bool)) //Bitmap Not Illustration + using (SolidBrush backBrush = new SolidBrush(OutputAdjustColorCheck ? OutputBackColor : Color.White)) + graphics.FillRectangle(backBrush, 0, 0, result.Width, result.Height); + graphics.DrawImage(result, 0, 0, result.Width, result.Height); ImageTool.SaveImage(outputImage, path, name, extension, imgEncoder, encoderParameters, pixelFormat); } @@ -231,6 +240,13 @@ private GenerateView() OutputForeColor = Color.FromKnownColor(Properties.Settings.Default.OutputForeColor.Value); ForeColorRate = Properties.Settings.Default.ForeColorRate.Value; + TextFontSize = Properties.Settings.Default.TextFontSize.Value; + TextFontFamily = Properties.Settings.Default.TextFontFamily.Value; + FontTextStyle = (Properties.Settings.Default.TextFontBold.Value ? FontStyle.Bold : 0) | (Properties.Settings.Default.TextFontItalic.Value ? FontStyle.Italic : 0); + + WebViewLineHeight = Properties.Settings.Default.WebViewLineHeight.Value; + WebViewFontSize = Properties.Settings.Default.WebViewFontSize.Value; + InitializeComponent(); } @@ -334,9 +350,9 @@ public GenerateView(Main mainForm, bool isWeView = false) : this() "body {\n" + "background-color: " + "#" + OutputBackColor.R.ToString("X2") + OutputBackColor.G.ToString("X2") + OutputBackColor.B.ToString("X2") + ";" + "color: " + "#" + OutputForeColor.R.ToString("X2") + OutputForeColor.G.ToString("X2") + OutputForeColor.B.ToString("X2") + ";" + - "line-height: 200%;" + - "font-size: 140%;" + - "font-family: 'Lucida Grande', 'Meiryo', 'Meiryo UI', 'Microsoft JhengHei UI', 'Microsoft JhengHei', sans-serif;" + + "line-height: " + WebViewLineHeight + ";" + + "font-size: " + WebViewFontSize + ";" + + "font-family: '" + TextFontFamily.Name + "', 'Lucida Grande', 'Meiryo', 'Meiryo UI', 'Microsoft JhengHei UI', 'Microsoft JhengHei', sans-serif;" + "-ms-writing-mode: tb-rl;" + "writing-mode: vertical-rl;" + "overflow-x: scroll;" + @@ -407,9 +423,8 @@ private int ParseOutput(int outputIdx, bool outputAll = false) { int outputCount = 0; - float zoomFactor = mainForm.ZoomFactor; - var modeWidth = mainForm.Modes.Width * zoomFactor; - var modeWidthMax = mainForm.Modes.WidthMax * zoomFactor; + var modeWidth = mainForm.Modes.Width * mainForm.ZoomFactor; + var modeWidthMax = mainForm.Modes.WidthMax * mainForm.ZoomFactor; outputImgs = new List(); Bitmap destImage = null; @@ -422,9 +437,9 @@ private int ParseOutput(int outputIdx, bool outputAll = false) #region Parse Text Image if (pageData.textList == null || pageData.textList.Count <= 0) { - AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor, false, true); //trigger create new dest Image when destImage is null + AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, false, true); //trigger create new dest Image when destImage is null if (pageData.isIllustration) //此頁為圖片時,先儲存目前已產生頁面,再儲存圖片檔案 - AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor, true, false, true); //Trigger to save Illustration Image + AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, true, false, true); //Trigger to save Illustration Image else if (pageData.columnBodyList != null) { float offsetX = -1; @@ -449,11 +464,11 @@ private int ParseOutput(int outputIdx, bool outputAll = false) if (RType == RectType.BodyIn && Width > mainForm.Modes.WidthMax && destPoint.X != InitWidthLocation) // && Entitys[0].RType == RectType.EntityHead { //該行為本頁最右邊第一段,且寬度大於眾數最大寬度,可能為標題,且輸出座標已非初始位置,換一頁輸出顯示 - AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint); //trigger save and create new dest Image } - int newWidth = (int)(Width * zoomFactor); - int blankWidth = offsetX != -1 ? (int)((offsetX - X - Width) * zoomFactor) : 0; + int newWidth = (int)(Width * mainForm.ZoomFactor); + int blankWidth = offsetX != -1 ? (int)((offsetX - X - Width) * mainForm.ZoomFactor) : 0; double blankFactor = (double)blankWidth / newWidth; blankFactor = blankFactor > 2.5 ? 2.5 : (blankFactor < 1.5 ? 0 : blankFactor); destPoint.X -= (int)(newWidth * blankFactor); //原圖兩行之間的空白行較大時,輸出位置加上空白行比例寬度 @@ -467,22 +482,22 @@ private int ParseOutput(int outputIdx, bool outputAll = false) if (destPoint.X == InitWidthLocation) destPoint.X -= newWidth + Leading; //位移右邊第一行輸出位置 if (columnRuby.Entitys != null && columnRuby.X - X - Width > mainForm.Modes.Width * EntityAdjacentRate) { //column 與 Ruby 非相鄰時,代表右側非 Ruby - var rubyWidth = (int)(columnRuby.Width * zoomFactor); - GenerateDrawImage(pageData, columnRuby.X, columnRuby.Width, columnRuby.Entitys, rubyWidth, zoomFactor, outputIdx, + var rubyWidth = (int)(columnRuby.Width * mainForm.ZoomFactor); + GenerateDrawImage(pageData, columnRuby.X, columnRuby.Width, columnRuby.Entitys, rubyWidth, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, ImageTool.NewEntitys(), outputAll); columnRuby = ImageTool.NewEntitys(); } - GenerateDrawImage(pageData, X, Width, Entitys, newWidth, zoomFactor, outputIdx, + GenerateDrawImage(pageData, X, Width, Entitys, newWidth, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, columnRuby, outputAll); offsetX = X; if (columnRuby.Entitys != null) columnRuby = ImageTool.NewEntitys(); if (Entitys[Entitys.Count - 1].Height < mainForm.Modes.HeighMin && Entitys[Entitys.Count - 1].RType != RectType.EntityEnd) - destPoint.Y += (int)(mainForm.Modes.HeighMin * zoomFactor); //每行非句尾的最後一字(句子連接下一頁),若高度不到最小高度(例如符號字),則增加空白輸出 + destPoint.Y += (int)(mainForm.Modes.HeighMin * mainForm.ZoomFactor); //每行非句尾的最後一字(句子連接下一頁),若高度不到最小高度(例如符號字),則增加空白輸出 else if (RType == RectType.BodyOut && Entitys[Entitys.Count - 1].RType == RectType.EntityEnd) - AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint); //trigger save and create new dest Image } } } @@ -491,7 +506,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) else { bool isBegin = false; - float fontSize = 30 * zoomFactor; + float fontSize = TextFontSize * mainForm.ZoomFactor; float blankSize = fontSize / 6; PointF destRubyPTmp = PointF.Empty; StringFormat format = new StringFormat();/*StringFormat.GenericTypographic*/ @@ -499,17 +514,17 @@ private int ParseOutput(int outputIdx, bool outputAll = false) format.LineAlignment = StringAlignment.Center; for (int tIdx = 0; tIdx < pageData.textList.Count; tIdx++) { - AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor, false, true); //trigger create new dest Image when destImage is null + AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, false, true); //trigger create new dest Image when destImage is null (string text, string ruby) = pageData.textList[tIdx]; bool newLineFlag = text.EndsWith("\n"); text = text.Replace("\n", ""); if (text == "_pagebreak_") { - AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint); //trigger save and create new dest Image } else if (text == "_img_") { - AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor, true, false, true, ruby); //Trigger to save Illustration Image + AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, true, false, true, ruby); //Trigger to save Illustration Image } else if (text == "_bold_") { /*webStr.Append($"{ruby}");*/ } else @@ -526,9 +541,9 @@ private int ParseOutput(int outputIdx, bool outputAll = false) do { isContinue = false; + using (var foreBrush = new SolidBrush(OutputForeColor)) using (Graphics gr = Graphics.FromImage(destImage)) { - //gr.CompositingMode = CompositingMode.SourceCopy; gr.CompositingQuality = CompositingQuality.HighQuality; gr.InterpolationMode = InterpolationMode.HighQualityBicubic; gr.SmoothingMode = SmoothingMode.AntiAlias; @@ -536,12 +551,6 @@ private int ParseOutput(int outputIdx, bool outputAll = false) gr.PageUnit = GraphicsUnit.Pixel; gr.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;//AntiAlias; - //Get instance brush with Solid style to draw background - Brush backBrush = new SolidBrush(OutputBackColor); - //Get instance a font to draw item name with this style - var foreBrush = new SolidBrush(OutputForeColor); - Font itemFont = new Font("Microsoft Sans Serif", fontSize, FontStyle.Bold, GraphicsUnit.Pixel); //Meiryo、MS Gothic、MS PGothic - if (ruby.Length > 0) { RectangleF destRect = new RectangleF(destPoint.X + fontSize + blankSize, destPoint.Y, fontSize / 2, fontSize / 2); @@ -551,7 +560,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) { if (destRect.X - fontSize - Leading < MarginLeft) { //若輸出 X軸位置已於最左側,則紀錄Ruby目前索引 - //AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + //AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, mainForm.ZoomFactor); //trigger save and create new dest Image idxRuby = idx; isContinue = true; break; @@ -564,7 +573,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) #region FixVerticalAlign if ("ー".IndexOf(charR) != -1) { //日本語の長音符 - rubyPath.AddString("丨", new FontFamily("Microsoft Sans Serif"), (int)FontStyle.Bold, fontSize / 2, new PointF(0, 0), format); + rubyPath.AddString("丨", TextFontFamily, (int)FontTextStyle, fontSize / 2, new PointF(0, 0), format); using (var flipXMatrix = new Matrix(-1, 0, 0, 1, destRect.X + fontSize / 4, destRect.Y + fontSize / 4)) using (Matrix matrix = new Matrix()) { //Flip a Graphics object. https://stackoverflow.com/a/53182901 @@ -574,7 +583,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) } else { - rubyPath.AddString(charR.ToString(), new FontFamily("Microsoft Sans Serif"), (int)FontStyle.Bold, fontSize / 2, destRect, format); + rubyPath.AddString(charR.ToString(), TextFontFamily, (int)FontTextStyle, fontSize / 2, destRect, format); if (IsVerticalAlign(charR)) //「」『』ー─―…()()〈〉《》〔〕﹝﹞【】〝〟==~~ { using (Matrix mRotate = new Matrix()) @@ -608,7 +617,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) { if (destPoint.X - Leading < MarginLeft) { //若輸出 X軸位置已於最左側,則換一頁 - AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint); //trigger save and create new dest Image idxText = idx; isContinue = true; break; @@ -623,7 +632,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) #region FixVerticalAlign if ("ー".IndexOf(charT) != -1) { //日本語の長音符 - textPath.AddString("丨", new FontFamily("Microsoft Sans Serif"), (int)FontStyle.Bold, fontSize, new PointF(0, 0), format); + textPath.AddString("丨", TextFontFamily, (int)FontTextStyle, fontSize, new PointF(0, 0), format); using (var flipXMatrix = new Matrix(-1, 0, 0, 1, destRect.X + fontSize / 2, destRect.Y + fontSize / 2)) using (Matrix matrix = new Matrix()) { //Flip a Graphics object. https://stackoverflow.com/a/53182901 @@ -633,7 +642,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) } else { - textPath.AddString(charT.ToString(), new FontFamily("Microsoft Sans Serif"), (int)FontStyle.Bold, fontSize, destRect, format); + textPath.AddString(charT.ToString(), TextFontFamily, (int)FontTextStyle, fontSize, destRect, format); if (IsVerticalAlign(charT)) //「」『』ー─―…()()〈〉《》〔〕﹝﹞【】〝〟==~~ { using (Matrix mRotate = new Matrix()) @@ -668,7 +677,7 @@ private int ParseOutput(int outputIdx, bool outputAll = false) destPoint.Y = InitHeightLocation; if (destPoint.X - Leading < MarginLeft) { - AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint); //trigger save and create new dest Image } } } @@ -701,12 +710,12 @@ private int ParseOutput(int outputIdx, bool outputAll = false) /// Trigger to generate new Bitmap page /// Trigger to save the current source Bitmap when the source is an illustration private void AddNowCreateNext(PageData pageData, bool outputAll, int outputIdx, - ref int outputCount, ref Bitmap srcImage, ref Bitmap destImage, ref PointF destPoint, double zoomFactor, - bool triggerAdd = true, bool triggerCreate = true, bool triggerSrcAdd = false) => AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor, + ref int outputCount, ref Bitmap srcImage, ref Bitmap destImage, ref PointF destPoint, + bool triggerAdd = true, bool triggerCreate = true, bool triggerSrcAdd = false) => AddNowCreateNext(outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, triggerAdd, triggerCreate, triggerSrcAdd, string.Format("{0}/{1}", pageData.path, pageData.name), false, pageData.columnHeadList, pageData.columnFooterList); private void AddNowCreateNext(bool outputAll, int outputIdx, - ref int outputCount, ref Bitmap srcImage, ref Bitmap destImage, ref PointF destPoint, double zoomFactor, + ref int outputCount, ref Bitmap srcImage, ref Bitmap destImage, ref PointF destPoint, bool triggerAdd = true, bool triggerCreate = true, bool triggerSrcAdd = false, string fullPath = "", bool isEpubAozora = true, List<(RectType RType, float X, float Y, float Width, float Height, List<(RectType RType, float X, float Y, float Width, float Height)> Entitys)> columnHeadList = null, List<(RectType RType, float X, float Y, float Width, float Height, List<(RectType RType, float X, float Y, float Width, float Height)> Entitys)> columnFooterList = null) @@ -744,9 +753,10 @@ private void AddNowCreateNext(bool outputAll, int outputIdx, { if (srcImage == null) srcImage = OpenImage(fullPath); - GenerateDrawTitle(HeadPositionType, columnHeadList, zoomFactor, srcImage, ref destImage); - GenerateDrawTitle(FooterPositionType, columnFooterList, zoomFactor, srcImage, ref destImage); + GenerateDrawTitle(HeadPositionType, columnHeadList, srcImage, ref destImage); + GenerateDrawTitle(FooterPositionType, columnFooterList, srcImage, ref destImage); } + GenerateDrawText(PagePositionType, outputIdx.ToString(), srcImage, ref destImage); } else (destImage, destPoint) = CreateDestImage(1, 1, null); } @@ -763,12 +773,12 @@ private void AddNowCreateNext(bool outputAll, int outputIdx, /// Margin size of print header or footer private void GenerateDrawTitle(PositionType PositionTypeBoxTitle, List<(RectType RType, float X, float Y, float Width, float Height, List<(RectType RType, float X, float Y, float Width, float Height)> Entitys)> columnTitleList, - double zoomFactor, Bitmap srcImage, ref Bitmap destImage, int initSize = 10) + Bitmap srcImage, ref Bitmap destImage, int initSize = 10) { if (PositionTypeBoxTitle == PositionType.None || columnTitleList == null || columnTitleList.Count <= 0) return; float offsetX = -1; - int modeWidth = (int)(mainForm.Modes.Width * zoomFactor); + int modeWidth = (int)(mainForm.Modes.Width * mainForm.ZoomFactor); Point destPointTitle = new Point(initSize, initSize); if (PositionTypeBoxTitle == PositionType.TopRight) destPointTitle = new Point(OutputWidth - initSize, initSize); else if (PositionTypeBoxTitle == PositionType.BottomRight) destPointTitle = new Point(OutputWidth - initSize, OutputHeight - initSize); @@ -782,35 +792,26 @@ private void GenerateDrawTitle(PositionType PositionTypeBoxTitle, for (int cIdx = columnTitleList.Count - 1; cIdx >= 0; cIdx--) { var columnTitle = columnTitleList[cIdx]; - int newWidth = (int)(columnTitle.Width * zoomFactor); - int newHeight = (int)(columnTitle.Height * zoomFactor); - int blankWidth = offsetX != -1 ? (int)((offsetX - columnTitle.X - columnTitle.Width) * zoomFactor) : 0; + int newWidth = (int)(columnTitle.Width * mainForm.ZoomFactor); + int newHeight = (int)(columnTitle.Height * mainForm.ZoomFactor); + int blankWidth = offsetX != -1 ? (int)((offsetX - columnTitle.X - columnTitle.Width) * mainForm.ZoomFactor) : 0; blankWidth = blankWidth > modeWidth ? modeWidth : blankWidth; DrawTitle(columnTitle, newWidth, newHeight, -blankWidth, true, destPointTitle.Y == OutputHeight - initSize, srcImage, ref destImage, ref destPointTitle); offsetX = columnTitle.X; } } - else if (PositionTypeBoxTitle == PositionType.TopLeft || PositionTypeBoxTitle == PositionType.BottomLeft) - { - for (int cIdx = 0; cIdx < columnTitleList.Count; cIdx++) - { - var columnTitle = columnTitleList[cIdx]; - int newWidth = (int)(columnTitle.Width * zoomFactor); - int newHeight = (int)(columnTitle.Height * zoomFactor); - int blankWidth = offsetX != -1 ? (int)((columnTitle.X - offsetX) * zoomFactor) : 0; - blankWidth = blankWidth > modeWidth ? modeWidth : blankWidth; - DrawTitle(columnTitle, newWidth, newHeight, blankWidth, false, destPointTitle.Y == OutputHeight - initSize, srcImage, ref destImage, ref destPointTitle); - offsetX = columnTitle.X + columnTitle.Width; - } - } - else if (PositionTypeBoxTitle == PositionType.Top || PositionTypeBoxTitle == PositionType.Bottom) + else if (PositionTypeBoxTitle == PositionType.TopLeft || PositionTypeBoxTitle == PositionType.BottomLeft || PositionTypeBoxTitle == PositionType.Top || PositionTypeBoxTitle == PositionType.Bottom) { + if (PositionTypeBoxTitle == PositionType.Top || PositionTypeBoxTitle == PositionType.Bottom) + destPointTitle.X -= (int)(columnTitleList.Count > 1 ? (columnTitleList[columnTitleList.Count - 1].X + + columnTitleList[columnTitleList.Count - 1].Width - columnTitleList[0].X) : columnTitleList[0].Width) / 2; + for (int cIdx = 0; cIdx < columnTitleList.Count; cIdx++) { var columnTitle = columnTitleList[cIdx]; - int newWidth = (int)(columnTitle.Width * zoomFactor); - int newHeight = (int)(columnTitle.Height * zoomFactor); - int blankWidth = offsetX != -1 ? (int)((columnTitle.X - offsetX) * zoomFactor) : 0; + int newWidth = (int)(columnTitle.Width * mainForm.ZoomFactor); + int newHeight = (int)(columnTitle.Height * mainForm.ZoomFactor); + int blankWidth = offsetX != -1 ? (int)((columnTitle.X - offsetX) * mainForm.ZoomFactor) : 0; blankWidth = blankWidth > modeWidth ? modeWidth : blankWidth; DrawTitle(columnTitle, newWidth, newHeight, blankWidth, false, destPointTitle.Y == OutputHeight - initSize, srcImage, ref destImage, ref destPointTitle); offsetX = columnTitle.X + columnTitle.Width; @@ -853,10 +854,71 @@ private void DrawTitle((RectType RType, float X, float Y, float Width, float Hei if (!shiftLeftX) destPointTitle.X += newWidth; } - /// - /// Read image file and parse to Bitmap. - /// - private Bitmap OpenImage(string path, string name) => OpenImage(string.Format("{0}/{1}", path, name)); + private void GenerateDrawText(PositionType PositionTypeBoxTitle, string text, + Bitmap srcImage, ref Bitmap destImage, int initSize = 10) + { + if (PositionTypeBoxTitle == PositionType.None || text.Trim() == "") return; + + Point destPoint = new Point(initSize, initSize); + + StringFormat format = new StringFormat(); + format.Alignment = StringAlignment.Near; + format.LineAlignment = StringAlignment.Near; + + if (PositionTypeBoxTitle == PositionType.TopRight) + { + destPoint = new Point(OutputWidth - initSize, initSize); + format.Alignment = StringAlignment.Far; + } + else if (PositionTypeBoxTitle == PositionType.BottomRight) + { + destPoint = new Point(OutputWidth - initSize, OutputHeight - initSize); + format.Alignment = StringAlignment.Far; + format.LineAlignment = StringAlignment.Far; + } + else if (PositionTypeBoxTitle == PositionType.TopLeft) + { + destPoint = new Point(initSize, initSize); + } + else if (PositionTypeBoxTitle == PositionType.BottomLeft) + { + destPoint = new Point(initSize, OutputHeight - initSize); + format.LineAlignment = StringAlignment.Far; + } + else if (PositionTypeBoxTitle == PositionType.Top) + { + destPoint = new Point(OutputWidth / 2, initSize); + format.Alignment = StringAlignment.Center; + } + else if (PositionTypeBoxTitle == PositionType.Bottom) + { + destPoint = new Point(OutputWidth / 2, OutputHeight - initSize); + format.Alignment = StringAlignment.Center; + format.LineAlignment = StringAlignment.Far; + } + + DrawText(text, format, ref destImage, ref destPoint); + } + + private void DrawText(string text, StringFormat format, ref Bitmap destImage, ref Point destPoint) + { + using (Graphics gr = Graphics.FromImage(destImage)) + { + gr.CompositingQuality = CompositingQuality.HighQuality; + gr.InterpolationMode = InterpolationMode.HighQualityBicubic; + gr.SmoothingMode = SmoothingMode.AntiAlias; + gr.PixelOffsetMode = PixelOffsetMode.HighQuality; + gr.PageUnit = GraphicsUnit.Pixel; + gr.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; + + using (var foreBrush = new SolidBrush(OutputForeColor)) + using (GraphicsPath textPath = new GraphicsPath()) + { + textPath.AddString(text, TextFontFamily, (int)FontTextStyle, TextFontSize * mainForm.ZoomFactor, destPoint, format); + gr.FillPath(foreBrush, textPath); + } + } + } /// /// Read image file and parse to Bitmap. @@ -905,23 +967,22 @@ private Bitmap OpenImage(string fullPath) /// Ruby column information of the current column of the source bitmap /// is generate all pages private void GenerateDrawImage(PageData pageData, float columnX, float columnWidth, - List<(RectType RType, float X, float Y, float Width, float Height)> Entitys, int newWidth, - float zoomFactor, int outputIdx, + List<(RectType RType, float X, float Y, float Width, float Height)> Entitys, int newWidth, int outputIdx, ref int outputCount, ref Bitmap srcImage, ref Bitmap destImage, ref PointF destPoint, (RectType RType, float X, float Y, float Width, float Height, List<(RectType RType, float X, float Y, float Width, float Height)> Entitys) columnRuby, bool outputAll = false) { float offsetY = pageData.rectBody.Y; //The Y-axis position of the top of the body of the source Bitmap int rubyIdx = 0; var rubyNewWidth = 0; - var modeWidth = mainForm.Modes.Width * zoomFactor; + var modeWidth = mainForm.Modes.Width * mainForm.ZoomFactor; (RectType RType, float X, float Y, float Width, float Height) rubyEntity = (0, 0, 0, 0, 0); - if (columnRuby.Entitys != null && columnRuby.Entitys.Count > 0) rubyNewWidth = (int)(columnRuby.Width * zoomFactor); + if (columnRuby.Entitys != null && columnRuby.Entitys.Count > 0) rubyNewWidth = (int)(columnRuby.Width * mainForm.ZoomFactor); if (columnRuby.Entitys != null && rubyIdx < columnRuby.Entitys.Count) rubyEntity = columnRuby.Entitys[rubyIdx++]; for (int eIdx = 0; eIdx < Entitys.Count; eIdx++) { var entity = Entitys[eIdx]; - var blankHeight = entity.Y > offsetY ? ((entity.Y - offsetY) * zoomFactor) : 0; - int newHeight = (int)(entity.Height * zoomFactor); + var blankHeight = entity.Y > offsetY ? ((entity.Y - offsetY) * mainForm.ZoomFactor) : 0; + int newHeight = (int)(entity.Height * mainForm.ZoomFactor); if (destPoint.Y != InitHeightLocation) { if (eIdx == 0) destPoint.X += newWidth < modeWidth ? (int)(modeWidth - newWidth) : 0; //該行寬度小於通常寬度時,將輸出 X軸位置往右偏移一點 @@ -944,7 +1005,7 @@ private void GenerateDrawImage(PageData pageData, float columnX, float columnWid } if (destPoint.X < MarginLeft) { //若輸出 X軸位置已於最左側,則換一頁 - AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint, zoomFactor); //trigger save and create new dest Image + AddNowCreateNext(pageData, outputAll, outputIdx, ref outputCount, ref srcImage, ref destImage, ref destPoint); //trigger save and create new dest Image destPoint.X -= newWidth + Leading; } destPoint.Y += blankHeight; @@ -966,9 +1027,9 @@ private void GenerateDrawImage(PageData pageData, float columnX, float columnWid { while ((rubyEntity.Y >= entity.Y && rubyEntity.Y <= entity.Y + entity.Height) || (entity.Y >= rubyEntity.Y && entity.Y <= rubyEntity.Y + rubyEntity.Height)) { - int rubyNewHeight = (int)(rubyEntity.Height * zoomFactor); - int rubyOffsetX = (int)((rubyEntity.X - entity.X - entity.Width) * zoomFactor); - int rubyOffsetY = (int)((rubyEntity.Y - entity.Y) * zoomFactor); + int rubyNewHeight = (int)(rubyEntity.Height * mainForm.ZoomFactor); + int rubyOffsetX = (int)((rubyEntity.X - entity.X - entity.Width) * mainForm.ZoomFactor); + int rubyOffsetY = (int)((rubyEntity.Y - entity.Y) * mainForm.ZoomFactor); RectangleF rubyDestRect = new RectangleF(destPoint.X + newWidth + rubyOffsetX, destPoint.Y + rubyOffsetY, rubyNewWidth, rubyNewHeight); gr.DrawImage(srcImage, Rectangle.Round(rubyDestRect), columnRuby.X, rubyEntity.Y, columnRuby.Width, rubyEntity.Height, GraphicsUnit.Pixel, imgAttr); if (columnRuby.Entitys != null && rubyIdx < columnRuby.Entitys.Count) rubyEntity = columnRuby.Entitys[rubyIdx++]; diff --git a/NovelTool/Main.cs b/NovelTool/Main.cs index 6d35865..04bb306 100644 --- a/NovelTool/Main.cs +++ b/NovelTool/Main.cs @@ -1,4 +1,5 @@ using SharpCompress.Archives; +using SharpCompress.Archives.Zip; using SharpCompress.Common; using SharpCompress.Readers; using System; @@ -9,6 +10,7 @@ using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.IO; +using System.IO.Compression; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -221,13 +223,25 @@ private void ToolStripOpen_Click(object sender, EventArgs e) { fileDirName = fileDirName + Path.DirectorySeparatorChar + fileName; Directory.CreateDirectory(fileDirName); - IArchive archive = ArchiveFactory.Open(openFileDialog.FileName); - IReader reader = archive.ExtractAllEntries(); - while (reader.MoveToNextEntry()) + using (IArchive archive = ArchiveFactory.Open(openFileDialog.FileName)) + using (IReader reader = archive.ExtractAllEntries()) { - if (!reader.Entry.IsDirectory) - reader.WriteEntryToDirectory(fileDirName, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true }); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + reader.WriteEntryToDirectory(fileDirName, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true, PreserveFileTime = true }); + } } + //using (FileStream zipToOpen = new FileStream(openFileDialog.FileName, FileMode.Open)) + //using (System.IO.Compression.ZipArchive archive = new System.IO.Compression.ZipArchive(zipToOpen)) + //{ + // foreach (System.IO.Compression.ZipArchiveEntry entry in archive.Entries) + // { + // Stream s = entry.Open(); + // var sr = new StreamReader(s); + // var myStr = sr.ReadToEnd(); + // } + //} } #endregion #region Parse Epub @@ -235,36 +249,38 @@ private void ToolStripOpen_Click(object sender, EventArgs e) { string fullPath = ""; string rootPath = ""; - XmlTextReader reader = new XmlTextReader($"{fileDirName}/META-INF/container.xml"); - XmlTextReader readerOpt = null; - while (reader.Read()) - { - if (reader.Name != "rootfile") continue; - - fullPath = reader.GetAttribute("full-path"); - rootPath = Path.GetDirectoryName($"{fileDirName}/{fullPath}"); - readerOpt = new XmlTextReader($"{fileDirName}/{fullPath}"); - break; - } string title = ""; string publisher = ""; List creators = new List(); List itemrefs = new List(); - //Dictionary images = new Dictionary(); Dictionary xhtmls = new Dictionary(); - while (readerOpt.Read()) + //Dictionary images = new Dictionary(); + using (XmlTextReader reader = new XmlTextReader($"{fileDirName}/META-INF/container.xml")) { - if (readerOpt.NodeType != XmlNodeType.Element) continue; + XmlTextReader readerOpt = null; + while (reader.Read()) + { + if (reader.Name != "rootfile") continue; - if (readerOpt.LocalName == "title") title = readerOpt.ReadString(); - else if (readerOpt.LocalName == "creator") creators.Add(readerOpt.ReadString()); - else if (readerOpt.LocalName == "publisher") publisher = readerOpt.ReadString(); - else if (readerOpt.LocalName == "item") + fullPath = reader.GetAttribute("full-path"); + rootPath = Path.GetDirectoryName($"{fileDirName}/{fullPath}"); + readerOpt = new XmlTextReader($"{fileDirName}/{fullPath}"); + break; + } + while (readerOpt.Read()) { - //if (readerOpt.GetAttribute("media-type").StartsWith("image")) images.Add(readerOpt.GetAttribute("id"), readerOpt.GetAttribute("href")); - if (readerOpt.GetAttribute("media-type") == "application/xhtml+xml") xhtmls.Add(readerOpt.GetAttribute("id"), readerOpt.GetAttribute("href")); + if (readerOpt.NodeType != XmlNodeType.Element) continue; + + if (readerOpt.LocalName == "title") title = readerOpt.ReadString(); + else if (readerOpt.LocalName == "creator") creators.Add(readerOpt.ReadString()); + else if (readerOpt.LocalName == "publisher") publisher = readerOpt.ReadString(); + else if (readerOpt.LocalName == "item") + { + //if (readerOpt.GetAttribute("media-type").StartsWith("image")) images.Add(readerOpt.GetAttribute("id"), readerOpt.GetAttribute("href")); + if (readerOpt.GetAttribute("media-type") == "application/xhtml+xml") xhtmls.Add(readerOpt.GetAttribute("id"), readerOpt.GetAttribute("href")); + } + else if (readerOpt.LocalName == "itemref") itemrefs.Add(readerOpt.GetAttribute("idref")); } - else if (readerOpt.LocalName == "itemref") itemrefs.Add(readerOpt.GetAttribute("idref")); } FileListView.BeginUpdate(); FileListView.Items.Clear(); diff --git a/NovelTool/NovelTool.csproj b/NovelTool/NovelTool.csproj index 36be788..f28b9d1 100644 --- a/NovelTool/NovelTool.csproj +++ b/NovelTool/NovelTool.csproj @@ -46,13 +46,11 @@ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll + ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll - - ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll - ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll @@ -83,7 +81,6 @@ Option.cs - Form @@ -93,6 +90,11 @@ + + True + True + Settings.settings + GenerateView.cs Designer @@ -117,11 +119,6 @@ True Resources.resx - - True - Settings.settings - True - diff --git a/NovelTool/Option.cs b/NovelTool/Option.cs index de1fdbc..809cd04 100644 --- a/NovelTool/Option.cs +++ b/NovelTool/Option.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; +using System.Windows.Forms; namespace NovelTool { diff --git a/NovelTool/Properties/AssemblyInfo.cs b/NovelTool/Properties/AssemblyInfo.cs index ffd575d..ee7bfa4 100644 --- a/NovelTool/Properties/AssemblyInfo.cs +++ b/NovelTool/Properties/AssemblyInfo.cs @@ -32,5 +32,5 @@ // 您可以指定所有的值,也可以使用 '*' 將組建和修訂編號 // 設為預設,如下所示: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.1.0.0")] -[assembly: AssemblyFileVersion("1.1.0.0")] +[assembly: AssemblyVersion("1.1.1.0")] +[assembly: AssemblyFileVersion("1.1.1.0")] diff --git a/NovelTool/Properties/Settings.Designer.cs b/NovelTool/Properties/Settings.Designer.cs index fec325f..a2fa5b7 100644 --- a/NovelTool/Properties/Settings.Designer.cs +++ b/NovelTool/Properties/Settings.Designer.cs @@ -653,5 +653,84 @@ public static Settings Default { this["FooterPositionType"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("30|4_EpubAozora|TextFont|Determine the font size of Epub or Aozora eBooks display" + + "ed in GenerateView (Default 30)")] + public global::OptionTreeView.Option TextFontSize { + get { + return ((global::OptionTreeView.Option)(this["TextFontSize"])); + } + set { + this["TextFontSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("[FontFamily: Name=Microsoft Sans Serif]|4_EpubAozora|TextFont|Determine the font " + + "of Epub or Aozora eBooks displayed in GenerateView (Default \"[FontFamily: Name=M" + + "icrosoft Sans Serif]\")")] + public global::OptionTreeView.Option TextFontFamily { + get { + return ((global::OptionTreeView.Option)(this["TextFontFamily"])); + } + set { + this["TextFontFamily"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("true|4_EpubAozora|TextFont|Determines whether the font style of Epub or Aozora eB" + + "ooks in GenerateView is bold (Default true)")] + public global::OptionTreeView.Option TextFontBold { + get { + return ((global::OptionTreeView.Option)(this["TextFontBold"])); + } + set { + this["TextFontBold"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("false|4_EpubAozora|TextFont|Determines whether the font style of Epub or Aozora e" + + "Books in GenerateView is italic (Default false)")] + public global::OptionTreeView.Option TextFontItalic { + get { + return ((global::OptionTreeView.Option)(this["TextFontItalic"])); + } + set { + this["TextFontItalic"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("200%|4_EpubAozora|WebViewStyle|Determine the line-height style of Epub or Aozora " + + "eBooks in GenerateView\'s WebView (Default 200%)")] + public global::OptionTreeView.Option WebViewLineHeight { + get { + return ((global::OptionTreeView.Option)(this["WebViewLineHeight"])); + } + set { + this["WebViewLineHeight"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("140%|4_EpubAozora|WebViewStyle|Determine the font-size style of Epub or Aozora eB" + + "ooks in GenerateView\'s WebView (Default 140%)")] + public global::OptionTreeView.Option WebViewFontSize { + get { + return ((global::OptionTreeView.Option)(this["WebViewFontSize"])); + } + set { + this["WebViewFontSize"] = value; + } + } } } diff --git a/NovelTool/Properties/Settings.settings b/NovelTool/Properties/Settings.settings index 4716be5..5602c72 100644 --- a/NovelTool/Properties/Settings.settings +++ b/NovelTool/Properties/Settings.settings @@ -149,5 +149,23 @@ None|3_Generate|3_Footer|Determine the footer position of the output image (Default None) + + 30|4_EpubAozora|TextFont|Determine the font size of Epub or Aozora eBooks displayed in GenerateView (Default 30) + + + [FontFamily: Name=Microsoft Sans Serif]|4_EpubAozora|TextFont|Determine the font of Epub or Aozora eBooks displayed in GenerateView (Default "[FontFamily: Name=Microsoft Sans Serif]") + + + true|4_EpubAozora|TextFont|Determines whether the font style of Epub or Aozora eBooks in GenerateView is bold (Default true) + + + false|4_EpubAozora|TextFont|Determines whether the font style of Epub or Aozora eBooks in GenerateView is italic (Default false) + + + 200%|4_EpubAozora|WebViewStyle|Determine the line-height style of Epub or Aozora eBooks in GenerateView's WebView (Default 200%) + + + 140%|4_EpubAozora|WebViewStyle|Determine the font-size style of Epub or Aozora eBooks in GenerateView's WebView (Default 140%) + \ No newline at end of file diff --git a/NovelTool/app.config b/NovelTool/app.config index a8ed5e1..cf8cb4b 100644 --- a/NovelTool/app.config +++ b/NovelTool/app.config @@ -13,6 +13,14 @@ + + + + + + + + diff --git a/NovelTool/lib/OptionTreeView.dll b/NovelTool/lib/OptionTreeView.dll index b9c6b24f921356ccea23e977b666ee9d6fe61000..b5c16ecef3e592374bd6547bc7edff39021a011d 100644 GIT binary patch literal 27136 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 literal 25600 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 F{u@j^(uDv3 diff --git a/README.md b/README.md index eee8575..ffaa543 100644 --- a/README.md +++ b/README.md @@ -136,4 +136,17 @@ Novel eBook images or scanned image files. 1. Head & Footer * `PositionType`: Determine the header/footer position of the output image (Default None)(None, TopLeft, TopRight, BottomLeft, BottomRight). - + + +### EpubAozora + +1. TextFont + * `TextFontSize`: Determine the font size of Epub or Aozora eBooks displayed in GenerateView (Default 30). + * `TextFontName`: Determine the font of Epub or Aozora eBooks displayed in GenerateView (Default "[FontFamily: Name=Microsoft Sans Serif]"). + * `TextFontBold`: Determines whether the font style of Epub or Aozora eBooks in GenerateView is bold (Default true). + * `TextFontItalic`: Determines whether the font style of Epub or Aozora eBooks in GenerateView is italic (Default false). + +1. WebViewStyle + * `WebViewLineHeight`: Determine the line-height style of Epub or Aozora eBooks in GenerateView's WebView (Default 200%). + * `WebViewFontSize`: Determine the font-size style of Epub or Aozora eBooks in GenerateView's WebView (Default 140%). +