public MemoryStream RenderWeatherImage(WeatherRendererInfo info) { MemoryStream output = new MemoryStream(); using (Image <Rgba32> image = images["background"].Clone()) { var now = info.Date; var topDateLine = now.ToString("h:mm:ss tt", CultureInfo.CurrentCulture).ToUpper(); var bottomDateLine = now.ToString("ddd MMM d", CultureInfo.CurrentCulture).ToUpper(); var tickerLine = info.Alert != null ? info.Alert + "\n" : ""; tickerLine += $"Temp: {(int)info.Temperature}°{info.Unit} Feels Like: {(int)info.FeelsLike}°{info.Unit}"; if (info.Alert != null) { image.Mutate(i => i.Fill <Rgba32>(WeatherColors.Red, new Rectangle(0, 480, image.Width, 96))); } // everything except the forecast var cmds = new List <DrawCommand> { new DrawCommand() { Text = info.Address, Font = mdFont, X = 150, Y = 8, Color = WeatherColors.White }, new DrawCommand() { Text = "Extended Forecast", Font = mdFont, IsRelative = true, X = 0, Y = 36, Color = WeatherColors.Yellow }, new DrawCommand() { Text = topDateLine, Font = smFont, X = 695, Y = 12, Color = WeatherColors.White }, new DrawCommand() { Text = bottomDateLine, Font = smFont, IsRelative = true, X = 0, Y = 25, Color = WeatherColors.White }, new DrawCommand() { Text = tickerLine, Font = mdFont, X = 5, Y = 485, Color = WeatherColors.White }, }; int bx = 15, by = 90; foreach (var day in info.Forecast) { cmds.AddRange(new List <DrawCommand> { new DrawCommand() { X = bx, Y = by }, // day of week, icon, summary new DrawCommand() { Text = day.Date.ToString("ddd", CultureInfo.CurrentCulture).ToUpper(), HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, IsRelative = true, X = 100, Y = 30, Font = mdFont, Color = WeatherColors.Yellow }, new DrawCommand() { Image = images.ContainsKey(day.Icon) ? images[day.Icon] : images["clear-day"], HorizontalAlignment = HorizontalAlignment.Center, ContentWidth = 190, IsRelative = true, X = -90, Y = 40 }, new DrawCommand() { Text = day.Summary, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, IsRelative = true, X = 90, Y = 150, Font = mdFont, Color = WeatherColors.White }, // low temperature new DrawCommand() { Text = "Lo", HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, IsRelative = true, X = -50, Y = 75, Font = mdFont, Color = WeatherColors.TealAlso }, new DrawCommand() { Text = day.LoTemp != null ? Math.Round(day.LoTemp.Value, 0).ToString() : "", HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, IsRelative = true, X = 0, Y = 50, Font = lgFont, Color = WeatherColors.White }, // high temperature new DrawCommand() { Text = "Hi", HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, IsRelative = true, X = 100, Y = -50, Font = mdFont, Color = WeatherColors.Yellow }, new DrawCommand() { Text = day.HiTemp != null ? Math.Round(day.HiTemp.Value, 0).ToString() : "", HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center, IsRelative = true, X = 0, Y = 50, Font = lgFont, Color = WeatherColors.White }, }); bx += 244; } int x = 0, y = 0; foreach (var cmd in cmds) { // reset the position if it's not relative if (cmd.IsRelative) { x += cmd.X; y += cmd.Y; } else { x = cmd.X; y = cmd.Y; } // if we have a text object, use textalignment, color, and text fields if (cmd.Text != null) { var textOpts = new TextGraphicsOptions(false) { HorizontalAlignment = cmd.HorizontalAlignment, VerticalAlignment = cmd.VerticalAlignment }; image.Mutate(i => i.DrawText(textOpts, cmd.Text, cmd.Font, WeatherColors.Black, new Vector2(x + 2, y + 2))); image.Mutate(i => i.DrawText(textOpts, cmd.Text, cmd.Font, cmd.Color, new Vector2(x, y))); } // if we have an image object, use the image field if (cmd.Image != null) { Point pos = new Point(x, y); if (cmd.ContentWidth > 0 && cmd.HorizontalAlignment == HorizontalAlignment.Center) { pos.X += (cmd.ContentWidth - cmd.Image.Width) / 2; } image.Mutate(i => i.DrawImage(cmd.Image, PixelBlenderMode.Normal, 1.0f, pos)); } } image.SaveAsPng(output); } output.Seek(0, SeekOrigin.Begin); return(output); }
// only get the data here, buddy public async Task <WeatherRendererInfo> GetForecastAsync(string query) { // use google to get address, lat, and lng for a human-entered string Location location; try { IGeocoder geocoder = new BingMapsGeocoder(bingApiKey); var geoResult = await geocoder.GeocodeAsync(query); dynamic address = geoResult.FirstOrDefault(); if (address == null) { return(null); } location = new Location { Latitude = address.Coordinates.Latitude, Longitude = address.Coordinates.Longitude, FormattedAddress = address.FormattedAddress }; if (address.Type.ToString().StartsWith("Postcode")) { location.FormattedAddress = $"{address.Locality} {address.FormattedAddress}"; } } catch (Exception) { return(null); } // request darksky without minutely/hourly, and use location to determine units var WeatherService = new DarkSkyService(darkSkyApiKey); DarkSkyResponse forecast = await WeatherService.GetForecast(location.Latitude, location.Longitude, new DarkSkyService.OptionalParameters { DataBlocksToExclude = new List <ExclusionBlock> { ExclusionBlock.Minutely, ExclusionBlock.Hourly, }, MeasurementUnits = "auto" }); var timezone = DateTimeZoneProviders.Tzdb[forecast.Response.TimeZone]; var myTime = SystemClock.Instance.GetCurrentInstant(); var info = new WeatherRendererInfo() { Address = location.FormattedAddress, Unit = forecast.Response.Flags.Units == "us" ? "F" : "C", Date = myTime.InZone(timezone), Temperature = forecast.Response.Currently.Temperature, FeelsLike = forecast.Response.Currently.ApparentTemperature, Alert = forecast.Response.Alerts?[0].Title }; int counter = 0; foreach (var day in forecast.Response.Daily.Data.Take(4)) { var dayRender = new WeatherRendererDay() { HiTemp = day.TemperatureHigh, LoTemp = day.TemperatureLow, Summary = weatherDescription.ContainsKey(day.Icon.ToString()) ? weatherDescription[day.Icon.ToString()] : day.Icon.ToString().Replace("-", ""), Icon = string.Join("-", Regex.Split(day.Icon.ToString(), @"(?<!^)(?=[A-Z])")).ToLower(), Date = info.Date.Plus(Duration.FromDays(counter)) }; info.Forecast.Add(dayRender); counter++; } return(info); }