diff --git a/TBO/ApplicationLibrary.cs b/TBO/ApplicationLibrary.cs index 7528ded..326e8fc 100644 --- a/TBO/ApplicationLibrary.cs +++ b/TBO/ApplicationLibrary.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Drawing; +using System.Drawing; using System.IO; using TBO.i18n; using TBO.UI; @@ -15,17 +14,15 @@ private Button btClose = new Button("btClose") { Image = Properties.Resources.x, Top = 5, Visible = Shell.FullScreen }; private Button btOpen = new Button("btOpen") { Image = Properties.Resources.file_directory, Top = 5, Left = 5 }; private Button btStudio = new Button("btStudio") { Image = Properties.Resources.pencil, Left = 5 }; - private Panel pLib = new Panel("pLib") { Width = 500, Scrollable = true }; - - private List lib = new List(); + private Panel pLib = new Panel("pLib") { Width = 500, Scrollable = true, Top = 5 }; public ApplicationLibrary() { + Add(pLib); Add(btFullscreen); Add(btClose); Add(btOpen); Add(btStudio); - Add(pLib); btFullscreen.DoClick = btFullscreenClick; btClose.DoClick = btCloseClick; @@ -33,6 +30,8 @@ btStudio.DoClick = btStudioClick; btStudio.Top = btOpen.Height + 10; + + PopulateList(); } public override void ResizeTo(Size size) @@ -44,7 +43,7 @@ } else btFullscreen.Left = size.Width - (btFullscreen.Width + 5); - pLib.Height = size.Height; + pLib.Height = size.Height - 10; pLib.Left = (size.Width - pLib.Width) / 2; } @@ -53,8 +52,9 @@ if (File.Exists(cmd)) { using (TBOFile tbo = new TBOFile(cmd)) - lib.Add(new LibraryTBO(tbo)); - Sort(); + Library.Add(tbo); + Library.Sort(); + Library.Save(); PopulateList(); } } @@ -64,19 +64,19 @@ btClose.Visible = Shell.FullScreen; } - private void Sort() - { - lib.Sort((a, b) => a.Title.CompareTo(b.Title)); - } - private void PopulateList() { pLib.RemoveAll(); int idx = 0; - foreach (LibraryTBO ltbo in lib) + foreach (LibraryTBO ltbo in Library.Tebeos) { - Item i = new Item("tbo_" + idx++) { Image = ltbo.Image, Text = ltbo.Title }; + string info = ltbo.Author; + if (Library.ValidValue(ltbo.Publisher)) + info = info + " (" + ltbo.Publisher + ")"; + Item i = new Item("tbo_" + idx++) { Image = ltbo.Image, Text = ltbo.DisplayName, Info = info, Count = ltbo.Year == 0 ? null : ltbo.Year.ToString(), Width = pLib.Width }; pLib.Add(i); + i.Tag = ltbo.FilePath; + i.DoClick = itTBOClick; } pLib.Invalidate(); } @@ -106,6 +106,12 @@ UIManager.Manager.OpenInsideStudio(); } + private void itTBOClick(Control c, Event e) + { + string path = Path.Combine(Library.BasePath, (string)c.Tag); + Shell.GoTo(ApplicationReader.ApplicationId, path); + } + public override string Id => ApplicationId; public override string Title => I18n.Lang.Library; } diff --git a/TBO/ApplicationReader.cs b/TBO/ApplicationReader.cs index 13125e6..3dbec9e 100644 --- a/TBO/ApplicationReader.cs +++ b/TBO/ApplicationReader.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Drawing; +using System.Drawing; using System.IO; -using System.Linq; -using System.Text; using TBO.i18n; using TBO.UI; using TBO.UI.tboTK; @@ -119,6 +115,11 @@ SetPage(tbo.CurrentPage); Shell.Invalidate(); } + else + { + UIManager.Manager.ShowError(I18n.Lang.Error_opening_tbo); + Shell.GoTo(ApplicationLibrary.ApplicationId); + } } public override void Shown() diff --git a/TBO/ImageWorks.cs b/TBO/ImageWorks.cs index b366374..be5e6ec 100644 --- a/TBO/ImageWorks.cs +++ b/TBO/ImageWorks.cs @@ -1,18 +1,26 @@ using System; using System.Drawing; using System.Drawing.Imaging; +using System.IO; namespace TBO { static class ImageWorks { - public static Bitmap To8bppGraysacle(Image i) + private static ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg); + + #region Tools + + public static ImageCodecInfo GetEncoder(ImageFormat format) { - Bitmap bmp = new Bitmap(i.Width, i.Height, PixelFormat.Format8bppIndexed); - ColorPalette pal = bmp.Palette; - for (int p = 0; p <= 255; p++) - pal.Entries[p] = Color.FromArgb(p, p, p); - bmp.Palette = pal; + ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); + foreach (ImageCodecInfo codec in codecs) + { + if (codec.FormatID == format.Guid) + { + return codec; + } + } return null; } @@ -32,6 +40,20 @@ return true; } + #endregion + + #region Conversion + + public static Bitmap To8bppGraysacle(Image i) + { + Bitmap bmp = new Bitmap(i.Width, i.Height, PixelFormat.Format8bppIndexed); + ColorPalette pal = bmp.Palette; + for (int p = 0; p <= 255; p++) + pal.Entries[p] = Color.FromArgb(p, p, p); + bmp.Palette = pal; + return null; + } + public static Bitmap ToBpp(Image i, PixelFormat toBPP) { Bitmap bmpto; @@ -121,6 +143,40 @@ return bmpto; } + #endregion + + #region I/O + + public static byte[] ImageJPEG(Image i, int quality) + { + EncoderParameters eParams = new EncoderParameters(1); + eParams.Param[0] = new EncoderParameter(Encoder.Quality, quality); + if (i == null) + return null; + MemoryStream ms = new MemoryStream(); + i.Save(ms, jpgEncoder, eParams); + return ms.ToArray(); + } + + public static byte[] ImagePNG(Image i) + { + if (i == null) + return null; + MemoryStream ms = new MemoryStream(); + i.Save(ms, ImageFormat.Png); + return ms.ToArray(); + } + + public static byte[] ImageGIF(Image i) + { + if (i == null) + return null; + MemoryStream ms = new MemoryStream(); + i.Save(ms, ImageFormat.Gif); + return ms.ToArray(); + } + + #endregion } } diff --git a/TBO/Library.cs b/TBO/Library.cs new file mode 100644 index 0000000..5d455c1 --- /dev/null +++ b/TBO/Library.cs @@ -0,0 +1,134 @@ +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using TBO.i18n; +using TBO.UI; +using XWolf.IO; + +namespace TBO +{ + static class Library + { + public const string LIB_FOLDER = "Library"; + public const string LIB_FILE = "Library.db"; + public const string LIB_UNKNOWN = "Unknown"; + private static List lib = new List(); + private static string baseDir; + private static bool readOnly; + + static Library() + { + baseDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), LIB_FOLDER); + try + { + Directory.CreateDirectory(baseDir); + } + catch { readOnly = true; } + Load(); + } + + public static bool ValidValue(string s) + { + if (s != null) + { + s = s.Trim(); + if (s.Length > 0) + return true; + } + return false; + } + + private static string Nvl(string s, string def = LIB_UNKNOWN) + { + return ValidValue(s) ? s : def; + } + + private static string MkPath(string s) + { + s = s.Trim(); + s = s.Replace("/", ""); + s = s.Replace("\\", ""); + s = s.Replace("?", ""); + s = s.Replace("*", ""); + s = s.Replace(":", ""); + s = s.Replace("\"", ""); + s = s.Replace("<", ""); + s = s.Replace(">", ""); + s = s.Replace("|", ""); + return s; + } + + private static bool IncludeInLibrary(LibraryTBO tbo) + { + if (readOnly) + return false; + string path = baseDir; + path = Path.Combine(path, MkPath(Nvl(tbo.Author))); + path = Path.Combine(path, MkPath(Nvl(tbo.Publisher))); + path = Path.Combine(path, MkPath(Nvl(tbo.Year.ToString()))); + try + { + Directory.CreateDirectory(path); + path = Path.Combine(path, tbo.DisplayName); + tbo.CopyTo(path); + return true; + } + catch { return false; }; + } + + #region I/O + + public static void Save() + { + string lpath = Path.Combine(baseDir, LIB_FILE); + try + { + using (FileStream fs = new FileStream(lpath, FileMode.OpenOrCreate, FileAccess.Write)) + { + fs.Position = 0; + fs.SetLength(0); + fs.WriteInt32(lib.Count); + foreach (LibraryTBO tbo in lib) + tbo.WriteTo(fs); + } + } + catch { } + } + + private static void Load() + { + string lpath = Path.Combine(baseDir, LIB_FILE); + try + { + using (FileStream fs = new FileStream(lpath, FileMode.Open, FileAccess.Read)) + { + lib.Clear(); + fs.Position = 0; + int cnt = fs.ReadInt32(); + for (int i = 0; i < cnt; i++) + lib.Add(new LibraryTBO(fs)); + } + } + catch { } + } + + #endregion + + public static void Add(TBOFile tbof) + { + LibraryTBO tbo = new LibraryTBO(tbof); + if (IncludeInLibrary(tbo)) + lib.Add(tbo); + else + UIManager.Manager.ShowError(I18n.Lang.Error_cant_add); + } + + public static void Sort() + { + lib.Sort((a, b) => a.Title.CompareTo(b.Title)); + } + + public static LibraryTBO[] Tebeos => lib.ToArray(); + public static string BasePath => baseDir; + } +} diff --git a/TBO/LibraryTBO.cs b/TBO/LibraryTBO.cs index 2e874d0..059dc32 100644 --- a/TBO/LibraryTBO.cs +++ b/TBO/LibraryTBO.cs @@ -1,36 +1,54 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; +using System.Drawing; +using System.IO; using TBO.UI.tboTK; +using XWolf.IO; namespace TBO { class LibraryTBO { - private string title; - private Image image; private string path; public LibraryTBO(TBOFile tbo) { - title = tbo.Title; - GenThumb(tbo); + Title = tbo.Title; + Variant = tbo.Variant; + Volume = tbo.Volume; + Author = tbo.Author; + Publisher = tbo.Publisher; + Year = tbo.Year; + Comments = tbo.Comments; + Image = GenThumb(tbo); path = tbo.FileName; } - private void GenThumb(TBOFile tbo) + public LibraryTBO(FileStream fs) { - using (Image page = tbo.GetImage(0)) { + path = fs.ReadString(); + Title = fs.ReadString(); + Variant = fs.ReadString(); + Volume = fs.ReadString(); + Author = fs.ReadString(); + Publisher = fs.ReadString(); + Year = fs.ReadInt32(); + Comments = fs.ReadString(); + Image = Image.FromStream(new MemoryStream(fs.ReadBlock())); + } + + private Image GenThumb(TBOFile tbo) + { + Image image; + using (Image page = tbo.GetImage(0)) + { if (page == null) - return; + return null; image = new Bitmap(256, 256); using (Graphics g = Graphics.FromImage(image)) { g.DrawImageKeepRatioEx(page, 0, 0, image.Width, image.Height); } } + return image; } public TBOFile Open() @@ -38,7 +56,56 @@ return new TBOFile(path); } - public string Title => title; - public Image Image => image; + #region I/O + + public void CopyTo(string newPath) + { + File.Copy(path, newPath); + path = newPath; + } + + public void WriteTo(FileStream fs) + { + string p = path; + if (p.StartsWith(Library.BasePath)) + p = p.Substring(Library.BasePath.Length + 1); + fs.WriteString(p); + fs.WriteString(Title); + fs.WriteString(Variant); + fs.WriteString(Volume); + fs.WriteString(Author); + fs.WriteString(Publisher); + fs.WriteInt32(Year); + fs.WriteString(Comments); + fs.WriteBlock(ImageWorks.ImagePNG(Image)); + } + + #endregion + + private string GetDisplayName() + { + if (Library.ValidValue(Title)) + { + string dname = Title; + if (Library.ValidValue(Variant)) + dname = dname + " (" + Variant.Trim() + ")"; + if (Library.ValidValue(Volume)) + dname = dname + " Vol." + Volume.Trim(); + return dname; + } + else return FileName; + } + + public string Title { get; } + public string Variant { get; } + public string Volume { get; } + public string Author { get; } + public string Publisher { get; } + public int Year { get; } + public string Comments { get; } + public Image Image { get; } + public string FileName => Path.GetFileNameWithoutExtension(path); + public string DisplayName => GetDisplayName(); + public string FilePath => path; } } diff --git a/TBO/TBO.csproj b/TBO/TBO.csproj index a8702fe..f1cdc9b 100644 --- a/TBO/TBO.csproj +++ b/TBO/TBO.csproj @@ -57,6 +57,7 @@ + diff --git a/TBO/TBOFile.cs b/TBO/TBOFile.cs index 2540c12..9d99cdd 100644 --- a/TBO/TBOFile.cs +++ b/TBO/TBOFile.cs @@ -16,9 +16,7 @@ private const int EOF = 0x1A; private const int FILEVERSION = 0; private const uint ENDIANMARK = 0xFEEDFACE; - - private static ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg); - private static EncoderParameters eParams = new EncoderParameters(1); + private const int JPEG_QUALITY = 60; private FileStream fs; private long tboStart; @@ -28,11 +26,6 @@ private bool sameEndian; private List pagepos = new List(); - static TBOFile() - { - eParams.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 60L); - } - public TBOFile(string filePath) { try @@ -135,7 +128,7 @@ private void WriteImage(Image i) { - fs.WriteBlock(ImageJPEG(i)); + fs.WriteBlock(ImageWorks.ImageJPEG(i, JPEG_QUALITY)); } private void Commit() @@ -157,22 +150,9 @@ #region Image Processing - private static ImageCodecInfo GetEncoder(ImageFormat format) - { - ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); - foreach (ImageCodecInfo codec in codecs) - { - if (codec.FormatID == format.Guid) - { - return codec; - } - } - return null; - } - private byte[] GetImageBytes(Image i, int grayscale, bool keepColors) { - byte[] img = ImageJPEG(i); + byte[] img = ImageWorks.ImageJPEG(i, JPEG_QUALITY); if (grayscale == 0) return img; if (keepColors && !ImageWorks.IsGray(i)) @@ -204,39 +184,12 @@ return gimg.Length < img.Length ? gimg : img; } - private byte[] ImageJPEG(Image i) - { - if (i == null) - return null; - MemoryStream ms = new MemoryStream(); - i.Save(ms, jpgEncoder, eParams); - return ms.ToArray(); - } - - private byte[] ImagePNG(Image i) - { - if (i == null) - return null; - MemoryStream ms = new MemoryStream(); - i.Save(ms, ImageFormat.Png); - return ms.ToArray(); - } - - private byte[] ImageGIF(Image i) - { - if (i == null) - return null; - MemoryStream ms = new MemoryStream(); - i.Save(ms, ImageFormat.Gif); - return ms.ToArray(); - } - private byte[] ImagePNG8bpp(Image i) { if (i == null) return null; using (Bitmap bmp = ImageWorks.ToBppGray(i, PixelFormat.Format8bppIndexed)) - return ImagePNG(bmp); + return ImageWorks.ImagePNG(bmp); } private byte[] ImagePNG4bpp(Image i) @@ -244,7 +197,7 @@ if (i == null) return null; using (Bitmap bmp = ImageWorks.ToBppGray(i, PixelFormat.Format4bppIndexed)) - return ImagePNG(bmp); + return ImageWorks.ImagePNG(bmp); } private byte[] ImagePNG4bpp(Image i, int[] palette) @@ -252,7 +205,7 @@ if (i == null) return null; using (Bitmap bmp = ImageWorks.ToBppGray(i, PixelFormat.Format4bppIndexed, palette)) - return ImagePNG(bmp); + return ImageWorks.ImagePNG(bmp); } private byte[] ImagePNG1bpp(Image i) @@ -260,7 +213,7 @@ if (i == null) return null; using (Bitmap bmp = ImageWorks.ToBpp(i, PixelFormat.Format1bppIndexed)) - return ImagePNG(bmp); + return ImageWorks.ImagePNG(bmp); } #endregion diff --git a/TBO/UI/Shell.cs b/TBO/UI/Shell.cs index d8013ba..f80dc2f 100644 --- a/TBO/UI/Shell.cs +++ b/TBO/UI/Shell.cs @@ -81,12 +81,12 @@ public static void Invalidate() { - DoInvalidate(); + DoInvalidate?.Invoke(); } public static void Invalidate(Rectangle r) { - DoInvalidateRegion(Zoom(r)); + DoInvalidateRegion?.Invoke(Zoom(r)); } #endregion diff --git a/TBO/UI/UIManager.cs b/TBO/UI/UIManager.cs index d2ba34d..d312714 100644 --- a/TBO/UI/UIManager.cs +++ b/TBO/UI/UIManager.cs @@ -26,6 +26,7 @@ public abstract void ShowAbout(); public abstract string OpenTBODialog(); public abstract void OpenInsideStudio(); + public abstract void ShowError(string text); public static UIManager Manager => manager; } diff --git a/TBO/UI/Windows/UIManagerWindows.cs b/TBO/UI/Windows/UIManagerWindows.cs index 7aabc11..36705cf 100644 --- a/TBO/UI/Windows/UIManagerWindows.cs +++ b/TBO/UI/Windows/UIManagerWindows.cs @@ -49,5 +49,10 @@ using (About a = new About()) a.ShowDialog(); } + + public override void ShowError(string text) + { + MessageBox.Show(text, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } } } diff --git a/TBO/UI/tboTK/Item.cs b/TBO/UI/tboTK/Item.cs index 51f8798..7b4b489 100644 --- a/TBO/UI/tboTK/Item.cs +++ b/TBO/UI/tboTK/Item.cs @@ -1,25 +1,42 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; +using System.Drawing; +using System.Drawing.Text; namespace TBO.UI.tboTK { class Item : Button { - private Font fnt = new Font(FontFamily.GenericSansSerif, 10); + private Font fnt = new Font(FontFamily.GenericSansSerif, 11); private Brush fg = new SolidBrush(Color.Black); + private Brush fgInfo = new SolidBrush(Color.Gray); + private Brush bg = new SolidBrush(Color.FromArgb(200, 255, 255, 255)); public Item(string id) : base(id) { } public override void Paint(Graphics g, Rectangle clip) { + g.Clip = new Region(Bounds); + g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; + g.FillRectangle(bg, Bounds); if (Image != null) g.DrawImageKeepRatioEx(Image, 0, 0, Height, Height); - g.DrawString(Text, fnt, fg, Height + 5, (Height / 2) - 5); + SizeF stitle = g.MeasureString(Text, fnt); + if (string.IsNullOrEmpty(Info)) + g.DrawString(Text, fnt, fg, Height + 5, ((Height - stitle.Height) / 2) - 1); + else + { + g.DrawString(Text, fnt, fg, Height + 5, ((Height - stitle.Height) / 2) - 10); + g.DrawString(Info, fnt, fgInfo, Height + 15, ((Height - stitle.Height) / 2) + 10); + } + if (!string.IsNullOrEmpty(Count)) + { + SizeF scount = g.MeasureString(Count, fnt); + g.DrawString(Count, fnt, fgInfo, (Left+Width-scount.Width)-5, ((Height - stitle.Height) / 2) + 10); + + } } public string Text { get; set; } + public string Info { get; set; } + public string Count { get; set; } } } diff --git a/TBO/UI/tboTK/Panel.cs b/TBO/UI/tboTK/Panel.cs index 4a4595e..a6139ee 100644 --- a/TBO/UI/tboTK/Panel.cs +++ b/TBO/UI/tboTK/Panel.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Drawing; +using System.Drawing.Drawing2D; namespace TBO.UI.tboTK { @@ -78,11 +79,13 @@ public override void Paint(Graphics g, Rectangle clip) { //g.FillRectangle(new SolidBrush(Color.Wheat), Left, Top, Width, Height); - // g.SetClip(new Rectangle(Left, Top, Width, Height)); + // g.SetClip(new Rectangle(Left, Top, Width, Height)); + GraphicsState gs = g.Save(); g.TranslateTransform(Left - scrollOffset.X, Top - scrollOffset.Y); foreach (Control c in controls.Values) if (c.Clips(clip)) c.Paint(g, clip); + g.Restore(gs); } private void SetScrollOffset(Point o) diff --git a/TBO/i18n/English.cs b/TBO/i18n/English.cs index b852265..7466371 100644 --- a/TBO/i18n/English.cs +++ b/TBO/i18n/English.cs @@ -9,5 +9,7 @@ { public override string Library => "Library"; public override string Reader => "Reader"; + public override string Error_cant_add => "Tebeo can't be added to library"; + public override string Error_opening_tbo => "Error opening tebeo"; } } diff --git a/TBO/i18n/Spanish.cs b/TBO/i18n/Spanish.cs index b37655a..846f47c 100644 --- a/TBO/i18n/Spanish.cs +++ b/TBO/i18n/Spanish.cs @@ -9,5 +9,7 @@ { public override string Library => "Biblioteca"; public override string Reader => "Lector"; + public override string Error_cant_add => "No se pudo añadir el tebeo a la biblioteca"; + public override string Error_opening_tbo => "Error al abrir el tebeo"; } } diff --git a/TBO/i18n/i18n.cs b/TBO/i18n/i18n.cs index 4e9ad1c..ef4a72f 100644 --- a/TBO/i18n/i18n.cs +++ b/TBO/i18n/i18n.cs @@ -27,5 +27,7 @@ public static I18n Lang => i18n; public abstract string Library { get; } public abstract string Reader { get; } + public abstract string Error_cant_add { get; } + public abstract string Error_opening_tbo { get; } } }