近日拿到一個需求,通過分析思考以及查詢資料得以解決,趁著不忙記錄一下:
需求:
頁面上放一個圖片控件,載入圖片之后,點擊圖片任何一個白色空間,找出點擊點所在區域所能容納的最大連續空白矩形面積及頂點坐標。
分析:
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 查看!!!
以上內容均為本人拙見,歡迎大家留言糾正及補充,愿與大家共勉~~~~