Created
July 2, 2012 17:01
-
-
Save Redth/3034282 to your computer and use it in GitHub Desktop.
ZXING MonoTouch ZxingViewController
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using System.Runtime.InteropServices; | |
| using MonoTouch.UIKit; | |
| using MonoTouch.CoreFoundation; | |
| using MonoTouch.AVFoundation; | |
| using MonoTouch.CoreVideo; | |
| using MonoTouch.CoreMedia; | |
| using com.google.zxing; | |
| using com.google.zxing.common; | |
| namespace Shield.IPhone | |
| { | |
| // based on https://github.com/xamarin/monotouch-samples/blob/master/AVCaptureFrames/Main.cs | |
| public class ZxingViewController : UIViewController | |
| { | |
| public event Action<Result> Scan; | |
| AVCaptureSession session; | |
| AVCaptureVideoPreviewLayer previewLayer; | |
| AVCaptureDevice captureDevice; | |
| UIImageView overlayView; | |
| UIButton buttonCancel; | |
| UIButton buttonFlash; | |
| DispatchQueue queue; | |
| ZxingScanner scanner; | |
| public override void LoadView () | |
| { | |
| base.LoadView (); | |
| if (!SetupCaptureSession ()) | |
| throw new NotSupportedException ("Unable to setup camera for scan"); | |
| previewLayer.Frame = UIScreen.MainScreen.Bounds; | |
| View.Layer.AddSublayer (previewLayer); | |
| } | |
| public override void ViewDidLoad () | |
| { | |
| overlayView = new UIImageView(UIScreen.MainScreen.Bounds); | |
| //Use your own overlay image here | |
| //overlayView.Image = UIImage.FromFile("Images/BarCodeOverlay.png"); | |
| this.View.AddSubview(overlayView); | |
| buttonCancel = new UIButton(UIButtonType.RoundedRect); | |
| buttonCancel.Frame = new System.Drawing.RectangleF(20, 20, 130, 30); | |
| buttonCancel.SetTitle("Cancel", UIControlState.Normal); | |
| buttonCancel.Alpha = 0.3f; | |
| buttonCancel.SetTitleColor(UIColor.White, UIControlState.Normal); | |
| buttonCancel.TintColor = UIColor.Gray; | |
| buttonCancel.TouchUpInside += (sender, e) => { | |
| this.Scan(null); | |
| }; | |
| this.View.AddSubview(buttonCancel); | |
| buttonFlash = new UIButton(UIButtonType.RoundedRect); | |
| buttonFlash.Frame = new System.Drawing.RectangleF(170, 20, 130, 30); | |
| buttonFlash.SetTitle("Flash On", UIControlState.Normal); | |
| buttonFlash.Alpha = 0.3f; | |
| buttonFlash.TintColor = UIColor.Gray; | |
| buttonFlash.SetTitleColor(UIColor.White, UIControlState.Normal); | |
| //buttonFlash.HorizontalAlignment = UIControlContentHorizontalAlignment.Right; | |
| buttonFlash.TouchUpInside += (sender, e) => { | |
| if (captureDevice != null) | |
| { | |
| if (captureDevice.TorchAvailable) | |
| { | |
| MonoTouch.Foundation.NSError err = null; | |
| captureDevice.LockForConfiguration(out err); | |
| if (captureDevice.TorchMode == AVCaptureTorchMode.Auto || captureDevice.TorchMode == AVCaptureTorchMode.Off) | |
| captureDevice.TorchMode = AVCaptureTorchMode.On; | |
| else | |
| captureDevice.TorchMode = AVCaptureTorchMode.Off; | |
| captureDevice.UnlockForConfiguration(); | |
| this.BeginInvokeOnMainThread(() => { | |
| if (buttonFlash.CurrentTitle == "Flash On") | |
| buttonFlash.SetTitle("Flash Off", UIControlState.Normal); | |
| else | |
| buttonFlash.SetTitle("Flash On", UIControlState.Normal); | |
| }); | |
| } | |
| } | |
| }; | |
| this.View.AddSubview(buttonFlash); | |
| } | |
| bool SetupCaptureSession () | |
| { | |
| // configure the capture session for low resolution, change this if your code | |
| // can cope with more data or volume | |
| session = new AVCaptureSession () { | |
| SessionPreset = AVCaptureSession.PresetMedium | |
| }; | |
| // create a device input and attach it to the session | |
| captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType (AVMediaType.Video); | |
| var input = AVCaptureDeviceInput.FromDevice (captureDevice); | |
| if (input == null){ | |
| // No input device | |
| return false; | |
| } | |
| session.AddInput (input); | |
| // create a VideoDataOutput and add it to the sesion | |
| var output = new AVCaptureVideoDataOutput () { | |
| VideoSettings = new AVVideoSettings (CVPixelFormatType.CV32BGRA) | |
| }; | |
| // configure the output | |
| queue = new DispatchQueue ("myQueue"); | |
| scanner = new ZxingScanner (this); | |
| output.SetSampleBufferDelegateAndQueue (scanner, queue); | |
| session.AddOutput (output); | |
| previewLayer = new AVCaptureVideoPreviewLayer (session); | |
| previewLayer.Orientation = AVCaptureVideoOrientation.Portrait; | |
| previewLayer.VideoGravity = "AVLayerVideoGravityResizeAspectFill"; | |
| session.StartRunning (); | |
| return true; | |
| } | |
| class ZxingScanner : AVCaptureVideoDataOutputSampleBufferDelegate | |
| { | |
| bool gotResult = false; | |
| ZxingViewController parent; | |
| MultiFormatReader reader; | |
| byte [] bytes; | |
| public ZxingScanner (ZxingViewController parent) | |
| { | |
| this.parent = parent; | |
| this.reader = new MultiFormatReader { | |
| Hints = new Hashtable { | |
| { DecodeHintType.POSSIBLE_FORMATS, new ArrayList { | |
| BarcodeFormat.UPC_A, BarcodeFormat.UPC_E , BarcodeFormat.CODE_128, | |
| BarcodeFormat.CODE_39, BarcodeFormat.EAN_13, BarcodeFormat.EAN_8 | |
| } } | |
| } | |
| }; | |
| } | |
| public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection) | |
| { | |
| try { | |
| if (!gotResult) | |
| { | |
| LuminanceSource luminance; | |
| connection.VideoOrientation = AVCaptureVideoOrientation.Portrait; | |
| using (var pixelBuffer = sampleBuffer.GetImageBuffer () as CVPixelBuffer) { | |
| if (bytes == null) | |
| bytes = new byte [pixelBuffer.Height * pixelBuffer.BytesPerRow]; | |
| pixelBuffer.Lock (0); | |
| Marshal.Copy (pixelBuffer.BaseAddress, bytes, 0, bytes.Length); | |
| luminance = new RGBLuminanceSource (bytes, pixelBuffer.Width, pixelBuffer.Height); | |
| pixelBuffer.Unlock (0); | |
| } | |
| var binarized = new BinaryBitmap (new HybridBinarizer (luminance)); | |
| var result = reader.decodeWithState (binarized); | |
| //parent.session.StopRunning (); | |
| gotResult = true; | |
| if (parent.Scan != null) | |
| { | |
| MonoTouch.AudioToolbox.SystemSound.FromFile ("Sounds/beep.wav").PlayAlertSound (); | |
| parent.Scan (result); | |
| } | |
| } | |
| } catch (ReaderException) { | |
| // ignore this exception; it happens every time there is a failed scan | |
| } catch (Exception e) { | |
| // TODO: this one is unexpected.. log or otherwise handle it | |
| throw; | |
| } finally { | |
| try { | |
| // lamest thing, but seems that this throws :( | |
| sampleBuffer.Dispose (); | |
| } catch { } | |
| } | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment