using DaJiaoYan.Models; using DaJiaoYan.Utils; using DaJiaoYan.Variables; using OpenCvSharp; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using static DaJiaoYan.Models.PartitionConfig; namespace DaJiaoYan.Services { struct ScanResult { public string Filename; public int Index; } internal class PingHandler : HttpHandler { private ResponseData pongResponse = new ResponseData { Code = 200, Data = "pong" }; public PingHandler(AsyncHttpServer httpServer) : base(httpServer) { } public override void Get(HttpListenerRequest request, HttpListenerResponse response) { Json(ref response, ref pongResponse); } } internal class ScannerHandler : HttpHandler { public ScannerHandler(AsyncHttpServer httpServer) : base(httpServer) { } public override void Get(HttpListenerRequest request, HttpListenerResponse response) { ResponseData result = new ResponseData { Code = 200, Data = Variables.Vars.Scanners }; Json(ref response, ref result); } } public class ScanHandler : HttpHandler { public ScanHandler(AsyncHttpServer httpServer) : base(httpServer) { } public override async void Post(HttpListenerRequest request, HttpListenerResponse response) { ResponseData result = new ResponseData { Code = 200 }; var form = this.HttpServer.ParseForm(ref request); form.TryGetValue("scanner", out string scanner); var files = new List(); var finished = false; result.Data = files; if (string.IsNullOrEmpty(scanner)) { result.Code = 400; result.Errors = "请选择扫描仪"; finished = true; } else if (!Vars.Scanners.Contains(scanner)) { result.Code = 400; result.Errors = "请选择正确的扫描仪"; finished = true; } else if (Scan.State == Scan.ScannerState.Running) { result.Code = 400; result.Errors = "正在扫描中"; finished = true; } else { ScanTask scanTask = new ScanTask { Scanner = scanner, ImageDpi = 200, ImageSuffix = "png", Colorful = true, Path = Const.TMP_PATH, CapXferCount = 2, OnScanBegin = (bool begin, string err) => { if (!begin) { result.Code = 400; result.Errors = err; finished = true; } }, OnDeleScanFileCompleted = (string f, int index) => { try { Mat img = Cv2.ImRead(f); if (img != null && img.Channels() > 1) { ImageUtils.Red2OtherColor(ref img, Scalar.Black); Mat dstImg = new Mat(img.Size(), MatType.CV_8UC1); Cv2.CvtColor(img, dstImg, ColorConversionCodes.BGR2GRAY); Cv2.ImWrite(f, dstImg); dstImg.Dispose(); } files.Add(ImageUtils.ToBase64(f)); img?.Dispose(); } catch { } }, OnScanTaskCompleted = () => { result.Code = 200; finished = true; }, OnScannerError = () => { result.Code = 200; result.Errors = "扫描出错!"; finished = true; } }; Scan.Start(scanTask); while (!finished || files.Count < 2) { await Task.Delay(100); } } Json(ref response, ref result); } } public class UploadHandler : HttpHandler { public UploadHandler(AsyncHttpServer httpServer) : base(httpServer) { } /// /// 扫描图片上传接口 /// /// /// public override async void Post(HttpListenerRequest request, HttpListenerResponse response) { ResponseData result = new ResponseData { Code = 200 }; int ocrVer = 0; var form = this.HttpServer.ParseForm(ref request); form.TryGetValue("token", out string token); form.TryGetValue("type", out string type); form.TryGetValue("school_id", out string school_id); form.TryGetValue("campus_id", out string campus_id); form.TryGetValue("class_id", out string class_id); form.TryGetValue("test_id", out string test_id); form.TryGetValue("subject_id", out string subject_id); form.TryGetValue("is_school_no", out string is_school_no); form.TryGetValue("sign_weight", out string sign_weight); form.TryGetValue("marking_type", out string marking_type); form.TryGetValue("scanner", out string scanner); form.TryGetValue("directory", out string directory); form.TryGetValue("ver", out string ver); if (!string.IsNullOrEmpty(ver)) { int.TryParse(ver, out ocrVer); } UploadHandlerPostParam param = new UploadHandlerPostParam( token, type, school_id, campus_id, class_id, test_id, subject_id, is_school_no, sign_weight, scanner, directory, marking_type, ocrVer ); if (param.GetErrorType != UploadHandlerPostParam.ErrorType.None) { result.Code = 400; result.Errors = param.ErrorMessage; } else { var divideConfig = await Api.GetDividePartitionConfig(param.TestId, param.Token); if (param.Type == UploadHandlerPostParam.UploadType.Scan) { if (Scan.State == Scan.ScannerState.Running) { result.Code = 400; result.Errors = "正在扫描中,请稍候"; } if (string.IsNullOrEmpty(scanner)) { result.Code = 400; result.Errors = "请选择扫描仪"; param.ScanFinish = true; } else if (!Vars.Scanners.Contains(scanner)) { result.Code = 400; result.Errors = "请选择正确的扫描仪"; param.ScanFinish = true; } else { AliyunOssClient ossClient = new AliyunOssClient(param.Token); if (!ossClient.AccessAvailable) { result.Code = 400; result.Errors = "没有上传权限,请检查"; } else { string batchId = Functions.GenUUID(); string uploadTaskInfoId = batchId; result.Data = batchId; UploadTask.deleNewUploadTask(uploadTaskInfoId); string path = Path.Combine(Const.TMP_PATH, campus_id.ToString(), test_id.ToString(), batchId); FileExts.CheckDirectory(path, true); param.Directory = path; object _locker = new object(); ScanResultPost scanResult = new ScanResultPost(param); //List files = new List(); List scanFiles = new List(); int n = 0, finished = 0; const int BATCH_SIZE = 2; //扫描1张就上传 bool uploadImage(string ossFn, string fn) { bool res = false; if (scanResult.MarkingType == UploadHandlerPostParam.MarkType.OnlineMarking) { try { Mat img = Cv2.ImRead(fn); if (img != null && img.Channels() > 1) { Mat dstImg = new Mat(img.Size(), MatType.CV_8UC1); Cv2.CvtColor(img, dstImg, ColorConversionCodes.BGR2GRAY); Cv2.ImWrite(fn, dstImg); img.Dispose(); dstImg.Dispose(); } img?.Dispose(); } catch { } } res = ossClient.SimpleUpload(ossFn, fn); UploadTask.deleIncreaseUploadTask(uploadTaskInfoId); return res; } async void uploadedFilenames() { //Console.WriteLine($"n={n}, total={scanResult.Total}, finish={scanResult.Finish}"); if (n >= BATCH_SIZE || scanResult.Finish) { List tasks = new List(); ScanResultPost sr = new ScanResultPost(param); lock (_locker) { sr.Finish = scanResult.Finish; sr.Total = scanResult.Total; sr.BatchId = scanResult.BatchId; } for (int i = sr.Total - n; i < sr.Total; i++) { int idx = i; ScanResultPost.ImageInfo info = new ScanResultPost.ImageInfo() { Image = scanFiles[idx].Filename, HasError = 1, Index = scanFiles[idx].Index }; sr.Images.Add(info); tasks.Add(Task.Run(() => { if (uploadImage(scanFiles[idx].Filename, Path.Combine(path, Path.GetFileName(scanFiles[idx].Filename)))) { info.HasError = 0; } })); } n = 0; await Task.Factory.StartNew(async () => { await Task.WhenAll(tasks.ToArray()); // 上传图片地址 await Api.PostExaminationScanResult(sr, param.Token); Vars.UploadedCounterIncrease(tasks.Count); lock (_locker) { finished += BATCH_SIZE; } //UploadTask.deleIncreaseUploadTask(uploadTaskInfoId, BATCH_SIZE); }); } } ScanTask scanTask = new ScanTask { Scanner = scanner, ImageDpi = 200, ImageSuffix = "jpg", Colorful = param.MarkingType == UploadHandlerPostParam.MarkType.LocalMarking || (divideConfig != null && !divideConfig.Template.MarkingOnLine), Path = path, CapXferCount = -1, OnScanBegin = (bool begin, string err) => { if (!begin) { result.Code = 400; result.Errors = err; scanResult.Finish = true; } }, OnDeleScanFileCompleted = (string f, int index) => { try { Task.Factory.StartNew(() => { string originFilename = Functions.GenUploadOriginImageName(param.TestId, param.CampusId, f, scanResult.BatchId); lock (_locker) { //files.Add(originFilename); scanFiles.Add(new ScanResult { Filename = originFilename, Index = index }); n++; scanResult.Total++; } UploadTask.deleIncreaseScanTask(uploadTaskInfoId, 1); uploadedFilenames(); }); } catch { } }, OnScanTaskCompleted = async () => { result.Code = 200; if (scanFiles.Count > 0) { while (finished < scanResult.Total) { await Task.Delay(1000); } } scanResult.Finish = true; UploadTask.deleFinishScanTask(uploadTaskInfoId); }, OnScannerError = () => { result.Code = 200; result.Errors = "扫描出错!"; scanResult.Finish = true; } }; await Task.Factory.StartNew(async () => { Scan.Start(scanTask); Vars.SetTaskStatus(batchId, false); while (!scanResult.Finish) { await Task.Delay(100); } uploadedFilenames(); Vars.SetTaskStatus(batchId, true); UploadTask.deleFinishUploadTask(uploadTaskInfoId); }); } } } else { int answerSheetsLength = 2; if (divideConfig != null) { answerSheetsLength = divideConfig.AnswerSheets.Length; } // 上传文件夹 List files = FileExts.GetImageFiles(param.Directory); if (divideConfig != null && files.Count > 0 && answerSheetsLength > 0 && files.Count % answerSheetsLength != 0) { result.Code = 400; result.Errors = "本地答卷数量与模板数量不一致,请核查"; } else if (files.Count > 0) { AliyunOssClient ossClient = new AliyunOssClient(param.Token); if (!ossClient.AccessAvailable) { result.Code = 400; result.Errors = "没有上传权限,请检查"; } else { const int BATCH_SIZE = 4; //作为一个批次上传的图片数量 string uploadTaskInfoId = Functions.GenUUID(); UploadTask.deleNewUploadTask(uploadTaskInfoId); UploadTask.deleIncreaseScanTask(uploadTaskInfoId, files.Count); UploadTask.deleFinishScanTask(uploadTaskInfoId); result.Data = uploadTaskInfoId; int n = 0, idx = 0; ScanResultPost scanResult = new ScanResultPost(param) { Total = files.Count }; bool uploadImage(string ossFn, string fn) { bool res = false; MemoryStream ms = new MemoryStream(); string suffix = Path.GetExtension(fn).ToLower(); ImageEncodingParam imageEncodingParam = Vars.IMAGE_SAVE_PNG_PARAM; Mat img; if (suffix.Equals(".jpeg", StringComparison.OrdinalIgnoreCase) || suffix.Equals(".jpg", StringComparison.OrdinalIgnoreCase)) { imageEncodingParam = Vars.IMAGE_SAVE_JPEG_PARAM; } if (scanResult.MarkingType == UploadHandlerPostParam.MarkType.LocalMarking || (divideConfig != null && !divideConfig.Template.MarkingOnLine)) { img = ImageUtils.Read(fn); } else { img = ImageUtils.Read(fn, ImreadModes.Grayscale); } if (img != null) { ms = img.ToMemoryStream(suffix, imageEncodingParam); res = ossClient.SimpleUpload(ossFn, ms); img?.Dispose(); ms?.Dispose(); } return res; } async Task uploadedFilenames() { //Console.WriteLine($"n={n}, total={scanResult.Total}, finish={scanResult.Finish}"); List tasks = new List(); if (n >= BATCH_SIZE || scanResult.Finish) { scanResult.Images.Clear(); for (int i = 0; idx < scanResult.Total && i < n; i++) { int _k = idx; string originImageFilename = Functions.GenUploadOriginImageName(scanResult.TestId, scanResult.CampusId, files[_k], scanResult.BatchId); ScanResultPost.ImageInfo info = new ScanResultPost.ImageInfo() { Image = originImageFilename, HasError = 1 }; scanResult.Images.Add(info); tasks.Add(Task.Run(() => { if (uploadImage(originImageFilename, files[_k])) { Console.WriteLine($"{originImageFilename} uploaded."); info.HasError = 0; info.Index = _k + 1; UploadTask.deleIncreaseUploadTask(uploadTaskInfoId); } })); idx++; } n = 0; } Task.WaitAll(tasks.ToArray()); // 上传图片地址 await Api.PostExaminationScanResult(scanResult, param.Token); Vars.UploadedCounterIncrease(tasks.Count); } _ = Task.Factory.StartNew(async () => { string batchId = scanResult.BatchId; Vars.SetTaskStatus(batchId, false); for (int i = 0; i < files.Count; i += BATCH_SIZE) { n = BATCH_SIZE; await uploadedFilenames(); await Task.Delay(100); } scanResult.Finish = true; n = BATCH_SIZE; await uploadedFilenames(); Vars.SetTaskStatus(batchId, true); UploadTask.deleFinishUploadTask(uploadTaskInfoId); }); } } else { result.Code = 400; result.Errors = "没有可上传的图片"; } } } Json(ref response, ref result); } public override void Get(HttpListenerRequest request, HttpListenerResponse response) { ResponseData result = new ResponseData { Code = 200 }; string id = request.QueryString.Get("id"); result.Data = UploadTask.deleGetUploadTask(id); Json(ref response, ref result); } } }