Created
July 2, 2012 17:47
-
-
Save Alxandr/3034545 to your computer and use it in GitHub Desktop.
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 MonoTouch.UIKit; | |
using com.google.zxing; | |
using MonoTouch.AVFoundation; | |
using MonoTouch.CoreFoundation; | |
using MonoTouch.CoreVideo; | |
using System.Collections; | |
using MonoTouch.CoreMedia; | |
using System.Runtime.InteropServices; | |
using com.google.zxing.common; | |
namespace FdvWeb | |
{ | |
// based on https://github.com/xamarin/monotouch-samples/blob/master/AVCaptureFrames/Main.cs | |
public class QRScanViewController : 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 (); | |
//buttonCancel.ButtonType = 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 (); | |
//buttonFlash.ButtonType = 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; | |
QRScanViewController parent; | |
MultiFormatReader reader; | |
byte[] bytes; | |
public ZxingScanner (QRScanViewController 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,*/ BarcodeFormat.QR_CODE | |
} } | |
} | |
}; | |
} | |
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