NativeScript : custom camera view - android

I am working on an iOS and Android application with a custom camera view (that's why I won't use camera module http://docs.nativescript.org/ApiReference/camera/README)
I need to have my own UI above the camera preview.
Can I do this with Nativescript ?
I could not find any module/plugin with this feature.
Is this hard to write my own module?

The Placeholder allows you to add any native widget to your application. To do that, you need to put a Placeholder somewhere in the UI hierarchy and then create and configure the native widget that you want to appear there. Finally, pass your native widget to the event arguments of the creatingView event.
NativeScript does not have a surface view and you need to use placeholder on top of camera plugin.
<Placeholder (creatingView)="creatingView($event)"></Placeholder>
public creatingView(args: any) {
var nativeView = new android.view.SurfaceView(application.android.currentContext);
args.view = nativeView;
}

Use the surfaceview in layout.xml
<SurfaceView
android:id="#+id/surfaceview"
android:layout_centerHorizontal="true"
android:layout_width="350dp"
android:layout_height="260dp" />
use following code in activity class
SurfaceView surfaceView;
CameraSource cameraSource;
final TextRecognizer textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
cameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setAutoFocusEnabled(true)
.build();
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
cameraSource.start(surfaceView.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
cameraSource.stop();
}
});
textRecognizer.setProcessor(new Detector.Processor<TextBlock>() {
#Override
public void release() {
}

I don't understand exactly your scenario, but what I have in one of my apps that has a barcode scanner (that uses a custom camera view as in your question?) which I wanted to have a laser beam line in the middle of the camera view-port, is this:
<GridLayout>
<YourCameraView />
<StackLayout id="laser"></StackLayout>
</GridLayout>
This enables you to have the laser on top of the YourCameraView element and you can position the laser element using vertical-align and horizontal-align CSS properties.
If you want more freedom, substitute the GridLayout with AbsoluteLayout, so then you can position the overlay elements (i.e. the laser element) using top and left CSS properties.

Related

Video player rotation in xamarin (Android)

I use MediaElement from xamarin community toolkit (https://learn.microsoft.com/en-us/xamarin/community-toolkit/) and I need to rotate it. I'm trying to do this just changing the rotation property:
<!--left:-->
<xct:MediaElement x:Name="vidLeft" Grid.Column="0" Grid.Row="1" IsLooping="True" Scale="2" ShowsPlaybackControls="False" />
<!-right:-->
<xct:MediaElement x:Name="vidRight" Grid.Column="2" Grid.Row="1" IsLooping="True" Scale="2" ShowsPlaybackControls="False" Rotation="90"/>
but it is not working correctly: https://i.stack.imgur.com/pcDGA.jpg
So, any ideas how to do this?
By the way, I can use any other video player with video rotating feature.
Thanks for ur help!
When you rotate the media file with Toolkit, there is something wrong with the Rotation property. And i do not find the official document for it.
For workaround, you could try to rotate the screen to rotate the media file.
You could rotate the screen with dependency service.
Create a interface:
public interface IOrientationService
{
void Landscape();
void Portrait();
}
Android:
public class OrientationService : IOrientationService
{
public void Landscape()
{
((Activity)Forms.Context).RequestedOrientation = ScreenOrientation.Landscape;
}
public void Portrait()
{
((Activity)Forms.Context).RequestedOrientation = ScreenOrientation.Portrait;
}
}
iOS:
public class OrientationService : IOrientationService
{
public void Landscape()
{
AppDelegate appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
appDelegate.allowRotation = true;
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeLeft), new NSString("orientation"));
}
public void Portrait()
{
AppDelegate appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
appDelegate.allowRotation = true;
UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Portrait), new NSString("orientation"));
}
}
For the usage of dependency service, you could refer to the MS docs.
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/introduction
You could post the issue about the rotation of MediaElement in GitHub. https://github.com/xamarin/XamarinCommunityToolkit/issues

How to restart camera preview on Xamarin forms when using a custom renderer view for a camera preview

I am trying to resume my Camera preview with android after putting the app to sleep or changing between apps. Or even starting a different app which uses the camera feature but the Camera crashed with getParameters() being null.
Is there a way to retrieve the control other the camera preview when resuming using the Xamarin forms application.
I have tried to use Camera.Restart() and didn't work.
public void SurfaceCreated(ISurfaceHolder holder)
{
try
{
if (Preview != null)
{
Preview.StopPreview();
Preview.Reconnect();
Preview.SetPreviewDisplay(holder);
Preview.EnableShutterSound(true);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
public void SurfaceDestroyed(ISurfaceHolder holder)
{
Preview.StopPreview();
Preview.Release();
}
public void SurfaceChanged(ISurfaceHolder holder, Android.Graphics.Format format, int width, int height)
{
Camera.Parameters parameters = Preview.GetParameters();
parameters.FocusMode = Camera.Parameters.FocusModeContinuousPicture;
IList<Camera.Size> previewSizes = parameters.SupportedPreviewSizes;
// You need to choose the most appropriate previewSize for your app
Camera.Size previewSize = previewSizes[0];
parameters.SetPreviewSize(previewSize.Width, previewSize.Height);
Preview.SetParameters(parameters);
Preview.StartPreview();
}
I was able to get it to work by reading more thoroughly about the behaviour of the Android camera(Camera1) hardware.
If you are working on Xamarin and trying to create camera view within the app the best way to do it is making a custom renderer and create a camera view in each platform. Like shown here:
https://learn.microsoft.com/en-ca/xamarin/xamarin-forms/app-fundamentals/custom-renderer/view
but this example only shows how to create the camera preview, there is no camera hardware lifecycle or taking a pictures included.
To solve the issue for the question above I had simply to do Camera.Open(0) to gain control over the camera again within the lifecycle of Xamarin forms pages.
Here is what I did(in CameraPreview class in Xamarin Forms):
Created Camera open event handler:
public event EventHandler CloseCameraRequest;
Created a method to invoke the event:
public void OpenCamera()
{
OpenCameraRequest?.Invoke(this, EventArgs.Empty);
}
Registered the handler in the android camera native class:
protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
base.OnElementChanged(e);
if (Control == null)
{
_nativeCameraPreview = new NativeCameraPreview(Context);
_nativeCameraPreview.PhotoCaptured += OnPhotoCaptured;
SetNativeControl(_nativeCameraPreview);
}
Control.Preview = Camera.Open(0);
if (e.OldElement != null)
{
e.NewElement.OpenCameraRequest -= OnOpenCameraRequest;
}
if (e.NewElement != null)
{
e.NewElement.OpenCameraRequest += OnOpenCameraRequest;
}
}
private void OnOpenCameraRequest(object sender, EventArgs e)
{
Control.Preview = Camera.Open(0);
}
Invoked the request all the way from Xamarin forms page OnAppearing method:
protected override void OnAppearing()
{
base.OnAppearing();
CameraPreview.OpenCamera();
}
This fixed the issue of resuming camera preview after opening other application which uses the camera or putting the app to sleep where camera preview will timeout.

Use two DjiCodecManager at the same time

My drone matrice 210.
DJI Android SDK 4.7.1
Device CrystalSky CS785, Android 5.1.1
I shuld display video stream from two camers at the same time, like a DJI Pilot.
My solutions:
I create two diferance DjiCodecManager, and use it in diferent VideoFeeder callbaks.
DJICodecManager primaryDJICodecManager = new DJICodecManager(Activity,
pramirySurfaceTexture,
pramirySurfaceTextureTextureWidth,
pramirySurfaceTextureTextureHeight);
DJICodecManager secondaryDJICodecManager = new DJICodecManager(Activity,
secondarySurfaceTexture,
secondarySurfaceTextureTextureWidth,
secondarySurfaceTextureTextureHeight);
pramirySurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
#Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
surfaceTexture.updateTexImage();
}
});
secondarySurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
#Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
surfaceTexture.updateTexImage();
}
});
VideoFeeder.VideoFeed videoFeed = VideoFeeder.getInstance().getPrimaryVideoFeed();
VideoFeeder.VideoFeed secondaryVideoFeed = VideoFeeder.getInstance().getSecondaryVideoFeed();
secondaryVideoFeed.setCallback(new VideoFeeder.VideoDataCallback() {
#Override
public void onReceive(byte[] videoBuffer, int size) {
if (DjiManagers.mSecondaryCodecManager != null) {
secondaryDJICodecManager.sendDataToDecoder(videoBuffer, size);
}
}
});
videoFeed.setCallback(new VideoFeeder.VideoDataCallback() {
#Override
public void onReceive(byte[] videoBuffer, int size) {
if (DjiManagers.mCodecManager != null) {
primaryDJICodecManager.sendDataToDecoder(videoBuffer, size);
}
}
});
But the pramirySurfaceTexture callback does not work. And on the second texture, an image from different cameras (color and grayscale (I use a thermal imaging camera)) appears alternately, but most often the texture is green.
Is it possible to create and use two DJICodecManager?
And if not, how can I show the video stream simultaneously?
DJI support answered me.
To use two DJICodecManafers. You must use the other constructor:
primaryDJICodecManager = new DJICodecManager(Activity,
djiSdkWrapper.getSurfaceTexture(),
djiSdkWrapper.getSurfaceTextureWidth(),
djiSdkWrapper.getSurfaceTextureHeight(),
videoStreamSource);
where videoStreamSource it's one of this:
UsbAccessoryService.VideoStreamSource.Camera
UsbAccessoryService.VideoStreamSource.Fpv
UsbAccessoryService.VideoStreamSource.SecondaryCamera
And when you send data to decoding you must use onother sendDataToDecode methond:
primaryDJICodecManager.sendDataToDecoder(array, size, index);
where intdex it's one of this:
UsbAccessoryService.VideoStreamSource.Camera.getIndex()
UsbAccessoryService.VideoStreamSource.Fpv.getIndex()
UsbAccessoryService.VideoStreamSource.SecondaryCamera.getIndex()
In accordance with what you specified when creating DJICodecManager.

QR code reader to extract data

i have a sales summary print out and has a QR Code ,
i want to develop an app (IOS and android) that reads the QR code , extract all information,do some calculations,and display in specific form , i tried zxing library but it did not extract all information from the receipt.any tip?
You can use google vision API to achieve this. I personally used this and found it great. The below code snippets should help you.
Put this below line in the gradle.
compile 'com.google.android.gms:play-services:9.4.0'
Use BarcodeDetector and CameraSource classes to capture the QR code on real time and decode it.
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> barcodes = detections.getDetectedItems();
if (barcodes.size() != 0) {
barcodeInfo.post(new Runnable() { // Use the post method of the TextView
public void run() {
barcodeInfo.setText( // Update the TextView
barcodes.valueAt(0).displayValue
);
}
});
}
}
});
Use a SparseArray to fetch the detections and the displayValue of the elements of this sparse array returns the deocded string.
After extracting the string one can do anything, be it displaying the string or make some calculation out of it etc.
This library is the most popular and easiest of reading QR codes in your Android application.
You should also have a look at the Wiki section of this library for learning about how to integrate this library into your Android Application and how to use this library.
This is how you can use this library.
1. Add this library to your project by adding following line into your dependencies inside build.gradle(Module: app) file
compile 'com.github.nisrulz:qreader:2.0.0'
2. Then, after syncing project files, add the SurfaceView element provided by this library into your XML layout file.
<SurfaceView
android:id="#+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
3. Declare the SurfaceView & QREader inside your Activity's Java file & then initialize it inside onCreate() method.
class MainActivity extends AppCompatActivity{
private SurfaceView mySurfaceView;
private QREader qrEader;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Setup SurfaceView
// -----------------
mySurfaceView = (SurfaceView) findViewById(R.id.camera_view);
// Init QREader
// ------------
qrEader = new QREader.Builder(this, mySurfaceView, new QRDataListener() {
#Override
public void onDetected(final String data) {
Log.d("QREader", "Value : " + data);
text.post(new Runnable() {
#Override
public void run() {
text.setText(data);
}
});
}
}).facing(QREader.BACK_CAM)
.enableAutofocus(true)
.height(mySurfaceView.getHeight())
.width(mySurfaceView.getWidth())
.build();
}
4. Initialize it inside onResume()
#Override
protected void onResume() {
super.onResume();
// Init and Start with SurfaceView
// -------------------------------
qrEader.initAndStart(mySurfaceView);
}
There are many more possibilities you can do with this library, so I recommend you to visit the GitHub repository and check it out. It's worth a shot!

Android How to turn a XML layout into a PDF?

I have a form that when currently filled out is sent to a dedicated email address on submission. I would like to have the opportunity to offer other options. Like saving it as a PDF file. The form is completed in a main.xml layout. Is it possible to turn xml layouts into PDF's? If so could someone point me in the direction of a good example.
Many Thanks
You can take a look on this link:
https://github.com/HendrixString/Android-PdfMyXml
Instructions
create XML layouts
First create XML layouts. give it dimensions in pixels (and for all it's sub views) and proportions according landscape or portrait according to ratio 1:1.41.
page1.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="2115px"
android:layout_height="1500px"
android:background="#color/white">
<TextView android:id="#+id/tv_hello"
android:textColor="#color/black"
android:textSize="27px"
android:textStyle="bold"
android:padding="6px"/>
</RelativeLayout>
you can create as many as pages/templates as you need.
Implement a View renderer
implement your View renderer by extending AbstractViewRenderer or by anonymously instantiating it and injecting the layout id. the initView(View view) will supply you an inflated View automatically. There are other options but I wont cover it now.
AbstractViewRenderer page = new AbstractViewRenderer(context, R.layout.page1) {
private String _text;
public void setText(String text) {
_text = text;
}
#Override
protected void initView(View view) {
TextView tv_hello = (TextView)view.findViewById(R.id.tv_hello);
tv_hello.setText(_text);
}
};
// you can reuse the bitmap if you want
page.setReuseBitmap(true);
Build the PDF document
Use PdfDocument or PdfDocument.Builder to add pages and render and run it all at background with progress bar.
PdfDocument doc = new PdfDocument(ctx);
// add as many pages as you have
doc.addPage(page);
doc.setRenderWidth(2115);
doc.setRenderHeight(1500);
doc.setOrientation(PdfDocument.A4_MODE.LANDSCAPE);
doc.setProgressTitle(R.string.gen_please_wait);
doc.setProgressMessage(R.string.gen_pdf_file);
doc.setFileName("test");
doc.setInflateOnMainThread(false);
doc.setListener(new PdfDocument.Callback() {
#Override
public void onComplete(File file) {
Log.i(PdfDocument.TAG_PDF_MY_XML, "Complete");
}
#Override
public void onError(Exception e) {
Log.i(PdfDocument.TAG_PDF_MY_XML, "Error");
}
});
doc.createPdf(ctx);
or use PdfDocument.Builder
new PdfDocument.Builder(ctx).addPage(page).filename("test").orientation(PdfDocument.A4_MODE.LANDSCAPE)
.progressMessage(R.string.gen_pdf_file).progressTitle(R.string.gen_please_wait).renderWidth(2115).renderHeight(1500)
.listener(new PdfDocument.Callback() {
#Override
public void onComplete(File file) {
Log.i(PdfDocument.TAG_PDF_MY_XML, "Complete");
}
#Override
public void onError(Exception e) {
Log.i(PdfDocument.TAG_PDF_MY_XML, "Error");
}
}).create().createPdf(this);
You can use this library to make it easy to do within a few lines of code -
PdfGenerator.getBuilder()
.setContext(context)
.fromLayoutXMLSource()
.fromLayoutXML(R.layout.layout_print,R.layout.layout_print)
.s̶e̶t̶D̶e̶f̶a̶u̶l̶t̶P̶a̶g̶e̶S̶i̶z̶e̶(̶P̶d̶f̶G̶e̶n̶e̶r̶a̶t̶o̶r̶.P̶a̶g̶e̶S̶i̶z̶e̶.A̶4̶)̶ //No Longer Work
.setFileName("Test-PDF")
.build();
Additionally you can also pass a callback (PdfGeneratorListener()) in .build() to notify about if the pdf generation is done or failed for an exception

Categories

Resources