距离上一次分享,感觉过去了好久好久。最近手里的项目也完成的差不多了,接下来的几天(年前)会和大家分享一下在项目中收获的东西。
需求:用户使用App之后,可以保存当前屏幕截图,然后通过扫描二维码的形式下载图片到手机上。
.net core 环境安装啥的我就不说了,去微软官网下载对应的SDK安装好。我使用的是.net core3.1,开发工具是VSCode。
打开终端,输入 : dotnet new webapi
终端自动创建一个webpai的模板,我们对这个模板做一些修改(模板自带了一个天气查询的例子)。
using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;
namespace FileUpload.Controllers
{
///
/// 访问当前控制器使用的路由地址
/// http://localhost/api/img
///
[Route("api/img")]
public class WeatherForecastController : Controller
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
///
/// 使用.net core 的依赖注入,将要用到的实例注入进来
///
private readonly IWebHostEnvironment _environment;
public WeatherForecastController(ILogger<WeatherForecastController> logger,
IWebHostEnvironment environment)
{
_logger = logger;
///
/// 使用.net core 的依赖注入,将要用到的实例注入进来
///
_environment = environment ?? throw new ArgumentNullException(nameof(environment));
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
///
/// 重要提示,函数的参数的名字必须保持和前端传来的字段名字相同
/// 在发布窗体数据或直接使用 JavaScript FormData 的非 Razor 窗体中,
/// 窗体元素或 FormData 指定的名称必须与控制器操作的参数名称相匹配。
///
///
///
[HttpPost]
public async Task<string> UploadImage(IFormFile file)
{
///
/// 获取当前静态文件目录所在文件夹
///
///
var uploads = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
///
/// 按年月日时分秒的格式保存当前文件
///
///
var fileName = DateTime.Now.ToString("yyyyMMddHHmmssffff") + ".jpg";
var targetPath = Path.Combine(uploads, fileName);
using (var steam = new FileStream(targetPath, FileMode.Create))
{
///
/// 将获取到的文件写入到服务器的指定目录中
///
///
await file.CopyToAsync(steam);
await steam.FlushAsync();
steam.Close();
///
/// 将当前接收到的文件的名字返回给前端
///
return fileName;
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace FileUpload
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
//services.AddAuthentication(CertificateAuthenticationDefaults.)
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
///添加访问静态文件支持
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:23643",
"sslPort": 44395
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"FileUpload": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "weatherforecast",
"applicationUrl": "http://localhost:5000;",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
到这里后台代码搭建就完成了,如果你出了什么问题,请看代码注释。其它具体的细节请看微软官方文档。
前台当然是在我们熟悉的Unity中完成啦。
public void StartScreenShoot()
{
StartCoroutine(ScreenSHOT());
}
private IEnumerator ScreenShot()
{
yield return new WaitForEndOfFrame();
//设置要截取的图片为矩形,大小和屏幕等高
Texture2D screenShot = new Texture2D(Screen.height, Screen.height, TextureFormat.RGB24, false);
var horizontalOffset = (Screen.width - Screen.height) / 2f;
//读取屏幕中间部分的像素,高度和当前屏幕高度等高
screenShot.ReadPixels(new Rect(horizontalOffset, 0, Screen.height, Screen.height), 0, 0);
screenShot.Apply();
yield return new WaitForEndOfFrame();
}
本例子中实现的是,将图片上传到服务器,服务器返回当前上传图片的文件名,用于网址访问
///
/// 将图片上传到自家服务器
///
///
///
IEnumerator UploadTexture(Texture2D targetTexture)
{
///
/// 将屏幕截图编码为字节流
///
///
byte[] bytes = targetTexture.EncodeToJPG();
///
/// 构建传输表单
///
///
WWWForm wwwForm = new WWWForm();
///
/// 重要:构建表单数据,这里的file字段必须保持和服务器对应函数的参数名称相同
///
///
wwwForm.AddBinaryData("file", bytes, "myfile.jpg");
///
/// 构建POST请求,打包时将下面网址替换为自己服务器的网址,也就是服务器对应的请求路由
///
///
using (UnityWebRequest www = UnityWebRequest.Post("http://localhost:5000/api/img", wwwForm))
{
///
/// 声明一个内存缓冲,用于接收服务器传回的内容
///
///
www.downloadHandler = new DownloadHandlerBuffer();
///
/// 重要:指定当前传输的文件类型,如果不指定,服务器可能会识别不了
///
///
www.uploadHandler.contentType = "multipart/form-data";
yield return www.SendWebRequest();
if (www.isHttpError || www.isNetworkError)
{
Debug.Log("自己的服务器错误");
loading.gameObject.SetActive(true);
}
else
{
//将接受到的图片在服务器的文件名和你自己的服务器域名组合起来
var imagURL = "http://localhost:5000/" + www.downloadHandler.text;
Debug.Log(imagURL);
yield return StartCoroutine(GetCLQRCode(imagURL));
}
}
}
生成二维码有很多种方式,这里使用最简单的一种。我们直接调用草料二维码提供的API接口来生成二维码。参考文章(https://www.jianshu.com/p/fece59a67860),看代码注释:
///
/// 从二维码提供商那里下载被转码后的二维码
///
///
///
IEnumerator GetCLQRCode(string qrcodeImage)
{
UnityWebRequest www = new UnityWebRequest();
//构建GET请求,将需要编码的字符串包装到请求参数中
string url = "https://cli.im/api/qrcode/code?text=" + qrcodeImage + "&mhid=t0uVWg+9ks4hMHcmLtBTOaM";
www.url = url;
Debug.Log(url);
www.method = UnityWebRequest.kHttpVerbGET;
www.downloadHandler = new DownloadHandlerBuffer();
yield return www.SendWebRequest();
if (www.isHttpError || www.isNetworkError)
{
Debug.Log("二维码服务商错误");
}
else
{
///
/// 请求成功,草料API会返回一个html格式的网页,
/// 需要对网页做一些内容截取,获取到返回的二维码的具体地址
///
var w = www.downloadHandler.text;
Debug.Log(w);
string s = w.Substring(w.IndexOf(") + 12, w.Length - (w.IndexOf(") + 12));
string result = s.Substring(0, s.IndexOf("\""));
Debug.Log(result);
UnityWebRequest qrcode = new UnityWebRequest();
qrcode.url = result;
qrcode.method = UnityWebRequest.kHttpVerbGET;
qrcode.downloadHandler = new DownloadHandlerBuffer();
yield return qrcode.SendWebRequest();
if (qrcode.isHttpError || qrcode.isNetworkError)
{
Debug.Log(qrcode.error);
Debug.Log("访问二维码出错");
}
else
{
//构建一个texture2D用来存储二维码
QRCodeTexture2D = new Texture2D(400, 400);
yield return new WaitForSeconds(3f);
//将接收到的图片数据写入构建的Texture2D中
QRCodeTexture2D.LoadImage(qrcode.downloadHandler.data);
QRCodeTexture2D.Apply();
rawImage.gameObject.SetActive(true);
//声明一个rawimage用来显示二维码
rawImage.texture = QRCodeTexture2D;
}
Debug.Log("获取二维码成功");
}
}
完。
更多内容,欢迎关注: