ScannerViewController.m 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. /*
  2. Copyright 2013 Scott Logic Ltd
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. #import "ScannerViewController.h"
  14. @import AVFoundation;
  15. #import <AudioToolbox/AudioToolbox.h>
  16. #import "SCShapeView.h"
  17. #import "ScannerControllerView.h"
  18. //#import "DetailViewController.h"
  19. #import "const.h"
  20. #import "AppDelegate.h"
  21. //#import "MainViewController.h"
  22. //#import "ContactListViewController.h"
  23. //#import "CartUtils.h"
  24. #import "RAUtils.h"
  25. #define SCANNER_TARGET_DETAIL 0
  26. #define SCANNER_TARGET_CART 1
  27. //#import "ScannerControlViewController.h"
  28. @interface ScannerViewController () <AVCaptureMetadataOutputObjectsDelegate> {
  29. AVCaptureVideoPreviewLayer *_previewLayer;
  30. SCShapeView *_boundingBox;
  31. NSTimer *_boxHideTimer;
  32. UILabel *_decodedMessage;
  33. }
  34. @end
  35. @implementation ScannerViewController
  36. //- (UIInterfaceOrientationMask)supportedInterfaceOrientations
  37. //{
  38. // return UIInterfaceOrientationMaskPortrait;
  39. //}
  40. //- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
  41. //{
  42. //
  43. // return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
  44. //
  45. //}
  46. - (BOOL)shouldAutorotate
  47. {
  48. return false;
  49. }
  50. - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
  51. {
  52. [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
  53. [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) {
  54. // 使用新的方法获取设备方向
  55. UIInterfaceOrientation orientation;
  56. // if (@available(iOS 13.0, *)) {
  57. UIWindowScene *windowScene = (UIWindowScene *)self.view.window.windowScene;
  58. orientation = windowScene.interfaceOrientation;
  59. // } else {
  60. // orientation = [[UIApplication sharedApplication] statusBarOrientation];
  61. // }
  62. // 计算新的 rect
  63. CGRect rect = CGRectMake(0, 0, size.width, size.height);
  64. DebugLog(@"%@", NSStringFromCGRect(self.focusZone.frame));
  65. [CATransaction begin];
  66. [CATransaction setDisableActions:YES]; // 禁用隐式动画,使用 coordinator 的动画
  67. // 更新 previewLayer
  68. self->_previewLayer.position = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
  69. self->_previewLayer.bounds = rect;
  70. // 设置视频方向
  71. switch (orientation) {
  72. case UIInterfaceOrientationPortrait:
  73. self->_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
  74. break;
  75. case UIInterfaceOrientationPortraitUpsideDown:
  76. self->_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
  77. break;
  78. case UIInterfaceOrientationLandscapeLeft:
  79. self->_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
  80. break;
  81. case UIInterfaceOrientationLandscapeRight:
  82. self->_previewLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
  83. break;
  84. default:
  85. break;
  86. }
  87. [CATransaction commit];
  88. } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) {
  89. // 转场完成后的操作(如果需要)
  90. }];
  91. }
  92. //
  93. //- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
  94. //{
  95. //// [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
  96. //// {
  97. //// UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
  98. //// // do whatever
  99. //// } completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
  100. //// {
  101. ////
  102. //// }];
  103. // CGRect rect=self.view.bounds;
  104. //
  105. // DebugLog(@"%@",NSStringFromCGRect(self.focusZone.frame));
  106. // // rect.origin.y=rect.origin.y+40;
  107. // // rect.size.height = rect.size.height-40;
  108. //
  109. //
  110. //
  111. //
  112. //
  113. //
  114. //
  115. // [CATransaction begin];
  116. // [CATransaction setAnimationDuration:0.5];
  117. // [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
  118. //// [self updatePreviewLayerForOrientation:toInterfaceOrientation];
  119. // _previewLayer.position = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
  120. //
  121. // // self.backgroundView.highLightRect = CGRectInset(self.focusZone.frame,6,6);
  122. // _previewLayer.bounds = rect;
  123. //
  124. //// UIInterfaceOrientation orientation = [[UIApplication sharedApplication]statusBarOrientation];
  125. //// switch (orientation) {
  126. ////
  127. ////
  128. ////
  129. //// case UIInterfaceOrientationPortrait:
  130. //// // [_previewLayer setAffineTransform:CGAffineTransformMakeRotation(0)];
  131. ////
  132. //// _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationPortrait;
  133. //// break;
  134. //// case UIInterfaceOrientationPortraitUpsideDown:
  135. //// //[_previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI)];
  136. //// _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationPortraitUpsideDown;
  137. //// break;
  138. //// case UIInterfaceOrientationLandscapeLeft:
  139. //// // [_previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI/2)];
  140. //// _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationLandscapeLeft;
  141. //// break;
  142. //// case UIInterfaceOrientationLandscapeRight:
  143. //// // [_previewLayer setAffineTransform:CGAffineTransformMakeRotation(-M_PI/2)];
  144. //// _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationLandscapeRight;
  145. //// break;
  146. //// default:
  147. //// break;
  148. //// }
  149. // [CATransaction commit];
  150. // [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
  151. //}
  152. //-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
  153. //{
  154. //
  155. //
  156. // [super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
  157. // CGRect rect=self.view.bounds;
  158. //
  159. // DebugLog(@"%@",NSStringFromCGRect(self.focusZone.frame));
  160. // // rect.origin.y=rect.origin.y+40;
  161. // // rect.size.height = rect.size.height-40;
  162. //
  163. //
  164. //
  165. //
  166. //
  167. //
  168. //
  169. // [CATransaction begin];
  170. // [CATransaction setAnimationDuration:0.5];
  171. // [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
  172. //// [self updatePreviewLayerForOrientation:toInterfaceOrientation];
  173. // _previewLayer.position = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
  174. //
  175. // // self.backgroundView.highLightRect = CGRectInset(self.focusZone.frame,6,6);
  176. // _previewLayer.bounds = rect;
  177. //
  178. // UIInterfaceOrientation orientation = [[UIApplication sharedApplication]statusBarOrientation];
  179. // switch (orientation) {
  180. //
  181. //
  182. //
  183. // case UIInterfaceOrientationPortrait:
  184. // // [_previewLayer setAffineTransform:CGAffineTransformMakeRotation(0)];
  185. //
  186. // _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationPortrait;
  187. // break;
  188. // case UIInterfaceOrientationPortraitUpsideDown:
  189. // //[_previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI)];
  190. // _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationPortraitUpsideDown;
  191. // break;
  192. // case UIInterfaceOrientationLandscapeLeft:
  193. // // [_previewLayer setAffineTransform:CGAffineTransformMakeRotation(M_PI/2)];
  194. // _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationLandscapeLeft;
  195. // break;
  196. // case UIInterfaceOrientationLandscapeRight:
  197. // // [_previewLayer setAffineTransform:CGAffineTransformMakeRotation(-M_PI/2)];
  198. // _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationLandscapeRight;
  199. // break;
  200. // default:
  201. // break;
  202. // }
  203. // [CATransaction commit];
  204. //
  205. //
  206. //}
  207. //- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
  208. //{
  209. // return UIInterfaceOrientationPortrait;
  210. //}
  211. -(void) playSound
  212. {
  213. /*
  214. SystemSoundID sameViewSoundID;
  215. // NSString *filePath = [[NSBundle mainBundle]pathForResource:@"sound" ofType:@"m4r"];
  216. // NSString *thesoundFilePath = [[NSBundle mainBundle] pathForResource:@"sound" ofType:@"wav"]; //音乐文件路径
  217. NSString *path = @"/System/Library/Audio/UISounds/begin_video_record.caf";
  218. CFURLRef thesoundURL = (__bridge CFURLRef) [NSURL fileURLWithPath:path] ;
  219. AudioServicesCreateSystemSoundID(thesoundURL, &sameViewSoundID);
  220. //变量SoundID与URL对应
  221. DebugLog(@"%u",(unsigned int)sameViewSoundID);
  222. AudioServicesPlaySystemSound(1112); //播放SoundID声音
  223. */
  224. CFBundleRef mainBundle;
  225. SystemSoundID soundFileObject;
  226. mainBundle = CFBundleGetMainBundle ();
  227. CFURLRef soundFileURLRef = CFBundleCopyResourceURL (
  228. mainBundle,
  229. CFSTR ("softScanBeep" ),
  230. CFSTR ("wav" ),
  231. NULL
  232. );
  233. AudioServicesCreateSystemSoundID (
  234. soundFileURLRef,
  235. &soundFileObject
  236. );
  237. AudioServicesPlaySystemSound(soundFileObject);
  238. }
  239. - (void)viewWillAppear:(BOOL)animated
  240. {
  241. [super viewWillAppear:animated];
  242. [[self navigationController] setNavigationBarHidden:NO animated:NO];
  243. //
  244. //[ attemptRotationToDeviceOrientation];
  245. //[UIViewController attemptRotationToDeviceOrientation];
  246. //
  247. // [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
  248. // self.view.transform = CGAffineTransformMakeRotation(M_PI/2);
  249. // CGRect frame = [UIScreen mainScreen].applicationFrame;
  250. // self.view.bounds = CGRectMake(0, 0, 768, 1024);
  251. }
  252. - (void)onBackClick:(UIButton *)sender {
  253. [self.navigationController popViewControllerAnimated:FALSE];
  254. }
  255. - (void)viewDidLoad
  256. {
  257. [super viewDidLoad];
  258. UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"back"] imageWithRenderingMode:UIImageRenderingModeAutomatic]
  259. style:UIBarButtonItemStylePlain
  260. target:self
  261. action:@selector( onBackClick:)];
  262. // closeButton.tintColor = UIColorFromRGB(0x996633);
  263. self.navigationItem.leftBarButtonItem = closeButton;
  264. }
  265. - (void)viewDidAppear:(BOOL)animated {
  266. [super viewDidAppear:animated];
  267. // 只有在此方法中取得的self.focusZone.frame才正确。
  268. // return;
  269. // [self.backgroundView removeFromSuperview];
  270. //self.back = (ScannerControllerView*)self.view;
  271. self.backgroundView.highLightRect = CGRectInset(self.focusZone.frame,6,6);
  272. [self.backgroundView setNeedsDisplay];
  273. // self.backgroundView.autoresizingMask=0xff;
  274. self.handelOutput = false;
  275. // self.ScannerControl =[self.storyboard instantiateViewControllerWithIdentifier:@"ScannerControlViewController"];
  276. // self.ScannerControl.Scannerdelegate = self;
  277. // self.view.layer.
  278. // Do any additional setup after loading the view, typically from a nib.
  279. // Create a new AVCaptureSession
  280. AVCaptureSession *session = [[AVCaptureSession alloc] init];
  281. session.sessionPreset = AVCaptureSessionPresetHigh;
  282. AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
  283. // float factor = device.videoZoomFactor;
  284. // float up = device.activeFormat.videoZoomFactorUpscaleThreshold;
  285. // [device lockForConfiguration:nil];
  286. // device.videoZoomFactor = device.activeFormat.videoZoomFactorUpscaleThreshold;
  287. // [device unlockForConfiguration];
  288. NSError *error = nil;
  289. // Want the normal device
  290. AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
  291. if(input) {
  292. // Add the input to the session
  293. [session addInput:input];
  294. } else {
  295. __weak typeof(self) weakself = self;
  296. // UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Camera access denied, please change iPad setting, allow App use camara. (setting -> privacy -> camera enable RA Image)" preferredStyle:UIAlertControllerStyleAlert];
  297. // UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  298. // [weakself dismissViewControllerAnimated:YES completion:nil];
  299. // }];
  300. // [alert addAction:action];
  301. // [self presentViewController:alert animated:YES completion:nil];
  302. if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { // 设备不可用
  303. UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Camera is not available" preferredStyle:UIAlertControllerStyleAlert];
  304. UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  305. [weakself dismissViewControllerAnimated:YES completion:nil];
  306. }];
  307. [alert addAction:action];
  308. [self presentViewController:alert animated:YES completion:nil];
  309. return;
  310. }
  311. // 相机权限
  312. AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
  313. if (authStatus ==AVAuthorizationStatusRestricted ||//此应用程序没有被授权访问的照片数据。可能是家长控制权限
  314. authStatus ==AVAuthorizationStatusDenied) //用户已经明确否认了这一照片数据的应用程序访问
  315. {
  316. // 无权限 引导去开启
  317. // NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
  318. // if ([[UIApplication sharedApplication]canOpenURL:url]) {
  319. // [[UIApplication sharedApplication]openURL:url];// 打开权限后返回应用会重启
  320. // } else {
  321. NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary];
  322. NSString *appName = [infoDict objectForKey:@"CFBundleName"];
  323. UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert];
  324. UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
  325. [weakself dismissViewControllerAnimated:YES completion:nil];
  326. }];
  327. [alert addAction:action];
  328. [self presentViewController:alert animated:YES completion:nil];
  329. // }
  330. return;
  331. }
  332. return;
  333. }
  334. AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init];
  335. // Have to add the output before setting metadata types
  336. [session addOutput:output];
  337. // What different things can we register to recognise?
  338. DebugLog(@"%@", [output availableMetadataObjectTypes]);
  339. // We're only interested in QR Codes
  340. [output setMetadataObjectTypes:@[AVMetadataObjectTypeUPCECode,AVMetadataObjectTypeCode39Code,AVMetadataObjectTypeCode39Mod43Code,AVMetadataObjectTypeEAN13Code,AVMetadataObjectTypeEAN8Code,AVMetadataObjectTypeCode93Code,AVMetadataObjectTypeCode128Code,AVMetadataObjectTypePDF417Code,AVMetadataObjectTypeQRCode,AVMetadataObjectTypeAztecCode]];
  341. DebugLog(@"%@", [output metadataObjectTypes]);
  342. // NSArray* supporttype=output.availableMetadataObjectTypes;
  343. // [output setMetadataObjectTypes:output.availableMetadataObjectTypes];
  344. // This VC is the delegate. Please call us on the main queue
  345. [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
  346. //
  347. // CGRect rt1 = self.ScannerControl.scannerZone.frame;
  348. // Display on screen
  349. _previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:session];
  350. _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
  351. // _previewLayer.orientation= AVCaptureVideoOrientationLandscapeRight;
  352. UIInterfaceOrientation orientation = [[UIApplication sharedApplication]statusBarOrientation];
  353. switch (orientation) {
  354. // UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
  355. // UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
  356. // UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
  357. // UIInterfaceOrientationLandscapeRight
  358. // AVCaptureVideoOrientationPortrait = 1,
  359. // AVCaptureVideoOrientationPortraitUpsideDown = 2,
  360. // AVCaptureVideoOrientationLandscapeRight = 3,
  361. // AVCaptureVideoOrientationLandscapeLeft = 4,
  362. case UIInterfaceOrientationPortrait:
  363. _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationPortrait;
  364. break;
  365. case UIInterfaceOrientationPortraitUpsideDown:
  366. _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationPortraitUpsideDown;
  367. break;
  368. case UIInterfaceOrientationLandscapeLeft:
  369. _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationLandscapeLeft;
  370. break;
  371. case UIInterfaceOrientationLandscapeRight:
  372. _previewLayer.connection.videoOrientation=AVCaptureVideoOrientationLandscapeRight;
  373. break;
  374. default:
  375. break;
  376. }
  377. CGRect rect=self.view.bounds;
  378. // rect.origin.y=rect.origin.y+40;
  379. // rect.size.height = rect.size.height-40;
  380. _previewLayer.bounds = rect;
  381. _previewLayer.position = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));
  382. // [self.view.layer addSublayer:_previewLayer];
  383. [self.view.layer insertSublayer:_previewLayer atIndex:0];
  384. // [self.view addSubview:self.backgroundView];
  385. [self.view bringSubviewToFront:self.backgroundView];
  386. // [self.view addSubview:self.ScannerControl.view];
  387. // CGRect rt = self.ScannerControl.scannerZone.bounds;
  388. // CGRect rt1 =output.rectOfInterest;
  389. // output.rectOfInterest = CGRectMake(0, 0, 300, 300); //self.ScannerControl.scannerZone.frame;
  390. // ScannerControllerView* view =[[ ScannerControllerView alloc] initWithFrame:self.view.frame];
  391. // view.backgroundColor = [UIColor clearColor];
  392. // ScannerLayer * layer = [[ScannerLayer alloc] init];
  393. // [self.view.layer addSublayer:layer];
  394. // Add the view to draw the bounding box for the UIView
  395. _boundingBox = [[SCShapeView alloc] initWithFrame:self.view.bounds];
  396. _boundingBox.backgroundColor = [UIColor clearColor];
  397. _boundingBox.hidden = YES;
  398. [self.view insertSubview:_boundingBox belowSubview:self.backgroundView];
  399. // Add a label to display the resultant message
  400. _decodedMessage = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetHeight(self.view.bounds) - 75, CGRectGetWidth(self.view.bounds), 75)];
  401. _decodedMessage.numberOfLines = 0;
  402. _decodedMessage.backgroundColor = [UIColor colorWithWhite:0.8 alpha:0.9];
  403. _decodedMessage.textColor = [UIColor darkGrayColor];
  404. _decodedMessage.textAlignment = NSTextAlignmentCenter;
  405. [self.view addSubview:_decodedMessage];
  406. _decodedMessage.userInteractionEnabled = YES;
  407. UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
  408. [backBtn setTitle:@"Cancel" forState:UIControlStateNormal];
  409. backBtn.titleLabel.backgroundColor = [UIColor clearColor];
  410. backBtn.titleLabel.font = [UIFont systemFontOfSize: 18.0];
  411. [backBtn setTitleColor:UIColorFromRGB(0x007aff) forState:UIControlStateNormal];
  412. backBtn.frame = CGRectMake(CGRectGetMaxX(self.view.frame) - 80, CGRectGetMaxY(self.view.frame)-CGRectGetHeight(_decodedMessage.frame), 60, CGRectGetHeight(_decodedMessage.frame));
  413. [self.view addSubview:backBtn];
  414. [backBtn addTarget:self action:@selector(backButtonClick:) forControlEvents:UIControlEventTouchUpInside];
  415. self.scanButton.layer.shadowColor = [UIColor blackColor].CGColor;
  416. self.scanButton.layer.shadowOffset = CGSizeMake(0, 0);
  417. self.scanButton.layer.shadowOpacity = 0.5;
  418. self.scanButton.layer.shadowRadius = 2.0;
  419. self.scanButton.layer.borderColor = [[UIColor darkGrayColor] CGColor];
  420. self.scanButton.layer.borderWidth = 15;
  421. // Start the AVSession running
  422. [session startRunning];
  423. }
  424. - (void)backButtonClick:(UIButton *)sender {
  425. [self dismissViewControllerAnimated:YES completion:nil];
  426. }
  427. //#pragma mark - ScannerControllerDelegate
  428. //-(void)BeginScan:(bool)begin
  429. //{
  430. // self.handelOutput = begin;
  431. //}
  432. #pragma mark - AVCaptureMetadataOutputObjectsDelegate
  433. - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
  434. {
  435. if(!self.handelOutput)
  436. return;
  437. AVMetadataObject * cadedate = nil;
  438. CGPoint centerzone =CGPointMake(CGRectGetMidX(self.focusZone.frame), CGRectGetMidY(self.focusZone.frame));
  439. float distance = MAXFLOAT;
  440. for (AVMetadataObject *metadata in metadataObjects) {
  441. DebugLog(@"%@",metadata);
  442. // if ([metadata.type isEqualToString:AVMetadataObjectTypeQRCode])
  443. {
  444. // Transform the meta-data coordinates to screen coords
  445. AVMetadataMachineReadableCodeObject *transformed = (AVMetadataMachineReadableCodeObject *)[_previewLayer transformedMetadataObjectForMetadataObject:metadata];
  446. // Update the frame on the _boundingBox view, and show it
  447. CGRect rt = transformed.bounds;
  448. CGRectGetMidX(rt);
  449. CGPoint centermeta =CGPointMake(CGRectGetMidX(rt), CGRectGetMidY(rt));
  450. if(CGRectContainsPoint(self.focusZone.frame, centermeta))
  451. {
  452. if(cadedate == nil)
  453. cadedate = metadata;
  454. float distancemeta = (centermeta.x-centerzone.x)*(centermeta.x-centerzone.x)+(centermeta.y-centerzone.y)*(centermeta.y-centerzone.y);
  455. if(distancemeta<distance)
  456. {
  457. distance = distancemeta;
  458. cadedate = metadata;
  459. }
  460. }
  461. }
  462. }
  463. if(cadedate==nil)
  464. return;
  465. AVMetadataMachineReadableCodeObject *transformed = (AVMetadataMachineReadableCodeObject *)[_previewLayer transformedMetadataObjectForMetadataObject:cadedate];
  466. // Update the frame on the _boundingBox view, and show it
  467. // CGRect rt = transformed.bounds;
  468. _boundingBox.frame = transformed.bounds;
  469. _boundingBox.hidden = NO;
  470. // Now convert the corners array into CGPoints in the coordinate system
  471. // of the bounding box itself
  472. // NSArray * corners = transformed.corners;
  473. NSArray *translatedCorners = [self translatePoints:transformed.corners
  474. fromView:self.view
  475. toView:_boundingBox];
  476. // Set the corners array
  477. _boundingBox.corners = translatedCorners;
  478. // Update the view with the decoded text
  479. _decodedMessage.text = [transformed stringValue];
  480. // Start the timer which will hide the overlay
  481. [self startOverlayHideTimer];
  482. [self playSound];
  483. self.handelOutput = false;
  484. [self StopScan];
  485. self.scan_val = [transformed stringValue];
  486. [self dismissViewControllerAnimated:false completion:^{
  487. if(self.returnCode)
  488. self.returnCode(self.scan_val);
  489. }];
  490. }
  491. - (IBAction)ScanButtonClick:(id)sender {
  492. self.scanButton.backgroundColor = [UIColor greenColor];
  493. [self.scanButton setTitle:@"Scanning" forState:UIControlStateNormal];
  494. // self.scanButton.layer.borderWidth = 1;
  495. self.handelOutput = true;
  496. // if (self.Scannerdelegate && [self.Scannerdelegate respondsToSelector:@selector(BeginScan:)]) {
  497. // [self.Scannerdelegate BeginScan:true];
  498. // }
  499. }
  500. -(void) StopScan
  501. {
  502. self.scanButton.backgroundColor = [UIColor redColor];
  503. [self.scanButton setTitle:@"Tap" forState:UIControlStateNormal];
  504. }
  505. #pragma mark - Utility Methods
  506. - (void)startOverlayHideTimer
  507. {
  508. // Cancel it if we're already running
  509. if(_boxHideTimer) {
  510. [_boxHideTimer invalidate];
  511. }
  512. // Restart it to hide the overlay when it fires
  513. _boxHideTimer = [NSTimer scheduledTimerWithTimeInterval:0.2
  514. target:self
  515. selector:@selector(removeBoundingBox:)
  516. userInfo:nil
  517. repeats:NO];
  518. }
  519. - (void)removeBoundingBox:(id)sender
  520. {
  521. // Hide the box and remove the decoded text
  522. _boundingBox.hidden = YES;
  523. // _decodedMessage.text = @"";
  524. }
  525. - (NSArray *)translatePoints:(NSArray *)points fromView:(UIView *)fromView toView:(UIView *)toView
  526. {
  527. NSMutableArray *translatedPoints = [NSMutableArray new];
  528. // The points are provided in a dictionary with keys X and Y
  529. for (NSDictionary *point in points) {
  530. // Let's turn them into CGPoints
  531. CGPoint pointValue = CGPointMake([point[@"X"] floatValue], [point[@"Y"] floatValue]);
  532. // Now translate from one view to the other
  533. CGPoint translatedPoint = [fromView convertPoint:pointValue toView:toView];
  534. // Box them up and add to the array
  535. [translatedPoints addObject:[NSValue valueWithCGPoint:translatedPoint]];
  536. }
  537. return [translatedPoints copy];
  538. }
  539. @end