#include "pch.h" #include "CvxText.h" #include #include "BaseUtility.h" #include #include using namespace std; using namespace cv; #if defined(GNUC) #pragma GCC diagnostic push #pragma GCC diagnostic ignored “-Wdeprecated-declarations” #elif defined(_MSC_VER) #pragma warning(disable : 4996) #endif void GetStringSize(HDC hDC, const char* str, int* w, int* h) { SIZE size; GetTextExtentPoint32A(hDC, str, strlen(str), &size); if (w != 0) *w = size.cx; if (h != 0) *h = size.cy; } cv::Size GetTextSize(const char* str, int fontSize, const char* fn, bool italic, bool underline) { HDC hDC = CreateCompatibleDC(0); LOGFONTA lf; lf.lfHeight = -fontSize; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 5; lf.lfItalic = italic; //斜体 lf.lfUnderline = underline; //下划线 lf.lfStrikeOut = 0; lf.lfCharSet = DEFAULT_CHARSET; lf.lfOutPrecision = 0; lf.lfClipPrecision = 0; lf.lfQuality = PROOF_QUALITY; lf.lfPitchAndFamily = 0; strcpy_s(lf.lfFaceName, fn); HFONT hf = CreateFontIndirectA(&lf); HFONT hOldFont = (HFONT)SelectObject(hDC, hf); int strBaseW = 0, strBaseH = 0; int singleRow = 0; char buf[1 << 12]; strcpy_s(buf, str); char *bufT[1 << 12]; // 这个用于分隔字符串后剩余的字符,可能会超出。 //处理多行 { int nnh = 0; int cw, ch; const char* ln = strtok_s(buf, "\n", bufT); while (ln != 0) { GetStringSize(hDC, ln, &cw, &ch); strBaseW = max(strBaseW, cw); strBaseH = max(strBaseH, ch); ln = strtok_s(0, "\n", bufT); nnh++; } singleRow = strBaseH; strBaseH *= nnh; } SelectObject(hDC, hOldFont); DeleteObject(hf); DeleteDC(hDC); cv::Size size; size.width = strBaseW; size.height = strBaseH; return size; } void putTextZH(cv::Mat &dst, cv::Size & rSize, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline) { CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3)); int x, y, r, b; if (org.x > dst.cols || org.y > dst.rows) return; x = org.x < 0 ? -org.x : 0; y = org.y < 0 ? -org.y : 0; LOGFONTA lf; lf.lfHeight = -fontSize; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 5; lf.lfItalic = italic; //斜体 lf.lfUnderline = underline; //下划线 lf.lfStrikeOut = 0; lf.lfCharSet = DEFAULT_CHARSET; lf.lfOutPrecision = 0; lf.lfClipPrecision = 0; lf.lfQuality = PROOF_QUALITY; lf.lfPitchAndFamily = 0; strcpy_s(lf.lfFaceName, fn); HFONT hf = CreateFontIndirectA(&lf); HDC hDC = CreateCompatibleDC(0); HFONT hOldFont = (HFONT)SelectObject(hDC, hf); int strBaseW = 0, strBaseH = 0; int singleRow = 0; char buf[1 << 12]; strcpy_s(buf, str); char *bufT[1 << 12]; // 这个用于分隔字符串后剩余的字符,可能会超出。 //处理多行 { int nnh = 0; int cw, ch; const char* ln = strtok_s(buf, "\n", bufT); while (ln != 0) { GetStringSize(hDC, ln, &cw, &ch); strBaseW = max(strBaseW, cw); strBaseH = max(strBaseH, ch); ln = strtok_s(0, "\n", bufT); nnh++; } singleRow = strBaseH; strBaseH *= nnh; } rSize.width = strBaseW; rSize.height = strBaseH; if (org.x + strBaseW < 0 || org.y + strBaseH < 0) { SelectObject(hDC, hOldFont); DeleteObject(hf); DeleteObject(hDC); return; } r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1; b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1; org.x = org.x < 0 ? 0 : org.x; org.y = org.y < 0 ? 0 : org.y; BITMAPINFO bmp = { 0 }; BITMAPINFOHEADER& bih = bmp.bmiHeader; int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4)); bih.biSize = sizeof(BITMAPINFOHEADER); bih.biWidth = strBaseW; bih.biHeight = strBaseH; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = BI_RGB; bih.biSizeImage = strBaseH * strDrawLineStep; bih.biClrUsed = 0; bih.biClrImportant = 0; void* pDibData = 0; HBITMAP hBmp = CreateDIBSection(hDC, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0); CV_Assert(pDibData != 0); HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp); //color.val[2], color.val[1], color.val[0] SetTextColor(hDC, RGB(255, 255, 255)); SetBkColor(hDC, 0); //SetStretchBltMode(hDC, COLORONCOLOR); strcpy_s(buf, str); const char* ln = strtok_s(buf, "\n", bufT); int outTextY = 0; while (ln != 0) { TextOutA(hDC, 0, outTextY, ln, strlen(ln)); outTextY += singleRow; ln = strtok_s(0, "\n", bufT); } uchar* dstData = (uchar*)dst.data; int dstStep = dst.step / sizeof(dstData[0]); unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep; unsigned char* pStr = (unsigned char*)pDibData + x * 3; for (int tty = y; tty <= b; ++tty) { unsigned char* subImg = pImg + (tty - y) * dstStep; unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep; for (int ttx = x; ttx <= r; ++ttx) { for (int n = 0; n < dst.channels(); ++n) { double vtxt = subStr[n] / 255.0; int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n]; subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv); } subStr += 3; subImg += dst.channels(); } } SelectObject(hDC, hOldBmp); SelectObject(hDC, hOldFont); DeleteObject(hf); DeleteObject(hBmp); DeleteDC(hDC); } ///////////////////////////// 数据收集卡 /////////////////////////////////////// // 获取字符串的画布上的宽度 int getLineStrWidth(string str, int fontSize, int ttBoxW, int tiSl, int backPix) { int iw = str.length()*fontSize*0.5; iw += ttBoxW; iw += tiSl; iw += backPix; iw += fontSize * 1.5; // 题号的宽度 最多不超过1.5个字体宽度 56. return iw; } // 转码 utf-8 2 ansi static void UTF82ANSI(LPCSTR lpBuff, int nLen, char* pData, int iMaxLen) { ZeroMemory(pData, sizeof(char)*iMaxLen); int nCont = MultiByteToWideChar(CP_UTF8, 0, lpBuff, nLen, NULL, 0); WCHAR* szTemp = new WCHAR[nCont + 1]; ZeroMemory(szTemp, sizeof(WCHAR)*(nCont + 1)); MultiByteToWideChar(CP_UTF8, 0, lpBuff, nLen, szTemp, nCont); //获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的 int len = WideCharToMultiByte(CP_ACP, 0, szTemp, nCont, NULL, 0, NULL, NULL); if (len < iMaxLen) { WideCharToMultiByte(CP_ACP, 0, szTemp, nCont, pData, len, NULL, NULL); } else { char* buffer = new char[len + 1]; //宽字节编码转换成多字节编码 WideCharToMultiByte(CP_ACP, 0, szTemp, nCont, buffer, len, NULL, NULL); buffer[len] = '\0'; //删除缓冲区并返回值 strncpy(pData, buffer, iMaxLen - 1); delete[] buffer; buffer = NULL; } delete[]szTemp; szTemp = NULL; } // 二进制码生成获取 void createBinString(Mat & img, int pageNum, int ptw, int pth, cv::Point ptStart, vector& vecBoxPages) { vector vecBinStr; vecBinStr.resize(12); for (size_t i = 11; i > 0; i--) { int ys = pageNum % 2; vecBinStr[i] = ys; pageNum = pageNum / 2; } vecBoxPages.clear(); int ptPgW = ptw / 2; int ptPgH = pth / 2; for (int j = 0; j < 3; j++) { int _startY = ptStart.y + 15 + 50 * j; for (int i = 0; i < 4; i++) { int _startX = ptStart.x + 18 + i * 72; vecBoxPages.push_back(cv::Rect(_startX, _startY, ptPgW, ptPgH)); if (vecBinStr[j * 4 + i]) rectangle(img, vecBoxPages[vecBoxPages.size() - 1], cv::Scalar(0), -1); else rectangle(img, vecBoxPages[vecBoxPages.size() - 1], cv::Scalar(200, 200, 200), 2, 8, 0); } } return; } void generatePageJson(vector& vecPts, vector& vecBoxPages) { Json::Value imageSize; imageSize["width"] = 1654; imageSize["height"] = 2344; Json::Value location(Json::arrayValue); for (auto& iter : vecPts) { Json::Value item; item["x"] = iter.x; item["y"] = iter.y; item["width"] = iter.width; item["height"] = iter.height; location.append(item); } Json::Value pagenumber(Json::arrayValue); int nSubVecSize = 4;// 每个小vector的容量 for (size_t i = 0, j = 1; i < vecBoxPages.size(); i += nSubVecSize) { vector vecSmall; auto last = std::min(vecBoxPages.size(), i + nSubVecSize); vecSmall.insert(vecSmall.begin(), vecBoxPages.begin() + i, vecBoxPages.begin() + last); Json::Value opt(Json::arrayValue); std::string choice[] = { "A", "B", "C", "D" }; for (int h = 0; h < vecSmall.size(); h++) { Json::Value bin; bin["x"] = vecSmall[h].x; bin["y"] = vecSmall[h].y; bin["width"] = vecSmall[h].width; bin["height"] = vecSmall[h].height; bin["optName"] = choice[h]; opt.append(bin); } Json::Value item; item["id"] = j; item["opt"] = opt; pagenumber.append(item); j++; } Json::Value itemRoot; itemRoot["imageSize"] = imageSize; itemRoot["location"] = location; itemRoot["pagenumber"] = pagenumber; Json::FastWriter writer; std::string strJson = writer.write(itemRoot); CFile zip; zip.Open(_T("D:\\page.json"), CFile::modeCreate | CFile::modeWrite); DWORD wide_string_len = MultiByteToWideChar(CP_ACP, 0, strJson.c_str(), -1, NULL, 0); WCHAR* wide_string = new WCHAR[wide_string_len]; wide_string_len = MultiByteToWideChar(CP_ACP, 0, strJson.c_str(), -1, wide_string, wide_string_len); DWORD utf8_string_len = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, NULL, 0, NULL, NULL); CHAR* utf8_string = new CHAR[utf8_string_len]; utf8_string_len = WideCharToMultiByte(CP_UTF8, 0, wide_string, -1, utf8_string, utf8_string_len, NULL, NULL); zip.Write((void*)utf8_string, utf8_string_len - 1); // LOG4CPLUS_INFO_FMT(pTestLogger, LOG4CPLUS_TEXT("%s"), CString(json_str.c_str())); delete wide_string; delete utf8_string; zip.Close(); } std::string JsonToString(const Json::Value & root) { static Json::Value def = []{ Json::Value def; Json::StreamWriterBuilder::setDefaults(&def); def["emitUTF8"] = true; return def; }(); std::ostringstream stream; Json::StreamWriterBuilder stream_builder; stream_builder.settings_ = def;//Config emitUTF8 std::unique_ptr writer(stream_builder.newStreamWriter()); writer->write(root, &stream); return stream.str(); } int dataCollectionPaper(int cols, int index, int fontSize, int lineGrayPix, bool engShow, std::vector& vecLines, CString dir, std::string& strPngPath) { /* 这里要做一些栏数 和 vecLines的对应值确认 */ if (2 == cols && 14 * 2 == vecLines.size()) ; // ok if (3 == cols && 14 * 3 == vecLines.size()) ; // ok if (4 == cols && 14 * 4 == vecLines.size()) ; // ok // 生成画布图像 cv::Mat img(cv::Size(1654, 2344), CV_8UC3, cv::Scalar(255, 255, 255)); int ptw = 80; int pth = 40; cv::Size fSize(0, 0); int leftPos = 100, rightPos = 1450; int topPos = 90; int fontW = rightPos - leftPos + ptw; vector vecPts = { cv::Rect(100,90,ptw,pth), cv::Rect(580,90,ptw,pth), cv::Rect(1450,90,ptw,pth), cv::Rect(100,2176,ptw,pth), cv::Rect(1450,2176,ptw,pth), }; // 画定位点 for (size_t i = 0; i < vecPts.size(); i++) { rectangle(img, vecPts[i], cv::Scalar(0, 0, 0), -1); } // 画示例框 topPos += pth; topPos += 30; rectangle(img, cv::Rect(leftPos, topPos, fontW, 200), cv::Scalar(0, 0, 0), 2, 8, 0); // 画页码框 cv::Rect boxPageNumber(leftPos + fontW - 300, topPos, 300, 200); rectangle(img, boxPageNumber, cv::Scalar(0, 0, 0), 2, 8, 0); // 生成二进制码流 /* 二进制码流的坐标在下面函数里面实现,需要用书写获取 */ vector vecBoxPages; createBinString(img, index, ptw, pth, cv::Point(boxPageNumber.x, boxPageNumber.y), vecBoxPages); string strPageNumInfo = "关联ID: " + to_string(index); putTextZH(img, fSize, strPageNumInfo.c_str(), cv::Point(boxPageNumber.x + 100, boxPageNumber.y + 50 * 2 + 20 + 15 + 15 + 15), Scalar(0), 20, "宋体"); // 生成page.json //generatePageJson(vecPts, vecBoxPages); // 画警示信息 string strMesInfo = "1、请在每题下方的横线上书写本题的内容!\ \n\n2、题号不需要书写,标点符号需要原样书写。☆\ \n\n3、如果本题书写有误,进行了涂抹修改等操作,请将题号前矩形框用任意笔进行填涂!☆☆\n"; putTextZH(img, fSize, strMesInfo.c_str(), cv::Point(leftPos + 20, topPos + 20), Scalar(0), 25, "宋体"); int lineTop1 = topPos + 20 + fSize.height + 20; cv::line(img, cv::Point(leftPos, lineTop1), cv::Point(rightPos + ptw - 300, topPos + 20 + fSize.height + 20), Scalar(0), 2, 8, 0); // 正确示例 string strEgInfo = "正\n确\n示\n例"; putTextZH(img, fSize, strEgInfo.c_str(), cv::Point(leftPos + 20, topPos + 20 + fSize.height + 20 + 3), Scalar(0), 20, "宋体"); cv::line(img, cv::Point(leftPos + 20 + fSize.width + 10, lineTop1), cv::Point(leftPos + 20 + fSize.width + 10, topPos + 200), Scalar(0, 0, 0), 2, 8, 0); // 贴图区域 /* 暂不实现 */ topPos += 200; // 文字区域 static int maxLineNum = 14; // 最大行数14 static int ttBoxWidth = 30; // 填涂框的边长 static int tiSl = 10; // 题号和题干间的距离 static int lineDis = 20; // 两行之间的距离 int colWidth = fontW / cols; // 单栏的宽度 fSize.width = 0; fSize.height = 0; Json::Value root(Json::arrayValue); for (int col = 0; col < cols; col++) { // 逐栏画题 int colTopPos = topPos; int colLeftPos = leftPos + col * colWidth; for (size_t i = 0; i < maxLineNum; i++) { size_t vecIndex = i + col * maxLineNum; if (vecIndex >= vecLines.size()) { break; } colTopPos += lineDis; int lineLen = ttBoxWidth + tiSl; // 画填涂框 30*30 大小 cv::Rect rcbox(colLeftPos, colTopPos, ttBoxWidth, ttBoxWidth); rectangle(img, rcbox, cv::Scalar(0), 1, 8, 0); int iQNum = i + 1 + col * maxLineNum; string strStinfo = to_string(iQNum); strStinfo += "."; cv::Point ptNum(colLeftPos + ttBoxWidth + tiSl, colTopPos); putTextZH(img, fSize, strStinfo.c_str(), ptNum, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离 lineLen += fSize.width; cv::Rect rcNum(ptNum.x, ptNum.y, fSize.width, fSize.height); strStinfo.clear(); string strTgInfo = vecLines[vecIndex]; if (!engShow) ; /* 移除词性 */ //char szTemp[2048]; //memset(szTemp, 0, sizeof(char)*(2048)); //UTF82ANSI(strTgInfo.c_str(), strTgInfo.length(), szTemp, 2048); //strTgInfo = szTemp; cv::Point ptQues(colLeftPos + ttBoxWidth + tiSl + fSize.width, colTopPos); putTextZH(img, fSize, strTgInfo.c_str(), ptQues, Scalar(0, 0, 0), fontSize, "宋体"); // 跟填涂框保持10px距离 lineLen += fSize.width; cv::Rect rcQues(ptQues.x, ptQues.y, fSize.width, fSize.height); cv::Rect rcAns(colLeftPos + 30, colTopPos + fSize.height, colWidth - ttBoxWidth, 1); colTopPos = colTopPos + fSize.height * 3.5; //两行之间两倍的距离用于书写 line(img, cv::Point(colLeftPos + 30, colTopPos), cv::Point(colLeftPos + colWidth - 1, colTopPos), Scalar(lineGrayPix, lineGrayPix, lineGrayPix), 1, 8, 0); rcAns.height = colTopPos - rcAns.y + lineDis; //生成识别信息 Json::Value ttbox; ttbox["x"] = rcbox.x; ttbox["y"] = rcbox.y; ttbox["width"] = rcbox.width; ttbox["height"] = rcbox.height; Json::Value queNum; queNum["x"] = rcNum.x; queNum["y"] = rcNum.y; queNum["width"] = rcNum.width; queNum["height"] = rcNum.height; Json::Value queInfo; queInfo["x"] = rcQues.x; queInfo["y"] = rcQues.y; queInfo["width"] = rcQues.width; queInfo["height"] = rcQues.height; queInfo["info"] = strTgInfo.c_str(); Json::Value ansInfo; ansInfo["x"] = rcAns.x; ansInfo["y"] = rcAns.y; ansInfo["width"] = rcAns.width; ansInfo["height"] = rcAns.height; Json::Value item; item["id"] = iQNum; item["ttbox"] = ttbox; item["queNum"] = queNum; item["queInfo"] = queInfo; item["ansInfo"] = ansInfo; root.append(item); // test /*rectangle(img, rcbox, cv::Scalar(0, 0, 200), 1, 8, 0); rectangle(img, rcNum, cv::Scalar(0, 200, 0), 1, 8, 0); rectangle(img, rcQues, cv::Scalar(100, 0, 0), 1, 8, 0); rectangle(img, rcAns, cv::Scalar(200, 0, 0), 1, 8, 0);*/ } } std::string strJson = JsonToString(root); CString strTemplatePath; strTemplatePath.Format(L"%s/json/%d.json", dir, index); CFile zip; zip.Open(strTemplatePath, CFile::modeCreate | CFile::modeWrite); zip.Write((void*)strJson.c_str(), strJson.length()); zip.Close(); wchar_t tempPath[MAX_PATH]; DWORD dwSize = MAX_PATH; GetTempPath(dwSize, tempPath);//获取临时文件夹路径 static int tmp_index = 1; wchar_t szPath[MAX_PATH]; _stprintf(szPath, L"%stmp_%d.png", tempPath, tmp_index); tmp_index++; if (tmp_index > 10) { tmp_index = 1; } strPngPath = TstringToGB2312(szPath); cv::imwrite(strPngPath, img); /*cv::namedWindow("fuck", 1); cv::imshow("fuck", img); cv::waitKey(0);*/ return 0; } int get_gray_num(cv::Mat & img, cv::Rect & box, int &meanGray, int threshold) { uchar * ptr; int count = 0; long long totalGrayNum = 0; for (int h = box.y; h < box.y + box.height; h++) { ptr = img.ptr(h); for (int w = box.x; w < box.x + box.width; w++) { int pix = static_cast(ptr[w]); totalGrayNum += pix; if (pix < threshold) count++; } } meanGray = totalGrayNum / box.area(); return count; } int get_around_box_gray(cv::Mat & img, cv::Rect & box) { int left = (box.x - box.width / 2) > 0 ? (box.x - box.width / 2) : 0; int top = (box.y - box.height / 2) > 0 ? (box.y - box.height / 2) : 0; int right = (box.x + box.width * 3 / 2) < (img.cols - 1) ? (box.x + box.width * 3 / 2) : (img.cols - 1); int bottom = (box.y + box.height * 3 / 2) < (img.rows - 1) ? (box.y + box.height * 3 / 2) : (img.rows - 1); uchar * ptr; std::int64_t total = 0; int number = 0; for (int h = top; h < bottom; h++) { ptr = img.ptr(h); for (int w = left; w < right; w++) { if (w > box.x && w<(box.x + box.width) && h>box.y&&h < (box.y + box.height)) continue; total += static_cast(ptr[w]); number++; } } return static_cast(total / number); } #define USE_THRESHOLD_VAL 200 bool analysis_ttbox_mark(cv::Mat & imgSrc, cv::Rect & rc) { int thre = min(200, max(get_around_box_gray(imgSrc, rc), 160)); int gray = get_gray_num(imgSrc, rc, thre, USE_THRESHOLD_VAL); double ds = gray * 1.0 / rc.area()*1.0; if (ds > 0.50) return true; return false; } int cutPaper(int pageNum, std::string strJsonPath, std::string strPaperPath, std::string strSavePath) { ifstream in(strJsonPath, ios::binary); if (!in.is_open()) { return 1; } Json::Features features; Json::Reader reader(features); Json::Value root; if (!reader.parse(in, root)) { return 1; } if (!root.isArray()) { return 1; } cv::Mat src = cv::imread(strPaperPath); if (src.empty()) { return 1; } auto pfGetPos = [](const Json::Value & value, cv::Rect& rc) { int x = 0, y = 0, w = 0, h = 0; if (value.isMember("x")) { x = value["x"].asInt(); } if (value.isMember("y")) { y = value["y"].asInt(); } if (value.isMember("width")) { w = value["width"].asInt(); } if (value.isMember("height")) { h = value["height"].asInt(); } rc = cv::Rect(x, y, w, h); }; for (int i = 0; i < root.size(); i++) { Json::Value row = root[i]; std::string id = row["id"].asString(); std::string info = row["queInfo"]["info"].asString(); Json::Value ttbox = row["ttbox"]; Json::Value ansInfo = row["ansInfo"]; cv::Rect rc_ttbox; cv::Rect rc_ansInfo; pfGetPos(ttbox, rc_ttbox); pfGetPos(ansInfo, rc_ansInfo); // 选择框灰度判断 bool ret = analysis_ttbox_mark(src, rc_ttbox); char szTxtPath[MAX_PATH] = { 0 }; char szJpgPath[MAX_PATH] = { 0 }; DWORD dwCount = GetTickCount(); sprintf(szTxtPath, "%s\\%s\\%d_%s_%ld.txt", strSavePath.c_str(), ret ? "abnormal" : "normal", pageNum, id.c_str(), dwCount); sprintf(szJpgPath, "%s\\%s\\%d_%s_%ld.jpg", strSavePath.c_str(), ret ? "abnormal" : "normal", pageNum, id.c_str(), dwCount); CFile zip; zip.Open(CA2T(szTxtPath), CFile::modeCreate | CFile::modeWrite); zip.Write((void*)info.c_str(), info.length()); zip.Close(); cv::Mat cut = src(rc_ansInfo); ret = cv::imwrite(szJpgPath, cut); return ret ? 0 : 1; } return 0; } int PareseModeJson(preinfo::templatesInfo& temeplatInfo) { ifstream in("./page.json", ios::binary); if (!in.is_open()) { return 1; } int uuid = 100000; /// 每个框子的一个独立ID 不会有重复的 Json::Features features; Json::Reader reader(features); Json::Value root; if (!reader.parse(in, root)) { return 1; } if (!root.isObject()) { return 1; } //1.获取模板大小信息 preinfo::PaperTemplateInfo page; Json::Value imageSize = root["imageSize"]; page.height = imageSize["height"].asInt(); page.width = imageSize["width"].asInt(); //2.获取定位点信息 Json::Value loction = root["location"]; auto funGetPos = [&](Json::Value item) { preinfo::PaperRect pb; int x = item["x"].asInt(); int y = item["y"].asInt(); int h = item["height"].asInt(); int w = item["width"].asInt(); pb.centerx = x + w / 2.0; pb.centery = y + h / 2.0; pb.width = w; pb.height = h; return pb; }; double offsetx = page.width; double offsety = page.height; for (int i = 0; i < loction.size(); i++) { Json::Value row = loction[i]; preinfo::LocationPoint lc; lc.id = uuid++; auto tm = funGetPos(row); lc.centerx = tm.centerx; lc.centery = tm.centery; lc.width = tm.width; lc.height = tm.height; if (offsetx > lc.centerx) offsetx = lc.getX(); if (offsety > lc.centery) offsety = lc.getY(); page.vecLocaltionPoints.push_back(lc); } //3.获取客观题信息 Json::Value pagenumber = root["pagenumber"]; for (int i = 0; i < pagenumber.size(); i++) { Json::Value item = pagenumber[i]; string strId = item["id"].asString(); preinfo::_QuestionChoice _qstc; _qstc.id = uuid++; _qstc.vecTiHao.push_back(atoi(strId.c_str())); double dBoundBox[4] = { 100000,100000,0,0 }; _qstc.type = preinfo::BOX_QUESTION_CHOICE_M; auto itOpts = item["opt"]; _qstc.number = itOpts.size(); std::vector _vctOpt; for (int i = 0; i < itOpts.size(); i++) { preinfo::TtItem opt; auto tm = funGetPos(itOpts[i]); opt.centerx = tm.centerx; opt.centery = tm.centery; opt.width = tm.width; opt.height = tm.height; _qstc.itemSize.width = opt.width; _qstc.itemSize.height = opt.height; dBoundBox[0] = dBoundBox[0] > opt.getX() ? opt.getX() : dBoundBox[0]; dBoundBox[1] = dBoundBox[1] > opt.getY() ? opt.getY() : dBoundBox[1]; dBoundBox[2] = dBoundBox[2] < (opt.centerx + opt.width / 2.0) ? (opt.centerx + opt.width / 2.0) : dBoundBox[2]; dBoundBox[3] = dBoundBox[3] < (opt.centery + opt.height / 2.0) ? (opt.centery + opt.height / 2.0) : dBoundBox[3]; auto subItem = itOpts[i]; opt.optName = subItem["optName"].asString(); _vctOpt.push_back(opt); } _qstc.width = (dBoundBox[2] - dBoundBox[0]); _qstc.height = (dBoundBox[3] - dBoundBox[1]); _qstc.centerx = dBoundBox[0] + _qstc.width / 2.0; _qstc.centery = dBoundBox[1] + _qstc.height / 2.0; _qstc.groups = _vctOpt; page._vecQtChoices.push_back(_qstc); } temeplatInfo.push_back(page); return 0; }