.Net Core裁剪图片并存入数据库
前言
由于我做的一个项目需要让用户上传图片并且可以在线裁剪并预览,但是我发现网上关于.net core这方面的资料很少,几乎都是别的语言的并且由于.net core的特殊性不能够直接使用.net的方法,所以在我在此将我收集到的资料总结一下,方便有需要的朋友借鉴。这次是我第一次写博客,不管是程序上还是文章上如果有任何不足欢迎大家指正,我会及时改正并吸取经验。
话不多说先上图
环境介绍
-
框架版本:.Net Core MVC 2.1
-
数据库:SQL Server 2016
-
编码工具:VS2017
-
前端的处理用的是JCrop和Bootstrap-fileinput这两个插件,前端UI采用的是Bootstrap
JCrop插件是用来裁剪图片的,页面上裁剪就是保存裁剪的位置信息,然后将位置信息转给后台在后台进行实际图片裁剪功能。
插件地址:http://code.ciaoca.com/jquery/jcrop/
Bootstrap-fileinput插件是Bootstrap下的文件上传的插件,功能强大,我将依靠这个完成文件的上传,当然也能够使用其他的文件上传工具。
插件地址:http://plugins.krajee.com/file-input
文件上传后页面上展示的图片是以Data URI Scheme方式进行展示的。
Data URI Scheme知识点: https://blog.csdn.net/aoshilang2249/article/details/510099473.后端图片处理用的是三方类库SixLabors.ImageSharp,我用的版本是V1.0.0-beta0007,这个类库可以直接在NuGet包管理器中添加。建议使用和我一样的版本,我在找资料的过程中发现,不同版本的类库裁剪图片的方法可能会有所不同。
SixLabors.ImageSharp官网:https://sixlabors.com/projects/imagesharp/
NuGet地址:https://www.nuget.org/packages/SixLabors.ImageSharp/1.0.0-beta0007
步骤
本文示例代码链接:https://github.com/s894792409/ImageTest
一、引用插件
引用插件时要注意文件的路径是否正确
- 引用JCrop和Bootstrap-fileinput这两个插件的样式表文件。
<link href="@Url.Content("~/tapmodo-Jcrop-1902fbc/css/jquery.Jcrop.css")" rel="stylesheet" />
<link href="@Url.Content("~/bootstrap-fileinput/css/fileinput.css")" rel="stylesheet" />
- 引用JCrop和Bootstrap-fileinput这两个插件的脚本文件。
<script src="@Url.Content("~/tapmodo-Jcrop-1902fbc/js/jquery.Jcrop.js")"></script>
<script src="@Url.Content("~/bootstrap-fileinput/js/fileinput.js")"></script>
<script src="@Url.Content("~/bootstrap-fileinput/js/locales/zh.js")"></script>
3.在 工具-NuGet包管理器中添加ImageSharp
注意:由于ImageSharp类库在NuGet上是预发行版,所以在搜索时不要忘了勾选包括预发行版否则会搜索不到。
需要的ImageSharp类库列表:
二、创建数据库和表
创建表的脚本(SQL Server):
CREATE TABLE [dbo].[UserInfo] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Photo] VARBINARY (MAX) NULL,
[PhotoType] VARCHAR (50) NULL,
[UserName] VARCHAR (50) NULL,
[Name] VARCHAR (50) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
三、创建两个Models类
- TailorInfo.cs
这个类用来存储裁剪图片的信息
public class TailorInfo
{
public string PictureWidth { get; set; }
public string PictureHeight { get; set; }
public int CoordinateX { get; set; }
public int CoordinateY { get; set; }
public int CoordinateWidth { get; set; }
public int CoordinateHeight { get; set; }
}
- UserInfo.cs
这个类用来与数据库进行适配
public class UserInfo
{
[Key]
public int Id { get; set; }
public byte[] Photo { get; set; }
public string PhotoType { get; set; }
[Display(Name ="用户名")]
public string UserName { get; set; }
[Display(Name = "姓名")]
public string Name { get; set; }
}
四、实现增删改查这四个功能
这里可以 右键Controller-添加-新搭建基架的项目 来创建一个基础框架
一、添加数据
1.前端界面:
@model ImageTest.Models.UserInfo
@{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>UserInfo</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label class="control-label">Photo</label><br />
<img id="show-img" class="thumbnail" src="~/tapmodo-Jcrop-1902fbc/demos/demo_files/sago.jpg" style="width:150px;height:150px;border:2px solid #808080;">
<button class="btn btn-primary" data-toggle="modal" data-target="#myModal" type="button">上传图片</button>
<br /><span class="text-danger" id="photoerr"></span>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="width:95%">
<div class="modal-dialog" style="width:95%">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body ">
<h4 class="modal-title" id="myModalLabel">上传图片</h4>
<div class="row">
<div class="col-md-5">
<br /><br /><br />
<input type="file" name="txt_file" id="txt_file" multiple class="file-loading" style="align-content:flex-end;" />
</div>
<div>
<h4>图片说明:</h4>
<p>1、图片格式需要jpg、gif、png为后缀名.</p>
<p>2、图片可以在线裁剪大小,以裁剪后为最终结果.</p>
<p>3、图片上传完毕即可关闭窗口.</p>
</div>
</div>
<div class="row">
<img id="cut-img" class="thumbnail " src="~/tapmodo-Jcrop-1902fbc/demos/demo_files/sago.jpg">
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="UserName" class="control-label"></label>
<input asp-for="UserName" id="UserNameval" class="form-control" />
<span asp-validation-for="UserName" id="UserNameerr" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" id="Nameval" class="form-control" />
<span asp-validation-for="Name" id="Nameerr" class="text-danger"></span>
</div>
<div class="form-group">
<input type="button" onclick="check()" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
- 选择裁剪图片位置并预览的Javascript代码
这里用到的就是JCrop和Bootstrap-fileinput这两个插件,他们分别负责裁剪图片和上传图片。以下是对他们初始化和设置的代码。language: 'zh'
是用来设置Bootstrap-fileinput的语言的,在设置语言之前必须引用相对应的文件并且在引用Bootstrap-fileinput之后,在前面我们已经引用过了中文的语言包:zh
,默认为英语。
var file;
var tailorInfo = "";
var photoflag = false;
var formData = new FormData();//用来保存需要提交的信息
//初始化fileinput
function FileInput(ctrlName, uploadUrl) {
var oFile = new Object();
oFile.Init = function (ctrlName, uploadUrl) {
var control = $('#' + ctrlName);
//初始化上传控件的样式
control.fileinput({
language: 'zh', //设置语言
browseLabel: '选择',
browseIcon: "<i class=\"glyphicon glyphicon-picture\"></i> ",
browseClass: "btn btn-primary", //按钮样式
uploadUrl: uploadUrl, //上传的地址
allowedFileExtensions: ['jpg', 'gif', 'png'],//接收的文件后缀
showUpload: true, //是否显示上传按钮
showCaption: true,//是否显示标题
showPreview: false,//隐藏预览
dropZoneEnabled: false,//是否显示拖拽区域
uploadAsync: true,//采用异步
autoReplace: true,
//minImageWidth: 50,
//minImageHeight: 50,
//maxImageWidth: 1000,
//maxImageHeight: 1000,
//maxFileSize: 0,//单位为kb,如果为0表示不限制文件大小
//minFileCount: 0,
maxFileCount: 1, //表示允许同时上传的最大文件个数
enctype: 'multipart/form-data',
validateInitialCount: true,
previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",
uploadExtraData: function () {
return { "tailorInfo": tailorInfo };
}
});
}
return oFile;
};
function PageInit() {
var jcorp = null;
var _this = this;
var fileInput = new FileInput();
fileInput.Init("txt_file", "@Url.Action("UpLoadFile")");
var input = $('#txt_file');
//图片上传完成后
input.on("fileuploaded", function (event, data, previewId, index) {
if (data.response.success) {
jcorp.destroy();
var str = data.response.message;
$('#cut-img').removeAttr('style');
$('#cut-img').attr('src', data.response.newImage);//Data URI Scheme形式
//$('#cut-img').width(data.response.width).height(data.response.height);
$('#show-img').attr('src', data.response.newImage);//Data URI Scheme形式
photoflag = true;
alert(str);
//$('#cut-img').attr('src', data.response.newImage + "?t=" + Math.random());//加尾巴解决缓存问题
}
});
//选择图片后触发
input.on('change', function (event, data, previewId, index) {
var img = $('#cut-img');
if (input[0].files && input[0].files[0]) {
file = input[0].files[0];
formData.append("files", input[0].files[0]);//保存用户上传的图片
var reader = new FileReader();
reader.readAsDataURL(input[0].files[0]);
reader.onload = function (e) {
img.removeAttr('style');
img.removeAttr('src');
img.attr('src', e.target.result);
img.Jcrop({
setSelect: [0, 0, 150, 150],
//handleSize: 10,
aspectRatio: 1,//选框宽高比
bgFade: false,
bgColor: 'black',
bgOpacity: 0.3,
onSelect: updateCords
}, function () {
jcorp = this;
});
};
if (jcorp != undefined) {
jcorp.destroy();
}
}
function updateCords(obj) {
tailorInfo = JSON.stringify({ "PictureWidth": $('.jcrop-holder').css('width'), "PictureHeight": $('.jcrop-holder').css('height'), "CoordinateX": obj.x, "CoordinateY": obj.y, "CoordinateWidth": obj.w, "CoordinateHeight": obj.h });
console.log(tailorInfo);
}
});
//上传出现错误
input.on('fileuploaderror', function (event, data, msg) {
alert(event + msg);
photoflag = false;
//jcorp.destroy();
//$('#cut-img').attr('src', '/Content/defaultAvatar.jpg');
return false;
});
//移除图片
input.on('fileclear', function (event) {
console.log("fileclear");
jcorp.destroy();
$('#cut-img').attr('src', '~/tapmodo-Jcrop-1902fbc/demos/demo_files/sago.jpg');
});
};
$(function () {
PageInit();
});
3.提交数据和图片
由于 input
这个控件被选择的图片只能提交一次,所以在这里不能再使用submit
提交。我用的是ajax
搭配FormData
来提交的数据。在用户选择图片后将被选择的图片复制一份放进了FormData
里
function check() {
var UserNameval = $("#UserNameval");//UserName的值
var UserNameerr = $("#UserNameerr");//UserName输入格式错误时的提示
var Nameval = $("#Nameval");//Name的值
var Nameerr = $("#Nameerr");//Name输入格式错误时的提示
var photoerr = $("#photoerr");
var checkformat = true;//检查格式的flag
if (UserNameval.val() == "") {
UserNameerr.html("用户名不能为空!");
checkformat = false;
} else {
UserNameerr.html("");
}
if (Nameval.val() == "") {
Nameerr.html("姓名不能为空!");
checkformat = false;
} else {
Nameerr.html("");
}
if (!photoflag) {
photoerr.html("图片未正确上传!");
checkformat = false;
} else {
photoerr.html("");
}
if (checkformat) { //验证完成后将数据通过ajax传到Controller
formData.append("tailorInfo", tailorInfo);
var Userinfo = JSON.stringify({ "UserName": UserNameval.val(), "Name": Nameval.val()});
formData.append("Userinfo", Userinfo);
$.ajax({
url: '@Url.Action("CreateData")',//这里填写Controller接收的方法
type: 'POST',
data: formData,
async: false,
cache: false,
contentType: false,
processData: false,
success: function (returndata) {
if (returndata.success) {
alert("Success! \n");
window.location.href = "index";// 重定向网页
} else {
alert(returndata.msg);
}
},
error: function (returndata) {
alert(returndata.msg);
}
});
}
}
4.后台处理图片并将信息保存到数据库中
首先我们要做的是处理预览部分的图片,这一部分用ImageSharp
处理图片并生成一个base64格式的缩略图返回给页面。代码如下:
[HttpPost]
public ActionResult UpLoadFile(string tailorInfo)
{
var success = false;
var message = string.Empty;
var newImage = string.Empty;
var pictureUrl = string.Empty;
try
{
var tailorInfoEntity = JsonConvert.DeserializeObject<TailorInfo>(tailorInfo);
tailorInfoEntity.PictureWidth = tailorInfoEntity.PictureWidth.Replace("px", "");
tailorInfoEntity.PictureHeight = tailorInfoEntity.PictureHeight.Replace("px", "");
var file = HttpContext.Request.Form.Files["txt_file"];
if (file != null && file.Length != 0)
{
newImage = ImageCompress(file.OpenReadStream(), tailorInfoEntity);
success = true;
message = "保存成功";
}
}
catch (Exception ex)
{
message = "保存失败 " + ex.Message + " " + ex.StackTrace.ToString();
}
return Json(new { success = success, message = message, newImage = newImage });
}
public static string ImageCompress(Stream content, TailorInfo tailorInfo)
{
IImageFormat format;
var imageString = string.Empty;
using (Image<Rgba64> image = Image.Load<Rgba64>(content, out format))
{
Rectangle rectangle = new Rectangle(tailorInfo.CoordinateX, tailorInfo.CoordinateY, tailorInfo.CoordinateWidth, tailorInfo.CoordinateHeight);
image.Mutate(x => x
.Crop(rectangle)
.Resize(tailorInfo.CoordinateWidth, tailorInfo.CoordinateHeight)
);
imageString = image.ToBase64String<Rgba64>(format);
}
return imageString;
}
接下来我们要做的是将用户提交的数据和图片存到数据库中。因为考虑到用户上传完图片后可能会取消或者更换图片,所以我在这里最终的处理图片,由于base64的一些特性我选择了存入数据库字节。当然,数据库存储图片有两种方法一种是存储图片的字节流另一种是把图片保存在本地存储图片的路径。这两种方法各有各自的优缺点,在这里我选择的是存储字节流。
[HttpPost]
public async Task<IActionResult> CreateData()
{
bool success = false;
var files = Request.Form.Files;
var file = files.FirstOrDefault();
string msg = Request.Form["tailorInfo"];
var tailorInfoEntity = JsonConvert.DeserializeObject<TailorInfo>(msg);
string stuinfo = Request.Form["Userinfo"];
var userInfo = JsonConvert.DeserializeObject<UserInfo>(stuinfo);
try
{
string webrootpath = _hostingEnvironment.WebRootPath;
string filename = $"{ Guid.NewGuid()}.png";
string path = Path.Combine(webrootpath, filename).ToString();
Image<Rgba64> image = Image.Load<Rgba64>(file.OpenReadStream());
Rectangle rectangle = new Rectangle(tailorInfoEntity.CoordinateX, tailorInfoEntity.CoordinateY, tailorInfoEntity.CoordinateWidth, tailorInfoEntity.CoordinateHeight);
image.Mutate(x => x
.Crop(rectangle)
.Resize(tailorInfoEntity.CoordinateWidth, tailorInfoEntity.CoordinateHeight)
);
image.Save(path);
FileStream fs = new FileStream(path, FileMode.Open);
MemoryStream memory = new MemoryStream();
fs.CopyTo(memory);
userInfo.Photo = memory.ToArray();
userInfo.PhotoType = file.ContentType;
fs.Close();
FileInfo fileInfo = new FileInfo(Path.Combine(path));
fileInfo.Delete();
_context.Add(userInfo);
await _context.SaveChangesAsync();
success = true;
}
catch (Exception e)
{
msg = e.Message;
}
return Json(new { success = success, msg = msg });
}
到此为止添加数据这一部分就完成了。
二、编辑数据
1.前端界面
编辑数据的前端界面与前面的相似,他们的区别在与初始显示的图片和提交时的判定。
@model ImageTest.Models.UserInfo
@{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<h4>UserInfo</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label class="control-label">Photo</label><br />
<img id="show-img" class="thumbnail" src="/UserInfoes/ViewPhoto?id=@Model.Id" style="width:150px;height:150px;border:2px solid #808080;">
<button class="btn btn-primary" data-toggle="modal" data-target="#myModal" type="button">上传图片</button>
<br /><span class="text-danger" id="photoerr"></span>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="width:95%">
<div class="modal-dialog" style="width:95%">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
</div>
<div class="modal-body ">
<h4 class="modal-title" id="myModalLabel">上传图片</h4>
<div class="row">
<div class="col-md-5">
<br /><br /><br />
<input type="file" name="txt_file" id="txt_file" multiple class="file-loading" style="align-content:flex-end;" />
</div>
<div>
<h4>图片说明:</h4>
<p>1、图片格式需要jpg、gif、png为后缀名.</p>
<p>2、图片可以在线裁剪大小,以裁剪后为最终结果.</p>
<p>3、图片上传完毕即可关闭窗口.</p>
</div>
</div>
<div class="row">
<img id="cut-img" class="thumbnail " src="/UserInfoes/ViewPhoto?id=@Model.Id">
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="UserName" class="control-label"></label>
<input asp-for="UserName" id="UserNameval" class="form-control" />
<span asp-validation-for="UserName" id="UserNameerr" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" id="Nameval" class="form-control" />
<span asp-validation-for="Name" id="Nameerr" class="text-danger"></span>
</div>
<div class="form-group">
<input type="button" onclick="check()" value="Save" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
- 提交和上传图片的脚本。
var file;
var tailorInfo = "";
var photoflag = false;//判断图片是否上传成功的flag
var chengephoto = false;//判断是否更改了图片的flag
var formData = new FormData();//用来保存需要提交的信息
//初始化fileinput
function FileInput(ctrlName, uploadUrl) {
var oFile = new Object();
oFile.Init = function (ctrlName, uploadUrl) {
var control = $('#' + ctrlName);
//初始化上传控件的样式
control.fileinput({
language: 'zh', //设置语言
browseLabel: '选择',
browseIcon: "<i class=\"glyphicon glyphicon-picture\"></i> ",
browseClass: "btn btn-primary", //按钮样式
uploadUrl: uploadUrl, //上传的地址
allowedFileExtensions: ['jpg', 'gif', 'png'],//接收的文件后缀
showUpload: true, //是否显示上传按钮
showCaption: true,//是否显示标题
showPreview: false,//隐藏预览
dropZoneEnabled: false,//是否显示拖拽区域
uploadAsync: true,//采用异步
autoReplace: true,
//minImageWidth: 50,
//minImageHeight: 50,
//maxImageWidth: 1000,
//maxImageHeight: 1000,
//maxFileSize: 0,//单位为kb,如果为0表示不限制文件大小
//minFileCount: 0,
maxFileCount: 1, //表示允许同时上传的最大文件个数
enctype: 'multipart/form-data',
validateInitialCount: true,
previewFileIcon: "<i class='glyphicon glyphicon-king'></i>",
msgFilesTooMany: "选择上传的文件数量({n}) 超过允许的最大数值{m}!",
uploadExtraData: function () {
return { "tailorInfo": tailorInfo };
}
});
}
return oFile;
};
function PageInit() {
var jcorp = null;
var _this = this;
var fileInput = new FileInput();
fileInput.Init("txt_file", "@Url.Action("UpLoadFile")");
var input = $('#txt_file');
//图片上传完成后
input.on("fileuploaded", function (event, data, previewId, index) {
if (data.response.success) {
jcorp.destroy();
var str = data.response.message;
$('#cut-img').removeAttr('style');
$('#cut-img').attr('src', data.response.newImage);//Data URI Scheme形式
//$('#cut-img').width(data.response.width).height(data.response.height);
$('#show-img').attr('src', data.response.newImage);//Data URI Scheme形式
photoflag = true;
alert("success");
//$('#cut-img').attr('src', data.response.newImage + "?t=" + Math.random());//加尾巴解决缓存问题
}
});
//选择图片后触发
input.on('change', function (event, data, previewId, index) {
var img = $('#cut-img');
chengephoto = true;
if (input[0].files && input[0].files[0]) {
file = input[0].files[0];
formData.append("files", input[0].files[0]);//保存用户上传的图片
var reader = new FileReader();
reader.readAsDataURL(input[0].files[0]);
reader.onload = function (e) {
img.removeAttr('style');
img.removeAttr('src');
img.attr('src', e.target.result);
img.Jcrop({
setSelect: [0, 0, 150, 150],
//handleSize: 10,
aspectRatio: 1,//选框宽高比
bgFade: false,
bgColor: 'black',
bgOpacity: 0.3,
onSelect: updateCords
}, function () {
jcorp = this;
});
};
if (jcorp != undefined) {
jcorp.destroy();
}
}
function updateCords(obj) {
tailorInfo = JSON.stringify({ "PictureWidth": $('.jcrop-holder').css('width'), "PictureHeight": $('.jcrop-holder').css('height'), "CoordinateX": obj.x, "CoordinateY": obj.y, "CoordinateWidth": obj.w, "CoordinateHeight": obj.h });
console.log(tailorInfo);
}
});
//上传出现错误
input.on('fileuploaderror', function (event, data, msg) {
alert("Error \n"+event + msg);
photoflag = false;
//jcorp.destroy();
//$('#cut-img').attr('src', '/Content/defaultAvatar.jpg');
return false;
});
//移除图片
input.on('fileclear', function (event) {
console.log("fileclear");
jcorp.destroy();
$('#cut-img').attr('src', '~/tapmodo-Jcrop-1902fbc/demos/demo_files/sago.jpg');
});
};
$(function () {
PageInit();
});
function check() {
var UserNameval = $("#UserNameval");//UserName的值
var UserNameerr = $("#UserNameerr");//UserName输入格式错误时的提示
var Nameval = $("#Nameval");//Name的值
var Nameerr = $("#Nameerr");//Name输入格式错误时的提示
var photoerr = $("#photoerr");//photo未成功上传时的提示
var checkformat = true;//检查格式的flag
if (UserNameval.val() == "") {
UserNameerr.html("用户名不能为空!");
checkformat = false;
} else {
UserNameerr.html("");
}
if (Nameval.val() == "") {
Nameerr.html("姓名不能为空!");
checkformat = false;
} else {
Nameerr.html("");
}
if (chengephoto) {
if (photoflag) {
photoerr.html("");
} else {
photoerr.html("图片未正确上传!")
checkformat = false;
}
}
if (checkformat == true ) { //验证完成后将数据通过ajax传到Controller
formData.append("tailorInfo", tailorInfo);
var userid =@Model.Id;
var Userinfo = JSON.stringify({ "Id": userid, "UserName": UserNameval.val(), "Name": Nameval.val() });
formData.append("Userinfo", Userinfo);
console.log(Userinfo);
$.ajax({
url: '@Url.Action("UpdateData")',//这里填写Controller接收的方法
type: 'POST',
data: formData,
async: false,
cache: false,
contentType: false,
processData: false,
success: function (returndata) {
if (returndata.success) {
alert("Success! \n");
window.location.href = "/UserInfoes/index";// 重定向网页
} else {
alert("Error!\n"+returndata.msg);
}
},
error: function (returndata) {
alert(returndata.msg);
}
});
}
}
- 获取保存的照片图片
从前面的前端代码中这里用到的是以uri的方式获取图片,通过uri来执行controller中的方法获取图片。
[HttpGet]
public IActionResult ViewPhoto(int id)
{
UserInfo userInfo = _context.UserInfo.SingleOrDefault(s => s.Id == id);
MemoryStream ms = new MemoryStream(userInfo.Photo);
return new FileStreamResult(ms, userInfo.PhotoType);
}
- 后台对更新数据的处理
[HttpPost]
public async Task<IActionResult> UpdateData()
{
bool success = false;
string msg = "";
try
{
var files = Request.Form.Files;
var file = files.FirstOrDefault();
msg = Request.Form["tailorInfo"];
var tailorInfoEntity = JsonConvert.DeserializeObject<TailorInfo>(msg);
string Userinfo = Request.Form["Userinfo"];
var userInfo = JsonConvert.DeserializeObject<UserInfo>(Userinfo);
var info = await _context.UserInfo.AsNoTracking().SingleOrDefaultAsync(s => s.Id == userInfo.Id);
if (file != null)
{
string webrootpath = _hostingEnvironment.WebRootPath;
string filename = $"{ Guid.NewGuid()}.png";
string path = Path.Combine(webrootpath, filename).ToString();
try
{
Image<Rgba64> image = Image.Load<Rgba64>(file.OpenReadStream());
Rectangle rectangle = new Rectangle(tailorInfoEntity.CoordinateX, tailorInfoEntity.CoordinateY, tailorInfoEntity.CoordinateWidth, tailorInfoEntity.CoordinateHeight);
image.Mutate(x => x
.Crop(rectangle)
.Resize(tailorInfoEntity.CoordinateWidth, tailorInfoEntity.CoordinateHeight)
);
image.Save(path);
FileStream fs = new FileStream(path, FileMode.Open);
MemoryStream memory = new MemoryStream();
fs.CopyTo(memory);
info.Photo = memory.ToArray();
info.PhotoType = file.ContentType;
fs.Close();
FileInfo fileInfo = new FileInfo(Path.Combine(path));
fileInfo.Delete();
}
catch (Exception e)
{
msg = e.Message;
try
{
FileInfo fileInfo = new FileInfo(Path.Combine(path));
fileInfo.Delete();
}
catch { }
}
}
info.Name = userInfo.Name;
info.UserName = userInfo.UserName;
_context.Update(info);
await _context.SaveChangesAsync();
success = true;
return Json(new { success = success, msg = msg });
}catch(Exception e)
{
msg = e.Message;
return Json(new { success = success, msg = msg });
}
}
三、查询所有数据
- 前端界面
这个界面不需要任何脚本,但是需要控制器返回所有数据,并且通过之前的ViewPhoto(id)
来显示图片。
@model IEnumerable<ImageTest.Models.UserInfo>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Photo)
</th>
<th>
@Html.DisplayNameFor(model => model.UserName)
</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model) {
<tr>
<td>
<img id="show-img" class="thumbnail" src="/UserInfoes/ViewPhoto?id=@item.Id" style="width:150px;height:150px;border:2px solid #808080;">
</td>
<td>
@Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
- 后端代码
public async Task<IActionResult> Index()
{
return View(await _context.UserInfo.ToListAsync());
}
四、删除数据
删除数据直接用基础框架中的就好了,这里不会有太多的改动,只是更改一下显示图片,显示图片的方法可参照之前的显示全部数据。
总结
到此为止整个例子就完成了,在此特别感谢几位大佬的文章:
https://www.cnblogs.com/CKExp/p/8681263.html
https://www.cnblogs.com/GuZhenYin/p/8194726.html