近日拿到一个需求,通过分析思考以及查询资料得以解决,趁着不忙记录一下:
需求:
页面上放一个图片控件,载入图片之后,点击图片任何一个白色空间,找出点击点所在区域所能容纳的最大连续空白矩形面积及顶点坐标。
分析:
1、首先采用<img>
标签控件显示图片并设置图片路径载入图片;
2、<img>
标签给定点击事件onImageClick(event)
,获取点击点坐标;
3、向后台传递点击点坐标(x,y)
,进行相关计算;
4、后台接收点击点坐标(x,y)
,并获取图片宽高;
5、后台计算矩形面积及顶点坐标方法:
(1)通过for循环,以点击点坐标(x,y)
为起点,向四周延展,如果相邻点亦为白色,即 bitmap.GetPixel(x, y).ToArgb()==Color.White.ToArgb()
则为白色,可继续延展,否则停止该方向的延展。
(2)上下左右四个方向均做延展操作后,得到 左上角:(minX,minY)
,右下角:(maxX,maxY)
两个顶点坐标;
(3)矩形的长:width = maxX-minX
, 宽:height=maxY-minY
,面积:area=width*height
;
6、整合数据,向前台返回对应数据值;
7、前台处理返回值并对其进行相关显示处理。
话不多说,上代码:
前台代码片段:
HTML代码片段
<div><!--用于显示返回的顶点坐标及区域面积等信息--><p id="desc"></p>
</div>
<div><!--用于显示即将操作的图片文件--><img id="image" src="~/Content/images/pic.jpg" alt="Image" onclick="onImageClick(event)" />
</div>
JavaScript代码片段:
function onImageClick(event) {var img = document.getElementById("image");var x = event.offsetX;var y = event.offsetY;var desc = document.getElementById("desc");//通过 XMLHttpRequest 对象发送 HTTP 请求var xhr = new XMLHttpRequest();xhr.open("POST", "/Home/GetRegion", true);xhr.setRequestHeader("Content-Type", "application/json");xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {var result = JSON.parse(xhr.responseText);var point = "(" + result.Vertices[0].X + "," + result.Vertices[0].Y + ")"var point1 = "(" + result.Vertices[1].X + "," + result.Vertices[1].Y + ")"var point2 = "(" + result.Vertices[2].X + "," + result.Vertices[2].Y + ")"var thtml = "最大空白区域像素数量:" + result.Count + ",\r\n"+ "最大空白区域面积:" + result.Area + ", \n\r"+ "点击点坐标:" + point + ", \n\r"+ "顶点:\r\n左上:" + point1 + ",右下:" + point2 ;desc.innerHTML = thtml;alert(thtml);}};// 传递参数xhr.send(JSON.stringify({ x: x, y: y }));
}
代码解释:
var xhr = new XMLHttpRequest();
xhr.open("POST", "/Home/GetRegion", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () { };
xhr.send(JSON.stringify({ x: x, y: y }));
这段代码是一个通过 XMLHttpRequest
对象发送 HTTP 请求的示例,主要是在浏览器中通过 JavaScript 与服务器进行交互。以下是代码的详细解析:
a、创建一个 XMLHttpRequest
对象:
var xhr = new XMLHttpRequest();
这行代码创建了一个新的 XMLHttpRequest
对象 xhr
。这个对象用于在客户端与服务器之间进行数据交换。
b、配置请求类型和目标 URL:
xhr.open("POST", "/Home/GetRegion", true);
○ “POST”:表示请求方法是 POST
,这意味着数据会被发送到服务器。
○ “/Home/GetRegion”:这是请求的 URL
,表示将向服务器的 /Home/GetRegion
路径发送请求。
○ true:这是一个布尔值,表示请求是异步的。即在发送请求后不会阻塞代码的执行,直到请求完成才会触发回调。
c、设置请求头:
xhr.setRequestHeader("Content-Type", "application/json");
这行代码设置请求的头部,指定请求体的数据格式是 JSON
。这样服务器就知道接收到的数据是 JSON 格式
,需要进行相应的解析。
d、定义请求的回调函数:
xhr.onreadystatechange = function () {};
onreadystatechange
是 XMLHttpRequest
对象的一个事件,当请求的状态发生变化时,会触发该事件。function () {}
是该事件触发时调用的空回调函数。通常在这个回调函数中可以处理请求成功后的操作,如响应的处理。
e、发送请求:
xhr.send(JSON.stringify({ x: x, y: y }));
这行代码使用 send
方法将数据发送给服务器。JSON.stringify({ x: x, y: y })
将x
和y
的值封装成一个 JSON 对象
,并将其转换为字符串后发送到服务器。
后台代码片段
(1)后台代码(接收前台传递点击点坐标):
/// <summary>
/// 获取点击点向四周延展所得连续最大矩形区域面积及顶点坐标
/// </summary>
/// <param name="clickPoint">点击点横纵坐标</param>
/// <returns></returns>
[HttpPost]
public JsonResult GetRegion([System.Web.Http.FromBody] ClickPoint clickPoint)
{//加载图片string path = clickPoint.ImagePath == null ? "/Content/Images/pic.jpg" : clickPoint.ImagePath;string imagePath = Server.MapPath("~" + path);Bitmap image = new Bitmap(imagePath);//获取区域相关信息RegionResult result = FindLargestBlankRegion(image, clickPoint.X, clickPoint.Y);return Json(result);
}
(2)获取顶点坐标及矩形面积计算方法:
/// <summary>
/// 计算顶点坐标及矩形面积
/// </summary>
/// <param name="image">图片信息</param>
/// <param name="startX">起始点X坐标</param>
/// <param name="startY">起始点Y坐标</param>
/// <returns></returns>
private RegionResult FindLargestBlankRegion(Bitmap image, int startX, int startY)
{// 获取 ARGB 值为 #FFFFFFFF 的系统定义的颜色Color emptyColor = Color.White;// 获取图片的宽高int width = image.Width;int height = image.Height;//包含像素数量listList<Point> regionPoints = new List<Point>();// 计算最大区域的四个顶点int minX = startX, maxX = startX, minY = startY, maxY = startY;#region 分别向四个方向扩展//向上扩展for (int i = startY; i >= 0; i--){if (IsEmptyColor(image.GetPixel(startX, i), emptyColor)){minY = i;regionPoints.Add(new Point(startX, i));}else{break;}}//向下扩展for (int i = startY; i < height; i++){if (IsEmptyColor(image.GetPixel(startX, i), emptyColor)){maxY = i;regionPoints.Add(new Point(startX, i));}else{break;}}//向左扩展for (int i = startX; i >= 0; i--){if (IsEmptyColor(image.GetPixel(i, startY), emptyColor)){minX = i;regionPoints.Add(new Point(i, startY));}else{break;}}//向右扩展for (int i = startX; i < width; i++){if (IsEmptyColor(image.GetPixel(i, startY), emptyColor)){maxX = i;regionPoints.Add(new Point(i, startY));}else{break;}}#endregion//计算扩展的矩形区域int areaWidth = maxX - minX;int areaHeight = maxY - minY;int pixelArea = areaWidth * areaHeight;var vertices = new List<Point>{new Point(startX,startY),new Point(minX,minY),new Point(maxX,maxY),};return new RegionResult{Count = regionPoints.Count,//区域所包含像素数Width = areaWidth,//区域宽Height = areaHeight,//区域高Area = pixelArea,//区域面积Vertices = vertices//顶点坐标};
}
(3)其他后台代码:
#region 公共方法/// <summary>
/// 定义颜色比较函数,比较ARGB值是否相等
/// </summary>
/// <param name="color"></param>
/// <param name="emptyColor"></param>
/// <returns></returns>
bool IsEmptyColor(Color color, Color emptyColor)
{return color.ToArgb() == emptyColor.ToArgb();
}#endregion#region Model
public class RegionResult
{public int Width { get; set; }public int Height { get; set; }public int Count { get; set; }public int Area { get; set; }public List<Point> Vertices { get; set; }
}public class ClickPoint
{public int X { get; set; }public int Y { get; set; }public string ImagePath { get; set; }
}
#endregion
考虑到有通过点击用户所上传图片进行相关操作的情况,故而添加了如下上传图片相关代码操作:
上传文件
前台上传图片代码片段
<input type="file" id="fileInput" />
前台上传图片并向后端传递文件方法
//处理图片上传
document.getElementById("fileInput").addEventListener("change", function (e) {const formData = new FormData();var file = e.target.files[0];if (file) {formData.append('file', file);//上传图片到服务器$.ajax({url: "/Home/UploadImage",type: "POST",data: formData,contentType: false,processData: false,success: function (res) {const imgElement = document.getElementById("image");imgElement.src = res.imagePath;//获取并显示上传的文件路径},error: function (xhr, status, error) {console.log("error uploading image: ", error);}});}
});
后台接收图片并上传至服务器
[HttpPost]
public ActionResult UploadImage(HttpPostedFileBase file)
{if (file != null && file.ContentLength > 0){string date = DateTime.Now.Ticks.ToString();// Define the directory to save the uploaded filevar path = Path.Combine(Server.MapPath("~/Content/Upload"), date + "_" + file.FileName);// Save the file to the serverfile.SaveAs(path);// Return the relative path of the saved filereturn Json(new { success = true, imagePath = "/Content/Upload/" + date + "_" + file.FileName });}return Json(new { success = false, message = "No file uploaded." });
}
以上就是大概的解决思路及相关代码,详细代码请移步 Gitee 查看!!!
以上内容均为本人拙见,欢迎大家留言纠正及补充,愿与大家共勉~~~~