zoukankan      html  css  js  c++  java
  • CloudNotes

    CloudNotes

    今天,我发布了CloudNotes的一个更新版本:1.0.5484.36793。这个版本与1.0.5472.20097不同的是,它拥有增强的笔记列表,与之前单调的列表系统相比,新的笔记列表不仅可以显示笔记的摘要内容,而且还可以从笔记中抽取第一张图片,并显示图片的详细信息:

    image

    怎么样?相比之前的笔记列表,现在的设计是不是能够展示更丰富的信息呢?

    升级到最新版本

    如果在读完我的第一篇关于CloudNotes的文章,《CloudNotes:一个云端个人笔记系统》之后,已经安装并体验了上一个版本的CloudNotes,那么,当你重新打开CloudNotes桌面客户端时,你将在登录界面,或者主界面的状态栏部分看到发现新版本更新的通知信息:

    image

    image

    你可以点击这个信息来进入新版本更新系统。然而不幸的是,更新系统会告诉你,更新失败,原因是因为你打开了Windows 7的用户帐户控制(UAC)的功能,更新程序不具备访问C:Program Files (x86)目录的权限。解决方案有如下两种:

    1. 进入控制面板,关闭用户帐户控制(UAC)功能
    2. 点击这里】下载CloudNotes更新程序的补丁包,下载以后,将zip文件解压并覆盖CloudNotes安装目录下的Updater目录中(比如:C:Program Files (x86)daxnetCloudNotes Desktop Client)的所有文件,然后重新通过CloudNotes桌面客户端进入升级程序,即可完成升级

    如果你是第一次看到有CloudNotes这么个玩意儿,并且打算尝试使用的话,请直接【点击这里】下载版本1.0.5484.36793,它是截止到本文撰写时的最新版本,包含了这个最新的日志列表和修复的CloudNotes更新程序。

    技术实现

    在此大致介绍一下我是如何实现这种全新的笔记列表界面的,并简要介绍一下如何让应用程序在UAC下具有访问文件系统资源的权限。

    增强的笔记列表

    说起来也有趣,有一天我看到有个同事在用Evernote,觉得它的笔记列表视图做得挺不错,还有缩略图:

    image

    给人的感觉就是能够在简单的视图中体现更多的笔记信息,让人更容易地找到需要查看的笔记内容。于是我也在想,我的CloudNotes桌面客户端是否也可以实现类似的效果。

    经过一番研究之后,我决定对目前笔记列表所使用的树形控件进行自定义:从System.Windows.Forms.TreeView类继承一个自定义的TreeViewEx类型,并使用OwnerDrawText的自定义绘画方式,对每个树状节点(TreeNode)进行重绘,以达到类似的效果。

    在TreeNode进行重绘时(就是在OnDrawNode事件处理过程中),TreeViewEx会根据当前节点上的TreeNodeExItem数据,对树状节点进行重绘,从而达到上面截图中展示的效果。实现起来其实并不困难,就是需要有耐心,文字的颜色、定位、图片的尺寸等等,都需要花时间慢慢调整。这部分代码我也不多做解释了,朋友们请自行参考CloudNotes.DesktopClient项目下ControlsTreeViewEx.cs源代码文件中的实现即可。相比之下,更为有趣技术点主要有:

    从HTML中获得纯文本信息

    这就是用于显示笔记的摘要文字部分。由于笔记是HTML格式存储的,而摘要部分却仅需要笔记文字的开头一段即可,因此,就需要从HTML中去掉HTML的标记,从中提取可读的纯文本信息。在CloudNotes中,我是使用下面的扩展方法来实现这个功能的。该方法同时被WebAPI和桌面客户端使用。通过代码可以看到,我仅仅将笔记中的前100个文字作为笔记的摘要信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    /// <summary>
    /// Extract the description from the html.
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    public static string ExtractDescription(this string html)
    {
        var plainText = html.RemoveHtmlTags();
        return plainText.Substring(0, plainText.Length < 100 ? plainText.Length : 100);
    }
     
    /// <summary>
    /// Removes all the HTML tags and bad characters from the given HTML string.
    /// </summary>
    /// <param name="html">The source HTML string.</param>
    /// <returns></returns>
    private static string RemoveHtmlTags(this string html)
    {
        html = HttpUtility.UrlDecode(html);
        html = HttpUtility.HtmlDecode(html);
     
        html = RemoveTag(html, "<!--", "-->");
        html = RemoveTag(html, "<script", "</script>");
        html = RemoveTag(html, "<style", "</style>");
     
        //replace matches of these regexes with space
        html = Tags.Replace(html, " ");
        html = NotOkCharacter.Replace(html, " ");
        html = SingleSpacedTrim(html);
     
        return html;
    }

    提取笔记中的第一张图片

    为了显示笔记图片的缩略图,首先需要提取笔记中的第一张图片,然后再通过图像处理函数产生缩略图。话不多说,直接上代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    /// <summary>
    /// The regular expression for extracting the Src value from an HTML Img tag.
    /// </summary>
    public const string ImgSrcFormatPattern = @"<img[^>]*?srcs*=s*[""']?([^'"" >]+?)[ '""][^>]*?>";
     
    /// <summary>
    /// Extract the thumbnail image from the html.
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    public static string ExtractThumbnailImageBase64(this string html)
    {
        var imageBase64List = html.GetImgSrcBase64FromHtml();
        string result = null;
        if (imageBase64List != null && imageBase64List.Any())
        {
            result = imageBase64List.First();
        }
        return result;
    }
     
    /// <summary>
    ///
    /// </summary>
    /// <param name="html"></param>
    /// <returns></returns>
    private static IEnumerable<string> GetImgSrcBase64FromHtml(this string html)
    {
        var matchesImgSrc = Regex.Matches(html, Constants.ImgSrcFormatPattern,
            RegexOptions.IgnoreCase | RegexOptions.Singleline);
        if (matchesImgSrc.Count == 0)
            return null;
        List<string> result = new List<string>();
        foreach (Match m in matchesImgSrc)
        {
            var href = m.Groups[1].Value;
            var pos = href.IndexOf("base64,", StringComparison.InvariantCultureIgnoreCase);
            pos += 7;
            result.Add(href.Substring(pos, href.Length - pos).Trim());
        }
        return result;
    }

    缩略图的产生

    缩略图的产生代码是在TreeViewEx控件中实现的,基本思路其实很简单,就是根据图片的长宽进行等比缩小即可。代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    private static Image FixedSize(Image imgPhoto, int width, int height, Color clearColor)
    {
        int sourceWidth = imgPhoto.Width;
        int sourceHeight = imgPhoto.Height;
        int sourceX = 0;
        int sourceY = 0;
        int destX = 0;
        int destY = 0;
     
        float nPercent;
        float nPercentW;
        float nPercentH;
     
        nPercentW = ((float)width / (float)sourceWidth);
        nPercentH = ((float)height / (float)sourceHeight);
        if (nPercentH < nPercentW)
        {
            nPercent = nPercentH;
            destX = Convert.ToInt16((width - (sourceWidth * nPercent)) / 2);
        }
        else
        {
            nPercent = nPercentW;
            destY = Convert.ToInt16((height - (sourceHeight * nPercent)) / 2);
        }
     
        int destWidth = (int)(sourceWidth * nPercent);
        int destHeight = (int)(sourceHeight * nPercent);
     
        Bitmap bmPhoto = new Bitmap(width, height,
            PixelFormat.Format24bppRgb);
        bmPhoto.SetResolution(imgPhoto.HorizontalResolution,
            imgPhoto.VerticalResolution);
     
        Graphics grPhoto = Graphics.FromImage(bmPhoto);
        grPhoto.Clear(clearColor);
        grPhoto.InterpolationMode =
            InterpolationMode.HighQualityBicubic;
     
        grPhoto.DrawImage(imgPhoto,
            new Rectangle(destX, destY, destWidth, destHeight),
            new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight),
            GraphicsUnit.Pixel);
     
        grPhoto.Dispose();
        return bmPhoto;
    }

    让应用程序在UAC下具有访问文件系统资源的权限

    这是之前版本中CloudNotes桌面客户端更新程序遇到的一个问题。如果用户将CloudNotes安装在系统目录中,更新程序在试图更新CloudNotes桌面客户端的版本的时候,就会遇到错误,提示无法更新。根本原因是用户在Windows系统中启用了用户帐户控制(UAC),即使当前登录系统的帐户是管理员,也并不代表该用户对系统中的所有资源都具备管理员权限。在这种情况下,即使是由管理员启动的更新程序,也无法将下载并解压好的文件复制到系统目录下。

    要解决这一问题,就需要在.NET应用程序的Manifest里指定requestedExecutionLevel,将其指定为requireAdministrator,于是,在执行更新程序的时候,会弹出以下标准对话框,让用户对应用程序所作出的行为进行确认:

    image

    此时只需点击“是”按钮即可完成更新。

    更改Manifest其实很简单,只需要在应用程序项目上,通过Visual Studio的“添加项目”对话框,即可添加App.manifest文件,将文件中的requestedExecutionLevel改为requireAdministrator即可:

    image

    有关CloudNotes WebAPI以及桌面客户端的其它内容,请大家直接上https://github.com/daxnet/CloudNotes站点直接查看源代码即可。不懂的地方可以在此留言。

    接下来??

    我是打算一步步对CloudNotes进行功能和性能完善的,接下来要做的事情还有太多。在每次完成新功能更新时,我都会出博客文章进行介绍。如果没有新功能,我也会穿插介绍已有功能的相关技术实现。就目前而言,打算接下来的版本逐步提供以下功能改进:

    • 本地缓存和服务器同步系统 - 目前每次打开和保存笔记,都是与服务器直接相连的,不仅增大服务器负载,而且用户体验也不够流畅
    • 插件系统 - 任何感兴趣的朋友都可以通过插件系统,为CloudNotes桌面客户端编写插件,比如,直接将网页抓取成日志等
    • 用户之间的互信和笔记共享服务
    • 文档结构视图 - 通过分析HTML文档,提供层级的文档结构视图,方便用CloudNotes进行写作的用户

    等等等等。。。。。。让我们一起期待吧。。

     
    分类: CloudNotes
  • 相关阅读:
    win 8系统:System.IO.FileNotFoundException: 未能加载文件或程序集“CefSharp.Core.dll”或它的某一个依赖项。找不到指定的模块
    shell 调试脚本设置
    shell 变量相关的命令
    shell 多行注释
    web site optimization
    centos7 yum install timeout
    centos7 update network time
    centos7 update docker
    centos7 install fastdfs nginx
    centos7 install rabbtimq
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/4209491.html
Copyright © 2011-2022 走看看