DocScannerCap.cpp 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. #include "stdafx.h"
  2. #include "DocScannerCap.h"
  3. #include "math.h"
  4. //template<typename T>
  5. //struct identity
  6. //{
  7. // typedef T type;
  8. //};
  9. //#define X(F, T) identity<T>::type& F = *reinterpret_cast<identity<T>::type*>( \
  10. // GetProcAddress(GetModuleHandle("user32.dll"), #F))
  11. //X(RegisterDeviceNotification, HDEVNOTIFY WINAPI(
  12. // IN HANDLE hRecipient,IN LPVOID NotificationFilter,IN DWORD Flags));
  13. //X(UnregisterDeviceNotification, BOOL(WINAPI *PUnregisterDeviceNotification)(IN HDEVNOTIFY Handle));
  14. //#undef X
  15. HWND g_hInnerWnd = NULL;
  16. HDEVNOTIFY g_hDevNotify = NULL;
  17. LRESULT CALLBACK CameraNotifierProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
  18. pFnEventFinished OnEvtFinished = &CDocScannerCap::EvtFinishedHandle;
  19. int GetCameraInfors(CAMERA_BUCKET& vtCameraList)
  20. {
  21. // enumerate all video capture devices
  22. DestoryCamereBuckets(vtCameraList);
  23. ICreateDevEnum *pDevEnum = NULL;
  24. IEnumMoniker *pEnum = NULL;
  25. int deviceCounter = 0;
  26. HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
  27. CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
  28. reinterpret_cast<void**>(&pDevEnum));
  29. if (SUCCEEDED(hr)) {
  30. // Create an enumerator for the video capture category.
  31. hr = pDevEnum->CreateClassEnumerator(
  32. CLSID_VideoInputDeviceCategory,
  33. &pEnum, 0);
  34. if (hr == S_OK) {
  35. //if (!silent)printf("SETUP: Looking For Capture Devices\n");
  36. IMoniker *pMoniker = NULL;
  37. while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
  38. IPropertyBag *pPropBag;
  39. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
  40. if (FAILED(hr)) {
  41. pMoniker->Release();
  42. continue; // Skip this one, maybe the next one will work.
  43. }
  44. PCAMERA_INFOR_ITEM item = new CAMERA_INFOR_ITEM();
  45. if(item != NULL) {
  46. item->Cleanup();
  47. // Find the description or friendly name.
  48. VARIANT varName;
  49. VariantInit(&varName);
  50. hr = pPropBag->Read(L"Description", &varName, 0);
  51. if (FAILED(hr)) {
  52. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  53. }
  54. if (SUCCEEDED(hr)) {
  55. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  56. int maxLen = sizeof(item->szDevName) - 2;
  57. int nLen = WrapW2A(varName, &(item->szDevName[0]), maxLen);
  58. VariantClear(&varName);
  59. }
  60. VARIANT varCLSID;
  61. VariantInit(&varCLSID);
  62. hr = pPropBag->Read(L"CLSID", &varCLSID, 0);
  63. if (SUCCEEDED(hr)) {
  64. int maxLen = sizeof(item->szCLSID) - 2;
  65. int nLen = WrapW2A(varCLSID, &(item->szCLSID[0]), maxLen);
  66. VariantClear(&varCLSID);
  67. }
  68. VARIANT varDevPath;
  69. VariantInit(&varDevPath);
  70. hr = pPropBag->Read(L"DevicePath", &varDevPath, 0);
  71. if (SUCCEEDED(hr)) {
  72. int maxLen = sizeof(item->szDevPath) - 2;
  73. int nLen = WrapW2A(varDevPath, &(item->szDevPath[0]), maxLen);
  74. VariantClear(&varDevPath);
  75. }
  76. VARIANT varWaveID;
  77. VariantInit(&varWaveID);
  78. hr = pPropBag->Read(L"WaveInID", &varWaveID, 0);
  79. if (SUCCEEDED(hr)) {
  80. item->uWaveInID = varWaveID.lVal;
  81. VariantClear(&varWaveID);
  82. }
  83. vtCameraList.push_back(item);
  84. }
  85. pPropBag->Release();
  86. pPropBag = NULL;
  87. pMoniker->Release();
  88. pMoniker = NULL;
  89. deviceCounter++;
  90. }
  91. pDevEnum->Release();
  92. pDevEnum = NULL;
  93. pEnum->Release();
  94. pEnum = NULL;
  95. }
  96. }
  97. return deviceCounter;
  98. }
  99. int IsDeviceBusy(const char* lpcszDeviceName)
  100. {
  101. LOG_FUNCTION();
  102. int nRet = -2;
  103. ICreateDevEnum *pDevEnum = NULL;
  104. HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
  105. CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&pDevEnum);
  106. IEnumMoniker *pEnum = NULL;
  107. hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0);
  108. if (SUCCEEDED(hr)) {
  109. // Create an enumerator for the video capture category.
  110. IMoniker *pMoniker = NULL;
  111. nRet = -1;
  112. while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
  113. IPropertyBag *pPropBag = NULL;
  114. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag));
  115. if (FAILED(hr)) {
  116. SAFE_RELEASE_IDEV(pPropBag);
  117. SAFE_RELEASE_IDEV(pMoniker);
  118. continue; // Skip this one, maybe the next one will work.
  119. }
  120. VARIANT varName;
  121. VariantInit(&varName);
  122. hr = pPropBag->Read(L"Description", &varName, 0);
  123. if (FAILED(hr)) {
  124. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  125. }
  126. if (SUCCEEDED(hr)) {
  127. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  128. int count = 0;
  129. char tmp[255] = {0};
  130. while (varName.bstrVal[count] != 0x00 && count < 255) {
  131. tmp[count] = (char)varName.bstrVal[count];
  132. count++;
  133. }
  134. if(SUCCEEDED(hr)) {
  135. if(!strcmp(lpcszDeviceName, tmp)) {
  136. //Deal the specific device
  137. nRet = 0;
  138. LPBC* pbc = NULL;
  139. IBaseFilter *P_VCamTrans = NULL;
  140. IBaseFilter *pCap = NULL;
  141. CreateBindCtx(0, pbc);
  142. hr = pMoniker->BindToObject((IBindCtx *)pbc, 0, IID_IBaseFilter,(void **)&pCap);
  143. IGraphBuilder *m_pGB = NULL;
  144. IMediaControl *m_pMC = NULL;
  145. IVideoWindow *m_pVW = NULL;
  146. IMediaEventEx *m_pME = NULL;
  147. hr = CoCreateInstance(CLSID_FilterGraph, NULL,
  148. CLSCTX_INPROC, IID_IGraphBuilder, (void **)&m_pGB);
  149. if (FAILED(hr)) {
  150. nRet = -2;
  151. SAFE_RELEASE_IDEV(m_pGB);
  152. SAFE_RELEASE_IDEV(pCap);
  153. SAFE_RELEASE_IDEV(pPropBag);
  154. SAFE_RELEASE_IDEV(pMoniker);
  155. goto PEnd;
  156. }
  157. m_pGB->AddFilter(pCap, NULL);
  158. ICaptureGraphBuilder2 *m_pCapGB = NULL;
  159. hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
  160. CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&m_pCapGB);
  161. if (FAILED(hr)) {
  162. nRet = -2;
  163. SAFE_RELEASE_IDEV(m_pCapGB);
  164. SAFE_RELEASE_IDEV(m_pGB);
  165. SAFE_RELEASE_IDEV(pCap);
  166. SAFE_RELEASE_IDEV(pPropBag);
  167. SAFE_RELEASE_IDEV(pMoniker);
  168. goto PEnd;
  169. }
  170. m_pCapGB->SetFiltergraph(m_pGB);
  171. IAMCrossbar *pXBar1 = NULL;
  172. hr = m_pCapGB->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pCap,
  173. IID_IAMCrossbar,(void **)&pXBar1);
  174. if (SUCCEEDED(hr)) {
  175. long OutputPinCount;
  176. long InputPinCount;
  177. long PinIndexRelated;
  178. long PhysicalType;
  179. long inPort = 0;
  180. long outPort = 0;
  181. pXBar1->get_PinCounts(&OutputPinCount,&InputPinCount);
  182. int videoBusy = 1;
  183. for (int i=0; i<InputPinCount; i++) {
  184. for (int j=0; j<OutputPinCount; j++) {
  185. if(S_OK == pXBar1->CanRoute(j, i)) {
  186. pXBar1->Route(j,i);
  187. m_pGB->AddFilter(pCap, L"Capture Filter");
  188. hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
  189. hr = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
  190. hr = m_pCapGB->RenderStream(NULL, NULL, pCap, NULL, P_VCamTrans);
  191. hr = m_pVW->put_Owner((OAHWND)NULL);
  192. hr = m_pVW->put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN);
  193. hr = m_pVW->put_Visible(OAFALSE);
  194. hr = m_pVW->put_AutoShow(OAFALSE);
  195. HRESULT innhr = m_pMC->StopWhenReady();
  196. if (SUCCEEDED(innhr))
  197. {
  198. videoBusy = 0;
  199. }
  200. else {
  201. Dbg("It works ? %d, %d", i, j);
  202. }
  203. SAFE_RELEASE_IDEV(m_pVW);
  204. SAFE_RELEASE_IDEV(m_pMC);
  205. SAFE_RELEASE_IDEV(P_VCamTrans);
  206. }
  207. }
  208. }
  209. if (videoBusy == 1)
  210. {
  211. Dbg("Test 1");
  212. nRet = 1; //视频设备占用
  213. }
  214. SAFE_RELEASE_IDEV(pXBar1);
  215. }
  216. else //pXBar1
  217. {
  218. m_pGB->AddFilter(pCap, L"Capture Filter");
  219. m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC);
  220. hr = m_pGB->QueryInterface(IID_IMediaEventEx, (void**)&m_pME);
  221. hr = m_pGB->QueryInterface(IID_IVideoWindow,(LPVOID*)&m_pVW);
  222. hr = m_pCapGB->RenderStream(NULL, NULL, pCap, NULL, P_VCamTrans);
  223. hr = m_pVW->put_Owner((OAHWND)NULL);
  224. hr = m_pVW->put_WindowStyle( WS_CHILD | WS_CLIPCHILDREN);
  225. hr = m_pVW->put_Visible(OAFALSE);
  226. hr = m_pVW->put_AutoShow(OAFALSE);
  227. HRESULT innhr = m_pMC->StopWhenReady();
  228. if (FAILED(innhr))
  229. {
  230. Dbg("Test 2");
  231. nRet = 1; //视频设备占用
  232. }
  233. SAFE_RELEASE_IDEV(m_pVW);
  234. SAFE_RELEASE_IDEV(m_pMC);
  235. SAFE_RELEASE_IDEV(P_VCamTrans);
  236. }
  237. SAFE_RELEASE_IDEV(m_pCapGB);
  238. SAFE_RELEASE_IDEV(m_pGB);
  239. SAFE_RELEASE_IDEV(pCap);
  240. break;
  241. }
  242. }
  243. }
  244. SAFE_RELEASE_IDEV(pPropBag);
  245. SAFE_RELEASE_IDEV(pMoniker);
  246. }
  247. }
  248. PEnd:
  249. SAFE_RELEASE_IDEV(pDevEnum);
  250. SAFE_RELEASE_IDEV(pEnum);
  251. Dbg("IsDeviceBusy(%s) returned %d", lpcszDeviceName, nRet);
  252. if(nRet != 1) {
  253. nRet = 0;
  254. }
  255. return nRet;
  256. }
  257. int GetCameraCount()
  258. {
  259. ICreateDevEnum *pDevEnum = NULL;
  260. IEnumMoniker *pEnum = NULL;
  261. int deviceCounter = 0;
  262. HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
  263. CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
  264. reinterpret_cast<void**>(&pDevEnum));
  265. if (SUCCEEDED(hr)) {
  266. hr = pDevEnum->CreateClassEnumerator(
  267. CLSID_VideoInputDeviceCategory,
  268. &pEnum, 0);
  269. if(hr == S_OK){
  270. IMoniker *pMoniker = NULL;
  271. while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
  272. IPropertyBag *pPropBag;
  273. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
  274. (void**)(&pPropBag));
  275. if (FAILED(hr)){
  276. pMoniker->Release();
  277. continue; // Skip this one, maybe the next one will work.
  278. }
  279. pPropBag->Release();
  280. pPropBag = NULL;
  281. pMoniker->Release();
  282. pMoniker = NULL;
  283. deviceCounter++;
  284. }
  285. pEnum->Release();
  286. pEnum = NULL;
  287. }
  288. pDevEnum->Release();
  289. pDevEnum = NULL;
  290. }
  291. return deviceCounter;
  292. }
  293. int UpdateCameraInfors(CAMERA_BUCKET& vtCameraList)
  294. {
  295. int old_count = vtCameraList.size();
  296. if(old_count > 0) {
  297. DestoryCamereBuckets(vtCameraList);
  298. }
  299. GetCameraInfors(vtCameraList);
  300. return old_count;
  301. }
  302. int ExclusiveCameraBuckes(const CAMERA_BUCKET& lhs, const CAMERA_BUCKET& rhs, CAMERA_BUCKET& diff)
  303. {
  304. int count = 0;
  305. const size_t l_size = lhs.size();
  306. const size_t r_size = rhs.size();
  307. if(!diff.empty()) {
  308. DestoryCamereBuckets(diff);
  309. }
  310. //Is it necessary to sort before doing comparation job ?
  311. if(l_size > r_size) {
  312. for(CAMERA_BUCKET_CITER citer=lhs.cbegin(); citer!=lhs.cend(); ++citer) {
  313. auto aim = std::find_if(rhs.cbegin(), rhs.cend(),
  314. [citer](PCAMERA_INFOR_ITEM const item){
  315. return !strcmp(item->szDevPath, (*citer)->szDevPath);
  316. });
  317. if(aim == rhs.cend()) {
  318. PCAMERA_INFOR_ITEM item = new CAMERA_INFOR_ITEM();
  319. if(item != NULL) {
  320. item->Copy((*citer));
  321. diff.push_back(item);
  322. count++;
  323. }
  324. }
  325. }
  326. } else if(l_size < r_size) {
  327. for(CAMERA_BUCKET_CITER citer=rhs.cbegin(); citer!=rhs.cend(); ++citer) {
  328. auto aim = std::find_if(lhs.cbegin(), lhs.cend(), [citer](PCAMERA_INFOR_ITEM const item){
  329. return !strcmp(item->szDevPath, (*citer)->szDevPath);
  330. });
  331. if(aim == lhs.cend()) {
  332. PCAMERA_INFOR_ITEM item = new CAMERA_INFOR_ITEM();
  333. if(item != NULL) {
  334. item->Copy((*citer));
  335. diff.push_back(item);
  336. count++;
  337. }
  338. }
  339. }
  340. }
  341. return count;
  342. }
  343. void DisplayCameraInfos(const CAMERA_BUCKET& vtCameraList)
  344. {
  345. Dbg("Cameralist:(%d)", vtCameraList.size());
  346. for(CAMERA_BUCKET_CITER it=vtCameraList.cbegin(); it!=vtCameraList.cend(); ++it) {
  347. if(*it) {
  348. (*it)->Display();
  349. }else {
  350. LOG_ASSERT(!"Empty elememt occurs !!");
  351. }
  352. }
  353. }
  354. void OnMouseTrace(int evt, int x, int y, int flags, void* param = NULL);
  355. const Scalar RED = Scalar(0,0,255);
  356. const Scalar PINK = Scalar(230,130,255);
  357. const Scalar BLUE = Scalar(255,0,0);
  358. const Scalar LIGHTBLUE = Scalar(255,255,160);
  359. const Scalar GREEN = Scalar(0,255,0);
  360. const Scalar BLACK = Scalar(0, 0, 0);
  361. const Scalar ERROR_GRAY = Scalar(205, 205, 205);
  362. const int WAITKEY_TIME = 30;
  363. const DWORD ERROR_CONTINUE_MILLSEC = 3000;
  364. const int ERROR_CONTINUE_TIMES = ERROR_CONTINUE_MILLSEC / WAITKEY_TIME;
  365. CDocScannerCap::CDocScannerCap(CPortableScannerFSM* pFSM)
  366. :m_videoID(-1)
  367. ,m_hrCoInited(S_FALSE)
  368. ,m_defWnd(NULL)
  369. ,m_dwErrCode(ERROR_SUCCESS)
  370. ,m_hPreviewPro(NULL)
  371. ,m_fPreviewing(false)
  372. ,m_colorMode(COLORFUL)
  373. ,m_roiMode(ROI_DEFAULT)
  374. ,m_roiRate(1.0f)
  375. ,m_bHide(FALSE)
  376. ,m_winSize(DR_X, DR_Y, DR_W, DR_H)
  377. ,rectStatus(NOT_SET)
  378. ,m_pFSM(pFSM)
  379. ,m_bHSPSType(false)
  380. {
  381. m_hrCoInited = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  382. }
  383. CDocScannerCap::~CDocScannerCap(void)
  384. {
  385. LOG_FUNCTION();
  386. #if 1
  387. //let VideoCapture object invoke release at destructor.
  388. _cleanup(false);
  389. RequestQueueCleanup();
  390. //Would meet confict ?
  391. Dbg("before destroyAllWindows...");
  392. destroyAllWindows();
  393. Dbg("after destroyAllWindows...");
  394. #endif
  395. if(m_hrCoInited == S_OK) {
  396. CoUninitialize();
  397. }
  398. }
  399. void CDocScannerCap::Test()
  400. {
  401. // cv::VideoCapture videoCap(0);
  402. // if(!videoCap.isOpened())
  403. // {
  404. // return;
  405. // }
  406. // cv::Mat edges;
  407. //#define WINDOWS_TITLE "edges"
  408. // cv::namedWindow(WINDOWS_TITLE);
  409. // moveWindow(WINDOWS_TITLE, 0, 0);
  410. // setWindowProperty(WINDOWS_TITLE, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
  411. // //HWND hWin = FindWindow(NULL, WINDOWS_TITLE);
  412. // HWND hWin = (HWND)cvGetWindowHandle(WINDOWS_TITLE);
  413. // DWORD dwFlag = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOZORDER;
  414. // dwFlag &= ~SWP_NOSIZE;
  415. // if(hWin == NULL)
  416. // {
  417. // LOG_TRACE("Find %s window handle faiiled, GLE=%u", WINDOWS_TITLE, GetLastError());
  418. // }
  419. // SetWindowPos(hWin, HWND_NOTOPMOST, 128, 128, edges.cols, edges.rows, dwFlag);
  420. // //Bordorless
  421. // SetWindowLong(hWin, GWL_STYLE, GetWindowLong(hWin, GWL_EXSTYLE) | WS_EX_TOPMOST | WS_EX_LAYERED);
  422. // SetLayeredWindowAttributes(hWin, RGB(255,255,255), 0, LWA_COLORKEY);
  423. // SetWindowLong(hWin, GWL_STYLE, GetWindowLong(hWin, GWL_EXSTYLE)
  424. // & (~WS_CAPTION)
  425. // & (~WS_BORDER)
  426. // & (~WS_THICKFRAME));
  427. // ShowWindow(hWin, SW_SHOW);
  428. // for(;;)
  429. // {
  430. // cv::Mat cameraFrame;
  431. // videoCap >> cameraFrame ;
  432. // imshow(WINDOWS_TITLE, cameraFrame);
  433. // if(cv::waitKey(30) >= 0) {
  434. // cameraFrame.release();
  435. // destroyWindow(WINDOWS_TITLE);
  436. // break;
  437. // }
  438. // }
  439. }
  440. bool CDocScannerCap::InitHwndForNotify()
  441. {
  442. static char szWindowClass[] = "Win32_DocScannerCap";
  443. static char szTitle[] = "Win32 Document Scanner Notificer";
  444. //get instance of current program (self)
  445. HINSTANCE hInstance = GetModuleHandle (NULL);
  446. char szPcName[MAX_PATH] = {0};
  447. DWORD nSize = sizeof(szPcName);
  448. GetComputerName(szPcName, &nSize);
  449. WNDCLASSEX wcex;
  450. wcex.cbSize = sizeof(WNDCLASSEX);
  451. wcex.style = CS_HREDRAW | CS_VREDRAW;
  452. wcex.lpfnWndProc = CameraNotifierProc;
  453. wcex.cbClsExtra = 0;
  454. wcex.cbWndExtra = 0;
  455. wcex.hInstance = hInstance;
  456. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  457. wcex.lpszMenuName = NULL;
  458. wcex.lpszClassName = szWindowClass;
  459. wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
  460. if (!RegisterClassEx(&wcex))
  461. {
  462. return false;
  463. }
  464. HWND hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
  465. CW_USEDEFAULT,
  466. CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  467. if (!hWnd)
  468. {
  469. return false;
  470. }
  471. ShowWindow(hWnd, SW_HIDE);
  472. UpdateWindow(hWnd);
  473. g_hInnerWnd = hWnd;
  474. return true;
  475. }
  476. bool CDocScannerCap::RegisterVideoNotify()
  477. {
  478. DEV_BROADCAST_DEVICEINTERFACE filterData;
  479. ZeroMemory(&filterData, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
  480. filterData.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
  481. filterData.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  482. filterData.dbcc_classguid = AM_KSCATEGORY_VIDEO;
  483. g_hDevNotify = RegisterDeviceNotification(g_hInnerWnd, &filterData, DEVICE_NOTIFY_WINDOW_HANDLE);
  484. if (g_hDevNotify == NULL) {
  485. return false;
  486. }
  487. return true;
  488. }
  489. bool CDocScannerCap::UnRegisterVideoNotify()
  490. {
  491. if (g_hDevNotify != NULL) {
  492. UnregisterDeviceNotification(g_hDevNotify);
  493. g_hDevNotify = NULL;
  494. }
  495. return true;
  496. }
  497. bool CDocScannerCap::Open(unsigned int idx)
  498. {
  499. if(m_cvCap.isOpened()) {
  500. _cleanup();
  501. }
  502. //the method first call release to close alreay opened file or camera
  503. m_cvCap.open(idx);
  504. if(!m_cvCap.isOpened()) {
  505. Dbg("open failed:");
  506. m_dwErrCode = ERROR_OPEN_FAILED;
  507. winName.clear();
  508. return false;
  509. }
  510. _setProperty();
  511. {
  512. CAMERA_INFOR_ITEM item;
  513. if(GetSpecificedCamInfor(idx, &item) > 0) {
  514. _setDevName(item.szDevName);
  515. winName = cv::String(DEFAULT_MAT_WINDOW_NAME) + "-" + devName;
  516. }else {
  517. CHAR szDevIndex[128] = {0};
  518. sprintf_s(szDevIndex, "%s-%d", DEFAULT_MAT_WINDOW_NAME, idx);
  519. winName = szDevIndex;
  520. _setDevName("");
  521. }
  522. }
  523. m_videoID = idx;
  524. m_dwErrCode = ERROR_SUCCESS;
  525. return true;
  526. }
  527. void CDocScannerCap::_setProperty()
  528. {
  529. //设置为不一样的分辨率,会出现耗时,1.5s 长城
  530. //SetResoultionRatio(1920, 1080);
  531. }
  532. bool CDocScannerCap::OpenCamera(LPCTSTR lpcszDev)
  533. {
  534. if(lpcszDev == NULL) {
  535. m_dwErrCode = ERROR_INVALID_PARAMETER;
  536. return false;
  537. }
  538. const int camId = _getCamIDByDevName(lpcszDev);
  539. if(camId < 0) {
  540. m_dwErrCode = ERROR_FILE_NOT_FOUND;
  541. Dbg("not found camera id.");
  542. return false;
  543. }
  544. //const int nRes = IsDeviceBusy(lpcszDev);
  545. //if(nRes) {
  546. // if(nRes == -2) {
  547. // m_dwErrCode = ERROR_INVALID_ACCESS;
  548. // } else if(nRes == -1) {
  549. // m_dwErrCode = ERROR_FILE_NOT_FOUND;
  550. // } else if(nRes == 1) {
  551. // m_dwErrCode = ERROR_DEVICE_IN_USE;
  552. // } else {
  553. // m_dwErrCode = ERROR_BAD_ENVIRONMENT;
  554. // }
  555. // return false;
  556. //}
  557. if(Open(camId))
  558. {
  559. if(devName.empty())
  560. _setDevName(lpcszDev);
  561. return true;
  562. }
  563. return false;
  564. }
  565. bool CDocScannerCap::ScanImage(const char* lpcszFilePath)
  566. {
  567. if(!m_fPreviewing) {
  568. Dbg("Request scaning without in previewing.");
  569. m_dwErrCode = ERROR_INVALID_ENVIRONMENT;
  570. return false;
  571. }
  572. if(lpcszFilePath == NULL) {
  573. m_dwErrCode = ERROR_INVALID_PARAMETER;
  574. return false;
  575. }
  576. char szFileName[MAX_PATH] = {0};
  577. int len = strlen(lpcszFilePath);
  578. if(len == 0) {
  579. _combineFileName(szFileName, MAX_PATH);
  580. cv::String strFileName("C:\\");
  581. strFileName += szFileName;
  582. strFileName += ".jpg";
  583. strcpy_s(szFileName, strFileName.c_str());
  584. }
  585. else {
  586. strcpy_s(szFileName, lpcszFilePath);
  587. }
  588. len = strlen(szFileName);
  589. if(len == 0) {
  590. m_dwErrCode = ERROR_INVALID_PARAMETER;
  591. return false;
  592. }
  593. RequestEventPtr item = CreateRequestEvent(EVTCODE_SCAN);
  594. if(!item) {
  595. Dbg("CreateRequestEvent failed");
  596. m_dwErrCode = ERROR_RESOURCE_FAILED;
  597. return false;
  598. }
  599. item->evtData = (CHAR*)malloc(sizeof(char)*(len+1));
  600. if(item->evtData == NULL) {
  601. Dbg("malloc failed");
  602. m_dwErrCode = ERROR_RESOURCE_FAILED;
  603. delete item;
  604. return false;
  605. }
  606. memset(item->evtData, 0, sizeof(char)*(len+1));
  607. strcpy_s(item->evtData, sizeof(char)*(len+1), szFileName);
  608. item->dwDataLen = len+1;
  609. PostIntoRequestQueue(&item);
  610. Dbg("WaitForResponse...");
  611. int nRes = WaitForResponse(EVTCODE_SCAN, 30*1000);
  612. Dbg("WaitForResponse returned: 0x%02x", nRes);
  613. if(nRes >= EVTSTATUS_ERROR_MASK) {
  614. }
  615. else if(nRes == EVTSTATUS_DONE_SUCC) {
  616. Dbg("Scan succ: %d[%s]", ExistsFileA(szFileName), szFileName);
  617. //Mat picture = imread(szFileName);
  618. //if(!picture.empty()) {
  619. // namedWindow("show-img");
  620. // imshow("show-img", picture);
  621. //}
  622. //else {
  623. // Dbg("picture is empty!!");
  624. //}
  625. }
  626. return true;
  627. }
  628. bool CDocScannerCap::CloseCamera()
  629. {
  630. _cleanup();
  631. m_dwErrCode = ERROR_SUCCESS;
  632. return true;
  633. }
  634. bool CDocScannerCap::StartPreview()
  635. {
  636. if(!_isVal()){
  637. m_dwErrCode = ERROR_INVALID_ENVIRONMENT;
  638. return false;
  639. }
  640. if(m_fPreviewing) {
  641. m_dwErrCode = SCHED_E_ALREADY_RUNNING;
  642. return false;
  643. }
  644. m_hPreviewPro = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
  645. CDocScannerCap::WndPreviewDlgProc, this,
  646. CREATE_SUSPENDED,
  647. NULL));
  648. if(m_hPreviewPro == NULL || m_hPreviewPro == INVALID_HANDLE_VALUE)
  649. {
  650. m_hPreviewPro = NULL;
  651. m_dwErrCode = E_HANDLE;
  652. Dbg("Create WndPreviewDlgProc thread failed");
  653. return false;
  654. }
  655. m_fPreviewing = true;
  656. if(ResumeThread(m_hPreviewPro) == (DWORD)-1) {
  657. Dbg("ResumeThread failed, GLE=%u", GetLastError());
  658. m_dwErrCode = E_UNEXPECTED;
  659. m_fPreviewing = false;
  660. CloseHandle(m_hPreviewPro);
  661. m_hPreviewPro = NULL;
  662. return false;
  663. }
  664. m_dwErrCode = ERROR_SUCCESS;
  665. return true;
  666. }
  667. bool CDocScannerCap::TerminatePreview()
  668. {
  669. m_dwErrCode = ERROR_SUCCESS;
  670. if(m_fPreviewing) {
  671. m_dwErrCode = E_UNEXPECTED;
  672. m_tpStopPreview = true;
  673. //30 seconds to timeout?
  674. Dbg("Set StopPreivew flag true, waitting...");
  675. DWORD dwResult = WaitForSingleObject(m_hPreviewPro, 30 * 1000);
  676. if(dwResult == WAIT_OBJECT_0) {
  677. Dbg("Wait succ.");
  678. //assert(m_fPreviewing == false);
  679. CloseHandle(m_hPreviewPro);
  680. m_hPreviewPro = NULL;
  681. m_dwErrCode = ERROR_SUCCESS;
  682. return true;
  683. }else if(dwResult == WAIT_TIMEOUT) {
  684. Dbg("Wait succ timeout: %d", m_fPreviewing);
  685. if(!m_fPreviewing) {
  686. CloseHandle(m_hPreviewPro);
  687. m_hPreviewPro = NULL;
  688. m_dwErrCode = ERROR_SUCCESS;
  689. return true;
  690. }
  691. m_dwErrCode = WAIT_TIMEOUT;
  692. }
  693. else {
  694. Dbg("WaitForSingleObject failed returned: %u.", dwResult);
  695. m_dwErrCode = dwResult;
  696. }
  697. }
  698. return (m_dwErrCode == ERROR_SUCCESS);
  699. }
  700. bool CDocScannerCap::_initWindow(bool fShown)
  701. {
  702. if(m_defWnd) {
  703. _destroyWindow();
  704. }
  705. //TODO: Identify the window name to unique.
  706. DWORD wdFlags = WINDOW_NORMAL;
  707. namedWindow(winName, wdFlags);
  708. m_defWnd = FindWindow(NULL, winName.c_str());
  709. if(m_defWnd == NULL) {
  710. destroyWindow(winName);
  711. m_dwErrCode = ERROR_INVALID_WINDOW_HANDLE;
  712. Dbg("Find %s window handle faiiled, GLE=%u", winName.c_str(), GetLastError());
  713. return false;
  714. }
  715. DWORD dwFlag = fShown ? SWP_SHOWWINDOW : SWP_HIDEWINDOW;
  716. BOOL bRet = ::SetWindowPos(m_defWnd, HWND_TOPMOST,
  717. m_winSize.x, m_winSize.y, m_winSize.width, m_winSize.height, dwFlag);
  718. Dbg("WinSize(%d): %d, %d, %d, %d", bRet, m_winSize.x, m_winSize.y, m_winSize.width, m_winSize.height);
  719. if(bRet) { m_bHide = !fShown; }
  720. m_dwErrCode = ERROR_SUCCESS;
  721. rectStatus = NOT_SET;
  722. return true;
  723. }
  724. void CDocScannerCap::_destroyWindow()
  725. {
  726. LOG_FUNCTION();
  727. if(!m_cmFrame.empty()) {
  728. m_cmFrame.release();
  729. }
  730. if(m_defWnd) {
  731. Dbg("before destroyWindow with %s", winName.c_str());
  732. destroyWindow(winName);
  733. Dbg("after destroyWindow with %s", winName.c_str());
  734. m_defWnd = NULL;
  735. m_bHide = FALSE;
  736. }
  737. return;
  738. }
  739. size_t CDocScannerCap::_combineFileName(char* szFnBuf, size_t sizeLen)
  740. {
  741. if(sizeLen == 0 || szFnBuf == NULL) {
  742. return 0;
  743. }
  744. memset(szFnBuf, 0, sizeof(char)*sizeLen);
  745. SYSTEMTIME st;
  746. GetLocalTime(&st);
  747. sprintf_s(szFnBuf, sizeLen, "%04d%02d%02d%02d%02d%02d.jpg", st.wYear, st.wMonth, st.wDay,
  748. st.wHour, st.wMinute, st.wSecond);
  749. return strlen(szFnBuf);
  750. }
  751. UINT WINAPI CDocScannerCap::WndPreviewDlgProc(PVOID param)
  752. {
  753. CDocScannerCap *pCap = reinterpret_cast<CDocScannerCap*>(param);
  754. if(pCap == NULL) {
  755. Dbg("WndPreviewDlgProc::praram is invalid(empty)");
  756. return UINT(-1);
  757. }
  758. return (UINT)(pCap->_executePreview());
  759. }
  760. void CDocScannerCap::EvtFinishedHandle(USHORT evtCode, UCHAR result, UINT checksum)
  761. {
  762. Dbg("EvtCode:%d, result:%d, checksum:%d", evtCode, result, checksum);
  763. }
  764. void CDocScannerCap::SetResoultionRatio(int width, int height, int nframes /*= -1*/)
  765. {
  766. Dbg("before: width=%d, height=%d , nframes=%d", (int)m_cvCap.get(CAP_PROP_FRAME_WIDTH),
  767. (int)m_cvCap.get(CAP_PROP_FRAME_HEIGHT), (int)m_cvCap.get(CAP_PROP_FRAME_COUNT));
  768. m_cvCap.set(CV_CAP_PROP_FRAME_WIDTH, width);
  769. m_cvCap.set(CV_CAP_PROP_FRAME_HEIGHT, height);
  770. Dbg("after: width=%d, height=%d , nframes=%d", (int)m_cvCap.get(CAP_PROP_FRAME_WIDTH),
  771. (int)m_cvCap.get(CAP_PROP_FRAME_HEIGHT), (int)m_cvCap.get(CAP_PROP_FRAME_COUNT));
  772. //m_cvCap.set(CAP_PROP_CONVERT_RGB, 0);
  773. }
  774. void CDocScannerCap::_setMouseCallback()
  775. {
  776. cvSetMouseCallback(winName.c_str(), OnMouseTrace, this);
  777. }
  778. void CDocScannerCap::MouseClick(int event, int x, int y, int flags)
  779. {
  780. //static Rect origin;
  781. if(event == CV_EVENT_LBUTTONDOWN) {
  782. //if(rectStatus == NOT_SET)
  783. {
  784. //Dbg("CV_EVENT_LBUTTONDOWN");
  785. rectStatus = IN_PROCESS;
  786. rect = Rect(x, y, 0, 0);
  787. //origin = rect;
  788. }
  789. } else if(event == CV_EVENT_MOUSEMOVE) {
  790. if(rectStatus == IN_PROCESS) {
  791. rect = Rect(Point(rect.x, rect.y), Point(x,y));
  792. //rect.x = MIN(origin.x, x);
  793. //rect.y = MIN(origin.y, y);
  794. //rect.width = abs(origin.x - x);
  795. //rect.height = abs(origin.y - y);
  796. //Dbg("CV_EVENT_MOUSEMOVE: %d,%d,%d,%d TID(%u)", rect.x, rect.y, rect.width, rect.height, GetCurrentThreadId());
  797. }
  798. }else if(event == CV_EVENT_LBUTTONUP) {
  799. if(rectStatus == IN_PROCESS) {
  800. if(rect.height == 0 || rect.width == 0) {
  801. Dbg("CV_EVENT_LBUTTONUP::Zero Area");
  802. rectStatus = NOT_SET;
  803. return;
  804. }
  805. rect = Rect(Point(rect.x, rect.y), Point(x,y));
  806. Dbg("CV_EVENT_LBUTTONUP");
  807. rectStatus = SET;
  808. }
  809. }
  810. }
  811. void CDocScannerCap::_setResizeArea(float ratio)
  812. {
  813. //m_cmFrame.at<Vec3b>(m_cmFrame.cols / 2, m_cmFrame.rows / 2)[0] = 0;
  814. //m_cmFrame.at<Vec3b>(m_cmFrame.cols / 2, m_cmFrame.rows / 2)[1] = 0;
  815. //m_cmFrame.at<Vec3b>(m_cmFrame.cols / 2, m_cmFrame.rows / 2)[2] = 255;
  816. //putText(m_cmFrame, "Hello", Point(m_cmFrame.cols/2, m_cmFrame.rows/2), 0, 0.7, Scalar(255, 0, 0));
  817. Rect area((1-ratio)/2*m_cmFrame.cols, (1-ratio)/2*m_cmFrame.rows, ratio*m_cmFrame.cols, ratio*m_cmFrame.rows);
  818. //Mat mask;
  819. //mask.create(m_cmFrame.size(), CV_8UC1);
  820. //mask.setTo( GC_BGD );
  821. //(mask(area)).setTo( Scalar(GC_PR_FGD));
  822. //Mat binMask;
  823. //if( binMask.empty() || binMask.rows != mask.rows || binMask.cols != mask.cols )
  824. // binMask.create(mask.size(), CV_8UC1 );
  825. //binMask = mask & 1;
  826. //m_cmFrame.copyTo(res, binMask);
  827. //WRITE_INFO_PARAM("w, h: %d, %d", m_cmFrame.cols, m_cmFrame.rows);
  828. //WRITE_INFO_PARAM("x, y, w, h: %d, %d, %d, %d", area.x, area.y, area.width, area.height);
  829. Mat roi = m_cmFrame(area);
  830. Mat res;
  831. res.create(roi.rows, roi.cols, m_cmFrame.type());
  832. roi.copyTo(res);
  833. //WRITE_INFO_PARAM("2 w, h: %d, %d", res.cols, res.rows);
  834. m_cmFrame.release();
  835. m_cmFrame = res;
  836. //rectangle(m_cmFrame, Point(area.x, area.y),
  837. // Point(area.x + area.width, area.y + area.height),
  838. // RED, rectangle_thickness);
  839. }
  840. void CDocScannerCap::_setInterestArea()
  841. {
  842. if(rectStatus == IN_PROCESS || rectStatus == SET) {
  843. Rect area(rect);
  844. //Dbg("rect: %d, %d, %d, %d", rect.x, rect.y, rect.width, rect.height);
  845. int suffix_x = rect.x - drawableRect.x;
  846. int suffix_y = rect.y - drawableRect.y;
  847. area.x = suffix_x > 0 ? rect.x : drawableRect.x;
  848. area.y = suffix_y > 0 ? rect.y : drawableRect.y;
  849. suffix_x = suffix_x > 0 ? suffix_x : 0;
  850. suffix_y = suffix_y > 0 ? suffix_y : 0;
  851. area.width = min(rect.width, drawableRect.width-suffix_x-rectangle_thickness);
  852. area.height = min(rect.height, drawableRect.height-suffix_y-rectangle_thickness);
  853. rectangle(m_cmFrame, Point(area.x, area.y),
  854. Point(area.x + area.width, area.y + area.height),
  855. GREEN, rectangle_thickness);
  856. assert(m_cmFrame.data);
  857. //Dbg("drawableRect: %d, %d, %d, %d", drawableRect.x, drawableRect.y, drawableRect.width, drawableRect.height);
  858. const CvScalar colorMask = cvScalarAll(-52);
  859. Mat res = Mat::ones(m_cmFrame.size(), CV_8UC1)*255;
  860. //Dbg("area: %d, %d, %d, %d", area.x, area.y, area.width, area.height);
  861. res(area).setTo(0);
  862. cv::add(m_cmFrame, (const cv::Scalar&)colorMask, m_cmFrame, res, m_cmFrame.type());
  863. rect = area;
  864. }
  865. }
  866. bool CDocScannerCap::_executePreview()
  867. {
  868. _initWindow(true);
  869. m_tpStopPreview = false;
  870. _setMouseCallback();
  871. if (GetWindowLong(m_defWnd, GWL_STYLE) & WS_POPUP) {
  872. SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
  873. }
  874. int eOccurTimes = 0, eClosedTimes = 0;
  875. DWORD dwEStartTick = 0;
  876. char szFileName[MAX_PATH] = {0};
  877. for(;;)
  878. {
  879. m_cvCap >> m_cmFrame;
  880. if(!m_cmFrame.data) {
  881. continue;
  882. }
  883. Mat gray = m_cmFrame.clone();
  884. cvtColor(m_cmFrame, gray, CV_BGR2GRAY);
  885. if(IsColorAbnormal(&IplImage(gray))) {
  886. IplImage* inner = &IplImage(gray);
  887. int B = CV_IMAGE_ELEM(inner, unsigned char, inner->height/2, (inner->width/2)*3+0);
  888. int G = CV_IMAGE_ELEM(inner, unsigned char, inner->height/2, (inner->width/2)*3+1);
  889. int R = CV_IMAGE_ELEM(inner, unsigned char, inner->height/2, (inner->width/2)*3+2);
  890. if(B == G && G == R && R == 205) {
  891. if(eOccurTimes == 0) {
  892. eOccurTimes++;
  893. Dbg("Wow! the scanner has problem");
  894. dwEStartTick = GetTickCount();
  895. }else if(eOccurTimes != -1) {
  896. eOccurTimes++;
  897. if(eOccurTimes >= ERROR_CONTINUE_TIMES
  898. || GetTickCount() > dwEStartTick + ERROR_CONTINUE_MILLSEC) {
  899. Dbg("Send Reset Event !! %d", eOccurTimes);
  900. eOccurTimes = -1;
  901. SetResetEvent();
  902. }
  903. }
  904. }else if(eOccurTimes != 0){
  905. eOccurTimes = 0;
  906. }
  907. if(B == G && G == R && B == 0) {
  908. if(eClosedTimes == 0) {
  909. Dbg("Eh, maybe forget to scratch the scanner");
  910. eClosedTimes = 1;
  911. }
  912. }else if(eClosedTimes != 0){
  913. Dbg("Ok, you achieve it");
  914. eClosedTimes = 0;
  915. }
  916. } else {
  917. if(eOccurTimes != 0 && eOccurTimes != -1) {
  918. eOccurTimes = 0;
  919. }
  920. if(eClosedTimes != 0){
  921. Dbg("Ok, you achieve it");
  922. eClosedTimes = 0;
  923. }
  924. }
  925. gray.release();
  926. if(m_roiMode != ROI_DEFAULT && m_bHSPSType) {
  927. _setResizeArea(m_roiRate);
  928. }
  929. if(m_colorMode == GRAY) {
  930. cvtColor(m_cmFrame, m_cmFrame, CV_BGR2GRAY);
  931. }
  932. Mat origin = m_cmFrame.clone();
  933. int cols = 0, rows = 0;
  934. {//填充边框以适应宽度
  935. Size origin_size = m_cmFrame.size();
  936. if(1.0*m_winSize.width / m_winSize.height > 1) {
  937. int aimWidth = (int)(1.0*origin_size.height*(1.0*m_winSize.width / m_winSize.height));
  938. if(aimWidth > origin_size.width) {
  939. cols = (aimWidth-origin_size.width) / 2;
  940. }else if(aimWidth < origin_size.width) {
  941. int aimHeigth = (int)(1.0*origin_size.width*(1.0*m_winSize.height / m_winSize.width));
  942. assert(aimHeigth >= origin_size.height);
  943. rows = (aimHeigth-origin_size.height) / 2;
  944. }
  945. }else if(1.0*m_winSize.width / m_winSize.height < 1) {
  946. int aimHeigth = (int)(1.0*origin_size.width*(1.0*m_winSize.height / m_winSize.width));
  947. if(aimHeigth > origin_size.height) {
  948. rows = (aimHeigth-origin_size.height) / 2;
  949. }else if(aimHeigth < origin_size.height) {
  950. int aimWidth = (int)(1.0*origin_size.height*(1.0*m_winSize.width / m_winSize.height));
  951. assert(aimWidth >= origin_size.width);
  952. cols = (aimWidth-origin_size.width) / 2;
  953. }
  954. }
  955. }
  956. if(cols > 0 || rows > 0) {
  957. copyMakeBorder(m_cmFrame, m_cmFrame, rows, rows, cols, cols, BORDER_CONSTANT, BLACK);
  958. }
  959. //Dbg("m_winSize: %d, %d", m_winSize.width, m_winSize.height);
  960. //Dbg("m_cmFrame: %d, %d", m_cmFrame.cols, m_cmFrame.rows);
  961. drawableRect.x = cols;
  962. drawableRect.width = origin.cols;
  963. drawableRect.y = rows;
  964. drawableRect.height = origin.rows;
  965. Mat picture = m_cmFrame.clone();
  966. _setInterestArea();
  967. imshow(winName, m_cmFrame);
  968. char keyCode = cvWaitKey(WAITKEY_TIME);
  969. //if(keyCode == 27) {
  970. // Dbg("ESC key press event recv.");
  971. // break;
  972. //}
  973. RequestEventPtr evtPtr = GetRequest();
  974. if(evtPtr) {
  975. Dbg("0x%02x event recv.", evtPtr->evtCode);
  976. switch(evtPtr->evtCode)
  977. {
  978. case EVTCODE_SCAN:
  979. {
  980. assert(evtPtr->valType == RequestEvent::ReqLen);
  981. assert(evtPtr->dwDataLen > 0 && evtPtr->evtData);
  982. char szFileName[MAX_PATH+1] = {0};
  983. memcpy_s(szFileName, MAX_PATH*sizeof(char),
  984. evtPtr->evtData, sizeof(char)*evtPtr->dwDataLen);
  985. try
  986. {
  987. cv::Mat testMat;
  988. if(rectStatus == SET && (rect.width != 0 && rect.height != 0)) {
  989. Mat result(picture, rect);
  990. //imwrite(szFileName, result);
  991. Dbg("ScanImage@1: %s %d", szFileName, result.size());
  992. testMat = result.clone();
  993. } else {
  994. //imwrite(szFileName, origin);
  995. Dbg("ScanImage@2: %s %d", szFileName, origin.size());
  996. testMat = origin.clone();
  997. }
  998. ImageWriteUntil(szFileName, testMat);
  999. //cv::Mat destMat;
  1000. /*int compatRate = MatResize(testMat, destMat, 100);
  1001. compatRate = compatRate > 0 ? compatRate + 1: 100;*/
  1002. //const int compatRate = 90;
  1003. //Dbg("set compress rate: %d", compatRate);
  1004. //vector<int> comprressionParams;
  1005. //comprressionParams.push_back(CV_IMWRITE_JPEG_QUALITY);
  1006. //comprressionParams.push_back(compatRate);
  1007. //default one
  1008. //comprressionParams.push_back(IMWRITE_JPEG_OPTIMIZE);
  1009. //comprressionParams.push_back(1);
  1010. //imwrite(szFileName, testMat, comprressionParams);
  1011. //Resize(szFileName, GetFileSize(szFileName), compatRate);
  1012. evtPtr->evtStatus = EVTSTATUS_DONE_SUCC;
  1013. }
  1014. catch(cv::Exception& ex)
  1015. {
  1016. Dbg("exception converting image to jpeg: %s", ex.what());
  1017. evtPtr->evtStatus = EVTSTATUS_DONE_FAIL;
  1018. }
  1019. evtPtr->OnAnswer();
  1020. }
  1021. break;
  1022. default:
  1023. {
  1024. }
  1025. break;
  1026. }
  1027. }
  1028. if(m_tpStopPreview) {
  1029. Dbg("Stop previewing event recv.");
  1030. break;
  1031. }
  1032. }
  1033. SetThreadExecutionState(ES_CONTINUOUS);
  1034. _destroyWindow();
  1035. m_fPreviewing = false;
  1036. return true;
  1037. }
  1038. int CDocScannerCap::GetSpecificedCamInfor(const int camID, PCAMERA_INFOR_ITEM info)
  1039. {
  1040. if(info == NULL) {
  1041. return -2;
  1042. }
  1043. info->Cleanup();
  1044. // Create the System Device Enumerator.
  1045. ICreateDevEnum *pSysDevEnum = NULL;
  1046. HRESULT hr = CoCreateInstance(
  1047. CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
  1048. IID_ICreateDevEnum, (void **)&pSysDevEnum);
  1049. if (FAILED(hr)) {
  1050. return -1;
  1051. }
  1052. BOOL done = false;
  1053. int deviceCounter = 0;
  1054. // Obtain a class enumerator for the video input category.
  1055. IEnumMoniker *pEnumCat = NULL;
  1056. hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
  1057. if (hr == S_OK) {
  1058. // Enumerate the monikers.
  1059. IMoniker *pMoniker = NULL;
  1060. ULONG cFetched;
  1061. while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (!done)) {
  1062. if(deviceCounter == camID) {
  1063. // Bind the first moniker to an object
  1064. IPropertyBag *pPropBag;
  1065. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
  1066. if (SUCCEEDED(hr)) {
  1067. // To retrieve the filter's friendly name, do the following:
  1068. VARIANT varName;
  1069. VariantInit(&varName);
  1070. hr = pPropBag->Read(L"Description", &varName, 0);
  1071. if (FAILED(hr)) {
  1072. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  1073. }
  1074. if (SUCCEEDED(hr)) {
  1075. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  1076. int maxLen = sizeof(info->szDevName) - 2;
  1077. int nLen = WrapW2A(varName, &(info->szDevName[0]), maxLen);
  1078. VariantClear(&varName);
  1079. }
  1080. VARIANT varCLSID;
  1081. VariantInit(&varCLSID);
  1082. hr = pPropBag->Read(L"CLSID", &varCLSID, 0);
  1083. if (SUCCEEDED(hr)) {
  1084. int maxLen = sizeof(info->szCLSID) - 2;
  1085. int nLen = WrapW2A(varCLSID, &(info->szCLSID[0]), maxLen);
  1086. VariantClear(&varCLSID);
  1087. }
  1088. VARIANT varDevPath;
  1089. VariantInit(&varDevPath);
  1090. hr = pPropBag->Read(L"DevicePath", &varDevPath, 0);
  1091. if (SUCCEEDED(hr)) {
  1092. int maxLen = sizeof(info->szDevPath) - 2;
  1093. int nLen = WrapW2A(varDevPath, &(info->szDevPath[0]), maxLen);
  1094. VariantClear(&varDevPath);
  1095. }
  1096. VARIANT varWaveID;
  1097. VariantInit(&varWaveID);
  1098. hr = pPropBag->Read(L"WaveInID", &varWaveID, 0);
  1099. if (SUCCEEDED(hr)) {
  1100. info->uWaveInID = varWaveID.lVal;
  1101. VariantClear(&varWaveID);
  1102. }
  1103. pPropBag->Release();
  1104. pPropBag = NULL;
  1105. pMoniker->Release();
  1106. pMoniker = NULL;
  1107. done = TRUE;
  1108. }
  1109. }
  1110. deviceCounter++;
  1111. }
  1112. pEnumCat->Release();
  1113. pEnumCat = NULL;
  1114. }
  1115. pSysDevEnum->Release();
  1116. pSysDevEnum = NULL;
  1117. if (done) {
  1118. return 1;
  1119. }
  1120. return 0;
  1121. }
  1122. int CDocScannerCap::_getCamIDByDevName(LPCTSTR lpcszDevName)
  1123. {
  1124. if (lpcszDevName == NULL || strlen(lpcszDevName) == 0) {
  1125. return -2;
  1126. }
  1127. ICreateDevEnum *pDevEnum = NULL;
  1128. IEnumMoniker *pEnum = NULL;
  1129. int deviceCounter = 0;
  1130. int aimID = -1;
  1131. bool done = false;
  1132. HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
  1133. CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
  1134. reinterpret_cast<void**>(&pDevEnum));
  1135. if (SUCCEEDED(hr)) {
  1136. // Create an enumerator for the video capture category.
  1137. hr = pDevEnum->CreateClassEnumerator(
  1138. CLSID_VideoInputDeviceCategory,
  1139. &pEnum, 0);
  1140. if(hr == S_OK) {
  1141. IMoniker *pMoniker = NULL;
  1142. while (pEnum->Next(1, &pMoniker, NULL) == S_OK && (!done)) {
  1143. IPropertyBag *pPropBag;
  1144. hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
  1145. (void**)(&pPropBag));
  1146. if (FAILED(hr)){
  1147. pMoniker->Release();
  1148. continue; // Skip this one, maybe the next one will work.
  1149. }
  1150. // Find the description or friendly name.
  1151. VARIANT varName;
  1152. VariantInit(&varName);
  1153. hr = pPropBag->Read(L"Description", &varName, 0);
  1154. if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  1155. if (SUCCEEDED(hr)){
  1156. hr = pPropBag->Read(L"FriendlyName", &varName, 0);
  1157. char szDevName[MAX_PATH + 2] = {0};
  1158. int count = 0;
  1159. while( varName.bstrVal[count] != 0x00 && count < MAX_PATH) {
  1160. szDevName[count] = (char)varName.bstrVal[count];
  1161. count++;
  1162. }
  1163. szDevName[count] = 0;
  1164. if(strcmp(szDevName, lpcszDevName) == 0) {
  1165. done = true;
  1166. aimID = deviceCounter;
  1167. }
  1168. }
  1169. pPropBag->Release();
  1170. pPropBag = NULL;
  1171. pMoniker->Release();
  1172. pMoniker = NULL;
  1173. deviceCounter++;
  1174. }
  1175. pDevEnum->Release();
  1176. pDevEnum = NULL;
  1177. pEnum->Release();
  1178. pEnum = NULL;
  1179. }
  1180. }
  1181. return aimID;
  1182. }
  1183. bool CDocScannerCap::IsColorAbnormal(IplImage* src)
  1184. {
  1185. const int threshold = 3;
  1186. const int width = src->width;
  1187. const int height = src->height;
  1188. int imax = 0, imin = 255;
  1189. uchar *content = (uchar*)src->imageData;
  1190. int step = src->widthStep/sizeof(uchar);
  1191. for (int i=0; i<height; ++i) {
  1192. for(int j=0; j<width; ++j) {
  1193. int term = (int)content[i*step+j];
  1194. if(term > imax) {
  1195. imax = term;
  1196. }
  1197. if(term < imin) {
  1198. imin = term;
  1199. }
  1200. }
  1201. }
  1202. if(imax - imin < threshold) {
  1203. return true;
  1204. }
  1205. return false;
  1206. }
  1207. bool CDocScannerCap::IsFrameFuzzy(IplImage* data)
  1208. {
  1209. //图片每行字节数及高
  1210. int width=data->widthStep;
  1211. int height=data->height;
  1212. ushort* sobelTable = new ushort[width*height];
  1213. memset(sobelTable, 0, width*height*sizeof(ushort));
  1214. int i, j, mul;
  1215. //指向图像首地址
  1216. uchar* udata = (uchar*)data->imageData;
  1217. for(i = 1, mul = i*width; i < height - 1; i++, mul += width) {
  1218. for(j = 1; j < width - 1; j++) {
  1219. sobelTable[mul+j]=abs(udata[mul+j-width-1] + 2*udata[mul+j-1] + udata[mul+j-1+width] -\
  1220. udata[mul+j+1-width] - 2*udata[mul+j+1] - udata[mul+j+width+1]);
  1221. }
  1222. }
  1223. for(i = 1, mul = i*width; i < height - 1; i++, mul += width) {
  1224. for(j = 1; j < width - 1; j++) {
  1225. if(sobelTable[mul+j] < 50 || sobelTable[mul+j] <= sobelTable[mul+j-1] ||\
  1226. sobelTable[mul+j] <= sobelTable[mul+j+1]) sobelTable[mul+j] = 0;
  1227. }
  1228. }
  1229. int totLen = 0;
  1230. int totCount = 1;
  1231. uchar suddenThre = 50;
  1232. uchar sameThre = 3;
  1233. //遍历图片
  1234. for(i = 1, mul = i*width; i < height - 1; i++, mul += width) {
  1235. for(j = 1; j < width - 1; j++) {
  1236. if(sobelTable[mul+j]) {
  1237. int count = 0;
  1238. uchar tmpThre = 5;
  1239. uchar max = udata[mul+j] > udata[mul+j-1] ? 0 : 1;
  1240. for(int t = j; t > 0; t--) {
  1241. count++;
  1242. if(abs(udata[mul+t] - udata[mul+t-1]) > suddenThre) {
  1243. break;
  1244. }
  1245. if(max && udata[mul+t] > udata[mul+t-1]) {
  1246. break;
  1247. }
  1248. if(!max && udata[mul+t] < udata[mul+t-1]) {
  1249. break;
  1250. }
  1251. int tmp = 0;
  1252. for(int s = t; s > 0; s--) {
  1253. if(abs(udata[mul+t] - udata[mul+s]) < sameThre) {
  1254. tmp++;
  1255. if(tmp > tmpThre) {
  1256. break;
  1257. }
  1258. }
  1259. else {
  1260. break;
  1261. }
  1262. }
  1263. if(tmp > tmpThre) break;
  1264. }
  1265. max = udata[mul+j] > udata[mul+j+1] ? 0 : 1;
  1266. for(int t = j; t < width; t++) {
  1267. count++;
  1268. if(abs(udata[mul+t] - udata[mul+t+1]) > suddenThre) {
  1269. break;
  1270. }
  1271. if(max && udata[mul+t] > udata[mul+t+1]) {
  1272. break;
  1273. }
  1274. if(!max && udata[mul+t] < udata[mul+t+1]) {
  1275. break;
  1276. }
  1277. int tmp = 0;
  1278. for(int s = t; s < width; s++) {
  1279. if(abs(udata[mul+t] - udata[mul+s]) < sameThre) {
  1280. tmp++;
  1281. if(tmp > tmpThre) {
  1282. break;
  1283. }
  1284. }
  1285. else {
  1286. break;
  1287. }
  1288. }
  1289. if(tmp > tmpThre) {
  1290. break;
  1291. }
  1292. }
  1293. max = udata[mul+j] > udata[mul+j+1] ? 0 : 1;
  1294. for(int t = j; t < width; t++) {
  1295. count++;
  1296. if(abs(udata[mul+t] - udata[mul+t+1]) > suddenThre) {
  1297. break;
  1298. }
  1299. if(max && udata[mul+t] > udata[mul+t+1]) {
  1300. break;
  1301. }
  1302. if(!max && udata[mul+t] < udata[mul+t+1]) {
  1303. break;
  1304. }
  1305. int tmp = 0;
  1306. for(int s = t; s < width; s++) {
  1307. if(abs(udata[mul+t] - udata[mul+s]) < sameThre) {
  1308. tmp++;
  1309. if(tmp > tmpThre) {
  1310. break;
  1311. }
  1312. }
  1313. else {
  1314. break;
  1315. }
  1316. }
  1317. if(tmp > tmpThre) {
  1318. break;
  1319. }
  1320. }
  1321. count--;
  1322. totCount++;
  1323. totLen += count;
  1324. }
  1325. }
  1326. }
  1327. //模糊度
  1328. float result = (float)totLen/totCount;
  1329. delete[] sobelTable;
  1330. if(result > 5) {
  1331. return true;
  1332. }
  1333. return false;
  1334. }
  1335. bool CDocScannerCap::ResetCamera()
  1336. {
  1337. if(!_isVal() && m_videoID == -1) {
  1338. Dbg("Nothing to do with ResetCamera(%d)", m_videoID);
  1339. return true;
  1340. }
  1341. bool fPreview = m_fPreviewing;
  1342. BOOL bHide = m_bHide;
  1343. if(m_fPreviewing) {
  1344. TerminatePreview();
  1345. do {
  1346. Sleep(100);
  1347. } while (m_fPreviewing);
  1348. }
  1349. if(m_cvCap.isOpened()) {
  1350. m_cvCap.release();
  1351. }
  1352. CAMERA_INFOR_ITEM item;
  1353. if(GetSpecificedCamInfor(m_videoID, &item) <= 0) {
  1354. m_dwErrCode = ERROR_FILE_NOT_FOUND;
  1355. _cleanup();
  1356. return true;
  1357. }
  1358. int nRes = IsDeviceBusy(item.szDevName);
  1359. if(nRes) {
  1360. if(nRes == -2) {
  1361. m_dwErrCode = ERROR_INVALID_ACCESS;
  1362. } else if(nRes == -1) {
  1363. m_dwErrCode = ERROR_FILE_NOT_FOUND;
  1364. } else if(nRes == 1) {
  1365. m_dwErrCode = ERROR_DEVICE_IN_USE;
  1366. } else {
  1367. m_dwErrCode = ERROR_BAD_ENVIRONMENT;
  1368. }
  1369. _cleanup();
  1370. return true;
  1371. }
  1372. m_cvCap.open(m_videoID);
  1373. if(!m_cvCap.isOpened()) {
  1374. _cleanup();
  1375. return false;
  1376. }
  1377. _destroyWindow();
  1378. winName = cv::String(DEFAULT_MAT_WINDOW_NAME) + "-" + item.szDevName;
  1379. _setDevName(item.szDevName);
  1380. m_dwErrCode = ERROR_SUCCESS;
  1381. //SetWinShown(m_hideMode != 0 ? false : true);
  1382. if(fPreview && !StartPreview()) {
  1383. Dbg("StartPreview failed");
  1384. return true;
  1385. }else if(fPreview && bHide) {
  1386. SetWinShown(false);
  1387. }
  1388. return true;
  1389. }
  1390. int CDocScannerCap::MatResize(const cv::Mat& src, cv::Mat& dest, int quantity)
  1391. {
  1392. const int aim_size = 1*1024*1024;
  1393. std::vector<int> params;
  1394. params.push_back(cv::IMWRITE_JPEG_QUALITY);
  1395. params.push_back(quantity);
  1396. std::vector<unsigned char> buff;
  1397. cv::imencode(".jpg", src, buff, params);
  1398. Dbg("after buffer: size: %d, with quantity: %d", buff.size(), quantity);
  1399. dest = cv::imdecode(buff, CV_LOAD_IMAGE_COLOR);
  1400. if(buff.size() > aim_size)
  1401. return (int)(aim_size * 1.2f / buff.size() * 100);
  1402. return 0;
  1403. }
  1404. DWORD CDocScannerCap::GetFileSize(LPCTSTR srcFilePath)
  1405. {
  1406. FILE* fHandle = fopen(srcFilePath, "rb");
  1407. if(!fHandle)
  1408. return -1;
  1409. fseek(fHandle, 0, SEEK_END);
  1410. DWORD fileSize = ftell(fHandle);
  1411. Dbg("get the file size: %lu", fileSize);
  1412. fclose(fHandle);
  1413. return fileSize;
  1414. }
  1415. int CDocScannerCap::ImageWriteUntil(LPCTSTR srcFilePath, const cv::Mat& src)
  1416. {
  1417. const int aim_size = 1*1024*1024;
  1418. int compatRates[] = {95, 90, 85, 80, 70, 60, 50, 40, 30, 20, 15};
  1419. for(int i=0; i<sizeof(compatRates)/sizeof(compatRates[0]); ++i)
  1420. {
  1421. const int compatRate = compatRates[i];
  1422. Dbg("set compress rate: %d", compatRate);
  1423. vector<int> comprressionParams;
  1424. comprressionParams.push_back(CV_IMWRITE_JPEG_QUALITY);
  1425. comprressionParams.push_back(compatRate);
  1426. try
  1427. {
  1428. imwrite(srcFilePath, src, comprressionParams);
  1429. } catch(cv::Exception& ex)
  1430. {
  1431. Dbg("exception converting image to jpeg: %s", ex.what());
  1432. return -1;
  1433. }
  1434. Sleep(50);
  1435. const auto fileSize = GetFileSize(srcFilePath);
  1436. if(fileSize == (DWORD)-1)
  1437. return -1;
  1438. if(fileSize <= aim_size)
  1439. return 0;
  1440. }
  1441. return 1;
  1442. }
  1443. int CDocScannerCap::Resize(LPCTSTR srcFilePath, DWORD dwSrcFileSize, int compressRate)
  1444. {
  1445. const int aim_size = 1*1024*1024;
  1446. if(dwSrcFileSize == -1 || aim_size >= dwSrcFileSize)
  1447. return 0;
  1448. cv::Mat src = cv::imread(srcFilePath);
  1449. if(src.empty())
  1450. return -1;
  1451. float rate = sqrt(aim_size * 1.0f / dwSrcFileSize);
  1452. Dbg("rate: %f", rate);
  1453. int width = static_cast<int>(src.cols*rate);
  1454. int height = static_cast<int>(src.rows*rate);
  1455. cv::Mat dest;
  1456. resize(src, dest, cv::Size(width, height));
  1457. vector<int> comprressionParams;
  1458. comprressionParams.push_back(CV_IMWRITE_JPEG_QUALITY);
  1459. comprressionParams.push_back(compressRate);
  1460. imwrite(srcFilePath, dest, comprressionParams);
  1461. FILE* fHandle = fopen(srcFilePath, "rb");
  1462. fseek(fHandle, 0, SEEK_END);
  1463. long fileSize = ftell(fHandle);
  1464. fclose(fHandle);
  1465. Dbg("get the resize file size: %ld", fileSize);
  1466. return 1;
  1467. }
  1468. LRESULT CALLBACK CameraNotifierProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  1469. {
  1470. if (message == WM_DEVICECHANGE) {
  1471. if (DBT_DEVICEARRIVAL != wParam && DBT_DEVICEREMOVECOMPLETE != wParam) {
  1472. return TRUE;
  1473. }
  1474. PDEV_BROADCAST_HDR pdbh = (PDEV_BROADCAST_HDR)lParam;
  1475. if (pdbh->dbch_devicetype != DBT_DEVTYP_DEVICEINTERFACE) {
  1476. return TRUE;
  1477. }
  1478. PDEV_BROADCAST_DEVICEINTERFACE pdbi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
  1479. if (pdbi->dbcc_classguid == AM_KSCATEGORY_VIDEO) {
  1480. if (DBT_DEVICEARRIVAL == wParam) {
  1481. printf("receive AM_KSCATEGORY_VIDEO change add \n");
  1482. } else if (DBT_DEVICEREMOVECOMPLETE == wParam) {
  1483. printf("receive AM_KSCATEGORY_VIDEO change remove \n");
  1484. }
  1485. }
  1486. return TRUE;
  1487. }
  1488. return DefWindowProc(hWnd, message, wParam, lParam);
  1489. }
  1490. void OnMouseTrace(int event, int x, int y, int flags, void* param /*= NULL*/)
  1491. {
  1492. CDocScannerCap* pCap = reinterpret_cast<CDocScannerCap*>(param);
  1493. if(pCap == NULL) {
  1494. Dbg("OnMouseTest::param is NULL!");
  1495. return;
  1496. }
  1497. pCap->MouseClick(event, x, y, flags);
  1498. }