Skip to content

Commit

Permalink
Merge pull request #68 from spoonconsulting/ultra-wide-angle-camera
Browse files Browse the repository at this point in the history
Ultra wide angle camera option
  • Loading branch information
parveshneedhoo authored May 13, 2024
2 parents 2962777 + 0dda35e commit f65d1b1
Show file tree
Hide file tree
Showing 12 changed files with 362 additions and 44 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## [2.0.18](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/compare/v2.0.17...v2.0.18) (2024-05-12)

* **iOS:** Added a method "switchCameraTo" to help switch between ultra-wide camera and default camera. ([#68](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/pull/68))
* **Android:** Added a method "switchCameraTo" to help switch between ultra-wide camera and default camera. ([#68](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/pull/68))
* **iOS:** Added a method "deviceHasUltraWideCamera" to check if device has ultra-wide camera. ([#68](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/pull/68))
* **Android:** Added a method "deviceHasUltraWideCamera" to check if device has ultra-wide camera. ([#68](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/pull/68))

## [2.0.17](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/compare/v2.0.16...v2.0.17) (2023-07-04)

* **iOS:** Use interfaceOrientation for ios 13+. ([#67](https://github.com/spoonconsulting/cordova-plugin-simple-camera-preview/pull/67))
Expand Down
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,46 @@ SimpleCameraPreview.setSize(size, () => {
console.log("Camera frame size set");
});
```

### deviceHasUltraWideCamera(successCallback, errorCallback)

Check if device has ultra-wide camera
<br>

```javascript

SimpleCameraPreview.deviceHasUltraWideCamera(size, (value: boolean) => {
console.log("Device has ultra-wide camera?: ", value);
});
```

### switchCameraTo(option, successCallback, errorCallback)

Switch camera between ultra-wide or default

The variable captureDevice can take two values:
```javascript
"ultra-wide-angle"

or

"default"
```
<br>

```javascript

const params = {
captureDevice: "ultra-wide-angle",
}

SimpleCameraPreview.switchCameraTo(
params,
(value: unknown) => {
return (typeof value === "boolean" ? value : false);
},
(e: unknown) => {
console.log("cannot switch camera: ", e);
}
);
```
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@spoonconsulting/cordova-plugin-simple-camera-preview",
"version": "2.0.17",
"version": "2.0.18",
"description": "Cordova plugin that allows camera interaction from HTML code for showing camera preview below or on top of the HTML.",
"keywords": [
"cordova",
Expand Down
2 changes: 1 addition & 1 deletion plugin.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>

<plugin id="@spoonconsulting/cordova-plugin-simple-camera-preview" version="2.0.17" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<plugin id="@spoonconsulting/cordova-plugin-simple-camera-preview" version="2.0.18" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">

<name>cordova-plugin-simple-camera-preview</name>
<description>Cordova plugin that allows camera interaction from HTML code. Show camera preview popup on top of the HTML.</description>
Expand Down
178 changes: 147 additions & 31 deletions src/android/CameraPreviewFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.hardware.camera2.CameraCharacteristics;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.Size;
import android.view.Display;
Expand All @@ -18,7 +21,9 @@

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.camera2.internal.Camera2CameraInfoImpl;
import androidx.camera.core.Camera;
import androidx.camera.core.CameraInfo;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
Expand All @@ -36,6 +41,9 @@

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;

Expand All @@ -55,6 +63,14 @@ interface HasFlashCallback {
void onResult(boolean result);
}

interface CameraSwitchedCallback {
void onSwitch(boolean result);
}

interface HasUltraWideCameraCallback {
void onResult(boolean result);
}

public class CameraPreviewFragment extends Fragment {

private PreviewView viewFinder;
Expand All @@ -69,6 +85,7 @@ public class CameraPreviewFragment extends Fragment {

private static float ratio = (4 / (float) 3);
private static final String TAG = "SimpleCameraPreview";
private String captureDevice;

public CameraPreviewFragment() {

Expand All @@ -82,6 +99,11 @@ public CameraPreviewFragment(int cameraDirection, CameraStartedCallback cameraSt
} catch (JSONException e) {
e.printStackTrace();
}
try {
this.captureDevice = options.getString("captureDevice");
} catch (JSONException e) {
e.printStackTrace();
}
startCameraCallback = cameraStartedCallback;
}

Expand Down Expand Up @@ -114,47 +136,51 @@ public void startCamera() {
startCameraCallback.onCameraStarted(new Exception("Unable to start camera"));
return;
}
setUpCamera(captureDevice,cameraProvider);

CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(direction)
.build();
preview.setSurfaceProvider(viewFinder.getSurfaceProvider());

Size targetResolution = null;
if (targetSize > 0) {
targetResolution = CameraPreviewFragment.calculateResolution(getContext(), targetSize);
if (startCameraCallback != null) {
startCameraCallback.onCameraStarted(null);
}
}

preview = new Preview.Builder().build();
imageCapture = new ImageCapture.Builder()
.setTargetResolution(targetResolution)
.build();
@SuppressLint("RestrictedApi")
public void deviceHasUltraWideCamera(HasUltraWideCameraCallback hasUltraWideCameraCallback) {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity());
ProcessCameraProvider cameraProvider = null;

cameraProvider.unbindAll();
try {
camera = cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageCapture
);
} catch (IllegalArgumentException e) {
// Error with result in capturing image with default resolution
cameraProvider = cameraProviderFuture.get();
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Error occurred while trying to obtain the camera provider: " + e.getMessage());
e.printStackTrace();
imageCapture = new ImageCapture.Builder()
.build();
camera = cameraProvider.bindToLifecycle(
this,
cameraSelector,
preview,
imageCapture
);
hasUltraWideCameraCallback.onResult(false);
return;
}
List<CameraInfo> cameraInfos = cameraProvider.getAvailableCameraInfos();

boolean defaultCamera = false;
boolean ultraWideCamera = false;
List<Camera2CameraInfoImpl> backCameras = new ArrayList<>();
for (CameraInfo cameraInfo : cameraInfos) {
if (cameraInfo instanceof Camera2CameraInfoImpl) {
Camera2CameraInfoImpl camera2CameraInfo = (Camera2CameraInfoImpl) cameraInfo;
if (camera2CameraInfo.getLensFacing() == CameraSelector.LENS_FACING_BACK) {
backCameras.add(camera2CameraInfo);
}
}
}

preview.setSurfaceProvider(viewFinder.getSurfaceProvider());

if (startCameraCallback != null) {
startCameraCallback.onCameraStarted(null);
for (Camera2CameraInfoImpl backCamera : backCameras) {
if (backCamera.getCameraCharacteristicsCompat().get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0] >= 2.4) {
defaultCamera = true;
} else if( backCamera.getCameraCharacteristicsCompat().get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0] < 2.4) {
ultraWideCamera = true;
}
}

hasUltraWideCameraCallback.onResult(defaultCamera == true && ultraWideCamera == true);
}

public static Size calculateResolution(Context context, int targetSize) {
Expand Down Expand Up @@ -309,4 +335,94 @@ public void setLocation(Location loc) {
this.location = loc;
}
}


public void switchCameraTo(String device, CameraSwitchedCallback cameraSwitchedCallback) {
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(() -> {
ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity());
ProcessCameraProvider cameraProvider = null;
try {
cameraProvider = cameraProviderFuture.get();
} catch (ExecutionException | InterruptedException e) {
Log.e(TAG, "Error occurred while trying to obtain the camera provider: " + e.getMessage());
e.printStackTrace();
cameraSwitchedCallback.onSwitch(false);
return;
}

setUpCamera(device,cameraProvider);

preview.setSurfaceProvider(viewFinder.getSurfaceProvider());
cameraSwitchedCallback.onSwitch(true);
});
}

@SuppressLint("RestrictedApi")
public void setUpCamera(String captureDevice, ProcessCameraProvider cameraProvider) {
CameraSelector cameraSelector;
if (captureDevice.equals("ultra-wide-angle")) {
cameraSelector = new CameraSelector.Builder()
.addCameraFilter(cameraInfos -> {
List<Camera2CameraInfoImpl> backCameras = new ArrayList<>();
for (CameraInfo cameraInfo : cameraInfos) {
if (cameraInfo instanceof Camera2CameraInfoImpl) {
Camera2CameraInfoImpl camera2CameraInfo = (Camera2CameraInfoImpl) cameraInfo;
if (camera2CameraInfo.getLensFacing() == CameraSelector.LENS_FACING_BACK) {
backCameras.add(camera2CameraInfo);
}
}
}

Camera2CameraInfoImpl selectedCamera = Collections.min(backCameras, (o1, o2) -> {
Float focalLength1 = o1.getCameraCharacteristicsCompat().get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0];
Float focalLength2 = o2.getCameraCharacteristicsCompat().get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)[0];
return Float.compare(focalLength1, focalLength2);
});

if (selectedCamera != null) {
return Collections.singletonList(selectedCamera);
} else {
return cameraInfos;
}
})
.build();
} else {
cameraSelector = new CameraSelector.Builder()
.requireLensFacing(direction)
.build();
}

Size targetResolution = null;
if (targetSize > 0) {
targetResolution = CameraPreviewFragment.calculateResolution(getContext(), targetSize);
}

preview = new Preview.Builder().build();
imageCapture = new ImageCapture.Builder()
.setTargetResolution(targetResolution)
.build();

cameraProvider.unbindAll();
try {
camera = cameraProvider.bindToLifecycle(
getActivity(),
cameraSelector,
preview,
imageCapture
);
} catch (IllegalArgumentException e) {
// Error with result in capturing image with default resolution
e.printStackTrace();
imageCapture = new ImageCapture.Builder()
.build();
camera = cameraProvider.bindToLifecycle(
getActivity(),
cameraSelector,
preview,
imageCapture
);
}

}
}
Loading

0 comments on commit f65d1b1

Please sign in to comment.