c#天天生成漂亮桌面背景、英文名言、翻译

.NET生成漂亮桌面背景

 

.NET生成漂亮桌面背景

一天,我朋友指着某某付费软件对我说,这个东西不错,天天生成一张桌面背景,还能学英语(放置名人名言和翻译)!我说,这东西搞很差我也能作,而后朋友说,“若是你搞出来了,我愿意给你付费$$$$元”,而后就有了今天的故事😎。github

该桌面背景效果以下:
json

该桌面背景有4个特色:api

  1. 背景为一张从必应下载的壁纸
  2. 英文为随机的名人名言,从API获取
  3. 注意文件下文有阴影,使用Direct2D
  4. 英文被翻译成了中文,使用了Azure Cognitive Service

固然还有重要的,须要将这张图片设为桌面背景,这经过Windows API完成。下面我将对里面的功能点一一讲解。数组

第一步 下载必应壁纸

bing.com天天提供了一张壁纸,下载bing壁纸是最简单的方式。根据用户协议,必应每日图片容许(也只容许)用户将其设置为桌面背景,所以能够放心使用。浏览器

bing壁纸的API以下:安全

https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=5&mkt=zh-cnruby

使用浏览器访问,格式以下:
微信

由图可见,API返回了一个JSON,里面一个images的数组,里面元素中的url属性便是bing壁纸。能够经过拼接https://www.bing.com来下载今天的bing壁纸:

所以,本段也分为三小步,用C#代码能够这样写:

1. 下载bing.com壁纸查询API

下载使用HttpClient,注意HttpClient在单个应用中应该定义为静态的。代码以下:

var http = new HttpClient(); string url = @"https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=5&mkt=zh-cn"; string content = await http.GetStringAsync(url);

注意其中的&n=5中的5,指的是最新的5张照片,若是想获取10张,能够将5改为10

2. 解析返回的壁纸JSON信息

解析JSON有不少方式,本文使用传统的Json.NET/Newtonsoft.Json来作:

string json = JToken.Parse(content); string images = json["images"] .Select(x => x["url"].ToString()) .Select(x => "https://cn.bing.com" + x); string pictureUrl = images.First();

注意第二行代码,其实能够直接获取全部的bing壁纸。

3. 下载完成的壁纸图片

这一步也经过HttpClient完成:

var fileName = Path.GetTempFileName(); File.WriteAllBytes(fileName, await http.GetByteArrayAsync(url)); return fileName;

而后下载的图片就保存在fileName这个变量所表达的路径中了。

注意:不必定非要下载到文件中,下载到内存中亦可,但下文中的代码须要少量调整,这里就不深刻了。

第二步 获取名人名言

我在网上找了一下,有很多网站都提供了英语名人名言服务,其中还不乏免费服务。本文使用的是favqs.com提供的API(随便找的),该API每次调用都会返回不一样的“名人名言”,我试了一下,可堪一用,免费API调用地址以下:

https://favqs.com/api/qotd

返回的json格式以下:

{
    "qotd_date": "2019-09-30T00:00:00.000+00:00", "quote": { "id": 61060, "dialogue": false, "private": false, "tags": [ "work" ], "url": "https://favqs.com/quotes/voltaire/61060-let-us-work-w-", "favorites_count": 0, "upvotes_count": 1, "downvotes_count": 0, "author": "Voltaire", "author_permalink": "voltaire", "body": "Let us work without theorizing, tis the only way to make life endurable." } }

能够看到做者和文本,可使用authorbody两个字段来表示。

这部分使用C#代码下载和解析过程以下:

async Task<string> GetQuote() { var url = @"https://favqs.com/api/qotd"; var content = await http.GetStringAsync(url); var json = JToken.Parse(content); return json["quote"]["body"] + "\r\n\t\t\t\t——" + json["quote"]["author"]; }

如代码所示,我将bodyauthor两个字段拼接成了一个字符串,能够直接使用,像这样:

Let us work without theorizing, tis the only way to make life endurable. ——Voltaire

第三步 生成图片(加阴影)

这步使用Direct2D,比较复杂,要注意的点不少,各位能够选择跳过这一步(直接拿代码😂),或者稍微看看。

string GenerateWallpaper(string pictureFileName, string english, string chinese) { var wic = new WIC.ImagingFactory2(); var d2d = new D2D.Factory(); float dpi = d2d.DesktopDpi.Width; Size2 size = new Size2(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height); WIC.FormatConverter image = CreateWicImage(wic, pictureFileName); using (var wicBitmap = new WIC.Bitmap(wic, size.Width, size.Height, WIC.PixelFormat.Format32bppPBGRA, WIC.BitmapCreateCacheOption.CacheOnDemand)) using (var target = new D2D.WicRenderTarget(d2d, wicBitmap, new D2D.RenderTargetProperties())) using (var dc = target.QueryInterface<D2D.DeviceContext>()) using (var bmpPicture = D2D.Bitmap.FromWicBitmap(target, image)) using (var dwriteFactory = new SharpDX.DirectWrite.Factory()) using (var brush = new SolidColorBrush(target, SharpDX.Color.LightGoldenrodYellow)) using (var bmpLayer = new D2D.Bitmap1(dc, target.PixelSize, new D2D.BitmapProperties1(new D2D.PixelFormat(SharpDX.DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Premultiplied), dpi, dpi, D2D.BitmapOptions.Target))) { var oldTarget = dc.Target; dc.Target = bmpLayer; target.BeginDraw(); { var textFormat = new DWrite.TextFormat(dwriteFactory, "Tahoma", size.Height / 27); // draw English { var textLayout = new DWrite.TextLayout(dwriteFactory, english, textFormat, target.Size.Width * 0.75f, float.MaxValue); var center = new Vector2((target.Size.Width - textLayout.Metrics.Width) / 2, (target.Size.Height - textLayout.Metrics.Height) / 2); target.DrawTextLayout(new Vector2(center.X, center.Y), textLayout, brush); } { // draw Chinese  var textLayout = new DWrite.TextLayout(dwriteFactory, chinese, textFormat, target.Size.Width * 0.75f, float.MaxValue); var center = new Vector2((target.Size.Width - textLayout.Metrics.Width) / 2, target.Size.Height - textLayout.Metrics.Height - size.Height / 18); target.DrawTextLayout(new Vector2(center.X, center.Y), textLayout, brush); } } target.EndDraw(); // shadow var shadow = new D2D.Effects.Shadow(dc); shadow.SetInput(0, bmpLayer, new RawBool(false)); dc.Target = oldTarget; target.BeginDraw(); { target.DrawBitmap(bmpPicture, new RectangleF(0, 0, target.Size.Width, target.Size.Height), 1.0f, BitmapInterpolationMode.Linear); dc.DrawImage(shadow, new Vector2(size.Height / 150.0f, size.Height / 150.0f)); dc.UnitMode = UnitMode.Pixels; target.DrawBitmap(bmpLayer, 1.0f, BitmapInterpolationMode.Linear); } target.EndDraw(); string wallpaperFileName = Path.GetTempPath() + "wallpaper.png"; using (var wallpaperStream = File.OpenWrite(wallpaperFileName)) { SaveD2DBitmap(wic, wicBitmap, wallpaperStream); wallpaperStream.Close(); return wallpaperFileName; } } } WIC.FormatConverter CreateWicImage(WIC.ImagingFactory wicFactory, string filename) { using (var decoder = new WIC.JpegBitmapDecoder(wicFactory)) using (var decodeStream = new WIC.WICStream(wicFactory, filename, NativeFileAccess.Read)) { decoder.Initialize(decodeStream, WIC.DecodeOptions.CacheOnLoad); using (var decodeFrame = decoder.GetFrame(0)) { var converter = new WIC.FormatConverter(wicFactory); converter.Initialize(decodeFrame, WIC.PixelFormat.Format32bppPBGRA); return converter; } } } void SaveD2DBitmap(WIC.ImagingFactory wicFactory, WIC.Bitmap wicBitmap, Stream outputStream) { using (var encoder = new WIC.BitmapEncoder(wicFactory, WIC.ContainerFormatGuids.Png)) { encoder.Initialize(outputStream); using (var frame = new WIC.BitmapFrameEncode(encoder)) { frame.Initialize(); frame.SetSize(wicBitmap.Size.Width, wicBitmap.Size.Height); var pixelFormat = wicBitmap.PixelFormat; frame.SetPixelFormat(ref pixelFormat); frame.WriteSource(wicBitmap); frame.Commit(); encoder.Commit(); } } }

要看的话,要点以下:

  1. 图片大小是由主显示器分辨率决定的,可使用Screen.PrimaryScreen.Bounds.Width/Screen.PrimaryScreen.Bounds.Height获取;
  2. 必定要注意不一样电脑的DPI设置,这样能够保证高DPI和低DPI的显示器都能有完美的效果,这部分是使用d2d.DesktopDpi.Width获取的,请注意里面的使用方式(最重要的是用不一样客户的电脑亲自运行看看);
  3. 字体大小是根据图片的高度决定的,如代码所示,字体大小为size.Height / 27
  4. 虽然代码先后顺序是先画文字、再画阴影,但实际生成代码部分,是先画阴影、再画文字,这样确保文字在阴影之上;
  5. 可使用textLayout.Metrics获取生成文字的宽度和高度,这样能够确保文件显示在中心位置;
  6. 注意下文中dc.UnitMode = UnitMode.Pixels,这是确保DPI显示正常。说来复杂,长话短说就是这其实很合理,前面设置了DPI,该DPI不只影响文字,也会影响图片,但实际上图片不该该被DPI影响。

之后有机会我会多聊聊Direct2D,这简直是一个宝库。

第四步 将文字翻译成中文

翻译服务API提供商就更多了,选择不少。我用的是Azure Cognitive Service,它也是免费的(也有付费版本)。建立这个服务后,它会提供两个单独的key,使用这个key便可调用翻译服务了:

不像是阿里云、AWS那种,Azure会为不一样的服务提供不一样的Access Key,这样作可能更容易控制信息安全一些。

Azure提供了SDK,所以调用起来很是简单:

async Task<string> EnglishToChinese(string english) { var client = new TranslateClient(new CognitiveServicesConfig { SubscriptionKey = Util.GetPassword("Translate_Free") }); var response = await client.TranslateAsync(new RequestContent { Text = english }, new RequestParameter { To = new string[] { "zh-Hans" } }); return response[0].Translations[0].Text; }

其实它的功能很是强大,甚至还能多国语言同步翻译等等。

最后一步 设置桌面背景

这一步调用Windows API,直接使用“祖传代码”便可:

public sealed class Wallpaper { const int SPI_SETDESKWALLPAPER = 20; const int SPIF_UPDATEINIFILE = 0x01; const int SPIF_SENDWININICHANGE = 0x02; [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni); public enum Style : int { Tiled, Centered, Stretched } public static void Set(string pictureFileName, Style style) { RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Desktop", true); if (style == Style.Stretched) { key.SetValue(@"WallpaperStyle", 2.ToString()); key.SetValue(@"TileWallpaper", 0.ToString()); } if (style == Style.Centered) { key.SetValue(@"WallpaperStyle", 1.ToString()); key.SetValue(@"TileWallpaper", 0.ToString()); } if (style == Style.Tiled) { key.SetValue(@"WallpaperStyle", 1.ToString()); key.SetValue(@"TileWallpaper", 1.ToString()); } SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pictureFileName, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); } }

使用时,直接这样调用:

Wallpaper.Set(wallpaperFileName, Wallpaper.Style.Centered);

注意:因为第三步中确保了分辨率同样,所以也不用关心第二个参数。

总结

最后看一下执行效果:

然而最后,我那个朋友说,你这东西要是支持Linux就好咯。我不用Linux,因此我也不打算支持(我看他其实也根本不用Linux),所以最后说好的$$$$我一分钱也没拿到😂。

因此这部分代码我托盘而出,向各位免费相送,分为带翻译版本和不带翻译版本,不带翻译版本可直接使用,带翻译版本须要注册一个免费Azure账号(其实也能运行,只是翻译中文会显示翻译错误)。愿博君一笑:

无翻译:https://github.com/sdcb/blog-data/blob/master/2019/20190930-wallpaper-by-dotnet/PictureAndQuote-Wallpaper.linq 带翻译:https://github.com/sdcb/blog-data/blob/master/2019/20190930-wallpaper-by-dotnet/PictureAndQuote-Wallpaper-T.linq

喜欢的朋友请关注个人微信公众号:【DotNet骚操做】

 

 

出处:https://www.cnblogs.com/Leo_wl/p/11638286.html

相关文章
相关标签/搜索