ZXing.Mobile - How to change the size of the camera scanner? - xamarin

UPDATE:
I've tried implementing this in an App.cs method called OpenCameraScanner (you would call this on click of a button on the page from which you want to scan):
App.cs
------------------------------------------------
public static ZXingScannerPage ScanPage;
public static ZXing.Result ScanResult;
public static async void OpenCameraScanner()
{
ScanPage = new ZXingScannerPage(customOverlay: customOverlay);
ScanPage.OnScanResult += (result) =>
{
ScanPage.IsScanning = false;
ScanResult = result;
Device.BeginInvokeOnMainThread(() =>
{
App.CurrentApp.CurrentPage.Navigation.PopModalAsync();
App.CurrentApp.CurrentPage.DisplayAlert("Scanned Barcode", result.Text, "OK");
});
};
var scanPage = new NavigationPage(ScanPage);
await App.CurrentApp.CurrentPage.Navigation.PushModalAsync(ScanPage);
}
However, when this method is called, the screen that opens is blank white, and you can't see the camera view behind it. Not sure why?
I'm using ZXing.Mobile in a Xamarin.Forms project (for iOS right now) for camera scanning functionality on an iPad.
Currently, I have it working great with the following 2 lines:
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
However, when the camera is open to scan, it takes up the entire iPad screen, which is really big.
Question: Is there a way to adjust the size of the camera overlay? (so that it's not full screen)
I see that the scanner.Scan() method takes an optional options parameter of type ZXing.Mobile.MobileBarcodeScanningOptions - I tried playing around with that, but the only possible relevant option there is a CameraResolutionSelector - but I'm having a really hard time finding any documentation on that.

There is a ZXing sample app that shows how to embed the ZXingScannerView and ZXingDefaultOverlay into a Xamarin.Form's Grid:
https://github.com/Redth/ZXing.Net.Mobile/blob/master/Samples/Forms/Core/CustomScanPage.cs
public CustomScanPage () : base ()
{
zxing = new ZXingScannerView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
AutomationId = "zxingScannerView",
};
zxing.OnScanResult += (result) =>
Device.BeginInvokeOnMainThread (async () => {
// Stop analysis until we navigate away so we don't keep reading barcodes
zxing.IsAnalyzing = false;
// Show an alert
await DisplayAlert ("Scanned Barcode", result.Text, "OK");
// Navigate away
await Navigation.PopAsync ();
});
overlay = new ZXingDefaultOverlay
{
TopText = "Hold your phone up to the barcode",
BottomText = "Scanning will happen automatically",
ShowFlashButton = zxing.HasTorch,
AutomationId = "zxingDefaultOverlay",
};
overlay.FlashButtonClicked += (sender, e) => {
zxing.IsTorchOn = !zxing.IsTorchOn;
};
var grid = new Grid
{
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
grid.Children.Add(zxing);
grid.Children.Add(overlay);
// The root page of your application
Content = grid;
}

Related

Xamarin and UWP Secondary Window Sizing

I'm using the following code to launch a secondary window.
static async Task OpenSecondaryWindow(ContentPage contentPage) {
var coreApplicationView = CoreApplication.CreateNewView();
int viewId = 0;
await coreApplicationView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {
var frame = new Windows.UI.Xaml.Controls.Frame();
frame.Navigate(contentPage);
Window.Current.Content = frame;
Window.Current.Activate();
viewId = ApplicationView.GetForCurrentView().Id;
App.StyleViews();
});
bool viewShown = await ApplicationViewSwitcher.TryShowAsStandaloneAsync(viewId);
}
ContentPage is of the same class that's instantiated and set to MainPage in my Xamarin.Forms.Application.
The problem I'm having is that when sizing the secondary window, the frame sizes, but not the content. What do I need to do to get the content to size as well?
This does the trick.
frame.SizeChanged += delegate (object sender, SizeChangedEventArgs e) {
contentPage.Layout(new Rectangle(0, 0, e.NewSize.Width, e.NewSize.Height));
};

Xamarin TabbedPage Performance When Using Children.Add

Good Afternoon,
I have a question regarding the performance of the tabbed page and whether there is a more efficient way to load the tabs into the page, without any frame loss or process hang.
Regarding this issue, I have been having a few issues with TabbedPage in Xamarin.Forms. My project currently consists of a Listview with 104 components. When I click on one of the items it opens up a tabbed page consisting of 3 tabed pages. I start the tabbed page using the following code
int Clicked = 0;
public async Task CheckClick(Page data)
{
Clicked += 1;
if (Clicked == 1)
{
await Navigation.PushAsync(data);
List_View.SelectedItem = null;
}
}
public async void OnSelection(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
var Cell = e.SelectedItem as DataSource;
switch (Cell.ID)
{
case 0:
await CheckClick(new Function_One());
break;
}
}
The real problem comes after, whether I pre load the information ahead of time or do what ever, whenever I call Children.Add(data); the whole application hangs for 1 or 2 seconds and than allows the page to load. The code is as follows.
public class Function_One : TabbedPage
{
private async Task Test()
{
//
var data = new NewPageData("", "", "OP.png", "Persian.png", Description, Usage, Storage, Data);
var data2 = new NewMedicalPage(Medical_Info, Translation, startinfo);
var data3 = new NewNotePage("", 0);
data.Icon = "Info.png";
await Task.Delay(100);// Little await to load the page first before hang
Device.BeginInvokeOnMainThread(async () =
{
Children.Add(data);// HERE is the freeze
Children.Add(data2);// these
Children.Add(data3);// 3 (Adding of the Tabs)
});
}
public void UpdateData()
{
Task.Run(async () =
{
try
{
Description.Spans.Add(new Span
{
Text = "Data.... ",
FontSize = 18,
FontFamily = variables.fontFamily
});
Usage.Spans.Add(new Span
{
Text = "MoreData...",
FontSize = 18,
FontFamily = variables.fontFamily
});
Storage.Spans.Add(new Span
{
Text = "LastData...",
FontSize = 18,
FontFamily = variables.fontFamily
});
await Test();
}
catch { }
}).ConfigureAwait(false);
}
public Function_One()
{
UpdateData();
BarBackgroundColor = MainColor;
BarTextColor = Color.WhiteSmoke;
Title = "Page";
}
}
NOTE: (This Project Is Completely An Offline Project, No Internet Needed)
If anyone could explain to me a better method for loading the data while keeping the application flowing and smooth, that would be appreciated. The data does not have to load all at once, just as long as the page opens as soon as its clicked!

Can ZXing be stopped or dispose so i can use it again?

im using ZXing.Net.Mobile for Forms like this
var scanPage = new ZXingScannerPage();
scanPage.OnScanResult += (result) => {
// Stop scanning
scanPage.IsScanning = false;
// Pop the page and show the result
Device.BeginInvokeOnMainThread(async () => {
// await Navigation.PopAsync();
await Navigation.PushModalAsync(new Pages.DataGridPage(PladsId));
});
};
from https://components.xamarin.com/gettingstarted/zxing.net.mobile.forms
but after i have scanned once the carmera is frozen when i try again
i have tried to Dispose/stop the scanner but without success
can ZXing be stopped or dispose so i can use it again ?
im using visual studio 2015 community, xamarin.Forms 2.3.3.168, Syncfusion 14.4.0.15 and ZXing.Net.Mobile 2.1.47. running it on a sony xperia z3 with Android version 6.0.1 and using API 23
Any help is deeply appreciated
Found the solution....
Use IsScanning=true only once... In ScannerView Constructor or in OnAppearing of the Page..
_zxing = new ZXingScannerView
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
HeightRequest = 250,
WidthRequest = 250,
IsAnalyzing = true,
IsScanning = true,
};
Don't write anything in OnDisappearing...
protected override void OnDisappearing()
{
// _zxing.IsScanning = false;
base.OnDisappearing();
}
IsAnalysing to be set false once scanning complete and should be set true in OnAppearing...
_zxing.OnScanResult += (result) =>
Device.BeginInvokeOnMainThread(async () =>
{
if (!string.IsNullOrWhiteSpace(result.Text))
{
_zxing.IsAnalyzing = false;
await OnGettingResult(result.Text);
}
});
protected override void OnAppearing()
{
base.OnAppearing();
_zxing.IsAnalyzing = true;
//Not required if already set while intialization
//_zxing.IsScanning = true;
}
Why don't you use it with async? After its done scanning, it returns me back in the navigation stack. It looks like your using the generic Scanner Page so the following solution would work.
var scanner = new ZXing.Mobile.MobileBarcodeScanner();
var result = await scanner.Scan();
if (result != null)
{
variableToAssign = result.Text;
}
If like me, you wanted the scanner to not switch off after one scan, or only scan the same code once, then you want to check if you have already scanned a particular qr code.
var options = new MobileBarcodeScanningOptions();
var scans = new HashSet<string>();
options.PossibleFormats.Add(ZXing.BarcodeFormat.QR_CODE);
ZXingScannerPage scanPage = new ZXingScannerPage(options);
scanPage.Title = "Scan QR Code";
scanPage.OnScanResult += (result) =>
{
//Only scan a particular QR code once
if (!scans.Contains(result.Text))
{
scans.Add(result.Text);
//etc
}
}
there's a workaround that should be work at start of your page and start of your action you will unsubscribe
scanPage.OnScanResult -= YourAction();
after-action finished you should subscribe again for scanning
scanPage.OnScanResult += YourAction();

Xamarin.forms i want to upload image on same page

i am uploading my image by using plugins.media but the problem is it redirect to another photoimage page and upload it there.
var profiletap = new TapGestureRecognizer();
profiletap.Tapped += async (s, e) =>
{
var file = await CrossMedia.Current.PickPhotoAsync();
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");
ImageSource im = ImageSource.FromStream(() =>
{
var stream = file.GetStream();
file.Dispose();
return stream;
});
await Navigation.PushModalAsync(new PhotoPage(im));
};
profile.GestureRecognizers.Add(profiletap);
ant here is photopage content
public class PhotoPage : demopage
{
public PhotoPage(ImageSource img)
{
Content = new Image
{
VerticalOptions =LayoutOptions.Start,
HorizontalOptions = LayoutOptions.Start,
Source =img
};
}
}
Instead of doing
await Navigation.PushModalAsync(new PhotoPage(im));
you can do something like
var img = new Image
{
Source =im
};
then add the new img control to the same container as where the "profile" control has already been added (probably some Stacklayout or Grid or some other layout control like that)
Be aware that you are struggling with the most basic concept of building out your app UI, which is a strong indicator you should read some getting started tutorials for xamarin.forms and really understand how the UI is built.

Why does live camera capture control with Xamarin Forms on iOS freeze?

I downloaded the source for Xamarin Moments from GitHub and now I'm trying to convert the CameraPage renderer from Page to a ContentView
Then I refactored the code to make it a ContentView renderer. Most of the actual setup of the live preview and image capture comes from the Moments app with some refactoring where needed/preferred.
The live preview shows up but when I press the button to take the picture the app freezes without an exception, not even in Xcode's console view.
//this is how it's called:
btnTakePicture.Clicked += (s,e)=> { GetCameraImage().Wait(); };
// this method freezes
public async Task<byte[]> GetCameraImage()
{
byte[] imageBuffer = null;
if (captureDeviceInput != null)
{
var videoConnection = stillImageOutput.ConnectionFromMediaType(AVMediaType.Video);
Console.WriteLine("[HASFIQWRPPOA] This message shows up");
// this is where the app freezes, even though the live preview still moves.
var sampleBuffer = await stillImageOutput.CaptureStillImageTaskAsync(videoConnection);
Console.WriteLine("[CLKJFADSFQXW] THIS DOESN'T SHOW UP");
// var jpegImageAsBytes = AVCaptureStillImageOutput.JpegStillToNSData (sampleBuffer).ToArray ();
var jpegImageAsNsData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
Console.WriteLine("[ROIAJDGNQWTG]");
// var image = new UIImage (jpegImageAsNsData);
// var image2 = new UIImage (image.CGImage, image.CurrentScale, UIImageOrientation.UpMirrored);
// var data = image2.AsJPEG ().ToArray ();
imageBuffer = jpegImageAsNsData.ToArray();
Console.WriteLine("[FIOUJGAIDGUQ] Image buffer: "+imageBuffer.Length);
}
if (imageBuffer != null && imageBuffer.Length > 100)
{
using (var ms = new MemoryStream(imageBuffer))
{
var uiimg = UIImage.LoadFromData(NSData.FromStream(ms));
this.Add(new UIImageView(uiimg));
}
}
return imageBuffer;
}
Here is how I set the live preview
// This method runs fine and the camera preview is started as expected
public void SetupLiveCameraStream()
{
try
{
// add a UIView to the renderer
liveCameraStream = new UIView()
{
Frame = new CGRect(0f, 0f, Element.Width, Element.Height),
};
this.Add(liveCameraStream);
// find a camera
var captureDevice = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Video);
if (captureDevice != null)
{
Console.WriteLine("[ZKSDJGWEHSY] Capture device found"); // not the case on simulator
captureSession = new AVCaptureSession();
videoPreviewLayer = new AVCaptureVideoPreviewLayer(captureSession)
{
Frame = liveCameraStream.Bounds
};
liveCameraStream.Layer.AddSublayer(videoPreviewLayer);
ConfigureCameraForDevice(captureDevice);
captureDeviceInput = AVCaptureDeviceInput.FromDevice(captureDevice);
var dictionary = new NSMutableDictionary();
dictionary[AVVideo.CodecKey] = new NSNumber((int)AVVideoCodec.JPEG);
stillImageOutput = new AVCaptureStillImageOutput()
{
OutputSettings = new NSDictionary()
};
captureSession.AddInput(captureDeviceInput);
captureSession.AddOutput(stillImageOutput);
captureSession.StartRunning();
Console.WriteLine("[OIGAJGUWRJHWY] Camera session started");
}
else
{
Console.WriteLine("[OASDFUJGOR] Could not find a camera device");
}
}
catch (Exception x)
{
Console.WriteLine("[QWKRIFQEAHJF] ERROR:" + x);
}
}
I had this issue, and it turned out I was deadlocking because of a combination of using async/await with Task.Result. At a guess you could be experiencing something similar with your usage of Task.Wait().
The two sections of code:
btnTakePicture.Clicked += await (s,e) => { GetCameraImage().Wait(); };
And:
var sampleBuffer = await stillImageOutput.CaptureStillImageTaskAsync(videoConnection);

Resources