Skip to content

Commit 482e81f

Browse files
committedApr 1, 2015
Add ability to select camera for android
1 parent 768cbef commit 482e81f

File tree

3 files changed

+186
-132
lines changed

3 files changed

+186
-132
lines changed
 

‎README.md

+16-16
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ Have to call [initialize][initialize] with canvas object(canvas tag to preview c
6363

6464
```javascript
6565
document.addEventListener('deviceready', function () {
66-
66+
6767
// have to call initialize function with canvas object
6868
var objCanvas = document.getElementById("canvas");
6969
window.plugin.CanvasCamera.initialize(objCanvas);
@@ -133,7 +133,7 @@ window.plugin.CanvasCamera.setFlashMode(flashMode);
133133
##### flashMode
134134
Value of flashMode can be one of the followings;
135135
```javascript
136-
CanvasCamera.FlashMode =
136+
CanvasCamera.FlashMode =
137137
{
138138
OFF : 0,
139139
ON : 1,
@@ -173,7 +173,7 @@ window.plugin.CanvasCamera.setCameraPosition(CanvasCamera.CameraPosition.FRONT);
173173
### options
174174
Optional parameters to customize the settings.
175175
```javascript
176-
{ quality : 75,
176+
{ quality : 75,
177177
destinationType : CanvasCamera.DestinationType.DATA_URL,
178178
sourceType : CanvasCamera.PictureSourceType.CAMERA,
179179
allowEdit : true,
@@ -235,15 +235,15 @@ CanvasCamera.PictureSourceType = {
235235
<p class="event listening">Connecting to Device</p>
236236
<p class="event received">Device is Ready</p>
237237
</div>
238-
238+
239239
<h2> Camera Position </h2>
240240
<input type="radio" name="deviceposition" id="deviceposition_back" value="Back" onclick="onChangeDevicePosition();"/>
241241
<label for="deviceposition_back">Back</label>
242242
<br/>
243243
<input type="radio" name="deviceposition" id="deviceposition_front" value="Front" onclick="onChangeDevicePosition();"/>
244244
<label for="deviceposition_front">Front</label>
245-
246-
245+
246+
247247
<h2> Flash Mode </h2>
248248
<input type="radio" name="flashmode" id="flashmode_off" value="Off" onclick="onChangeFlashMode();"/>
249249
<label for="flashmode_off">Off</label>
@@ -254,21 +254,21 @@ CanvasCamera.PictureSourceType = {
254254
<input type="radio" name="flashmode" id="flashmode_auto" value="Auto" onclick="onChangeFlashMode();"/>
255255
<label for="flashmode_auto">Auto</label>
256256
<br/>
257-
257+
258258
<input type="button" value="Take a picture" onclick="onTakePicture();" />
259259

260260

261261
</div>
262-
262+
263263
<!— camera preview canvas —>
264264
<canvas id="camera" width="352" height="288" style="border:2px"></canvas>
265-
265+
266266
<script type="text/javascript" src="cordova.js"></script>
267267
<script type="text/javascript" src="js/index.js"></script>
268268
<script type="text/javascript">
269269
app.initialize();
270270
</script>
271-
271+
272272
<script>
273273
document.addEventListener("deviceready", function() {
274274
canvasMain = document.getElementById("camera");
@@ -285,7 +285,7 @@ CanvasCamera.PictureSourceType = {
285285
};
286286
CanvasCamera.start(opt);
287287
});
288-
288+
289289
function onChangeDevicePosition() {
290290
291291
var newDevicePosition = CanvasCamera.CameraPosition.BACK;
@@ -300,9 +300,9 @@ CanvasCamera.PictureSourceType = {
300300
//
301301
CanvasCamera.setCameraPosition(newDevicePosition);
302302
}
303-
303+
304304
function onChangeFlashMode() {
305-
305+
306306
var newFlashMode = CanvasCamera.FlashMode.OFF;
307307
if (document.getElementById("flashmode_off").checked)
308308
{
@@ -316,14 +316,14 @@ CanvasCamera.PictureSourceType = {
316316
{
317317
newFlashMode = CanvasCamera.FlashMode.AUTO;
318318
}
319-
319+
320320
CanvasCamera.setFlashMode(newFlashMode);
321321
}
322-
322+
323323
function onTakePicture() {
324324
CanvasCamera.takePicture(onTakeSuccess);
325325
}
326-
326+
327327
function onTakeSuccess(data) {
328328
//
329329
}

‎src/android/CanvasCamera.java

+123-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import android.app.Activity;
44
import android.util.Log;
55
import android.util.Size;
6+
import android.util.SparseIntArray;
67
import android.os.Handler;
78
import android.os.HandlerThread;
89
import android.content.Context;
@@ -45,6 +46,30 @@ public class CanvasCamera extends CordovaPlugin
4546
{
4647
private final static String TAG = "SimpleCamera";
4748

49+
/**
50+
* Conversion from screen rotation to JPEG orientation for back facing camera.
51+
*/
52+
private static final SparseIntArray BACK_CAMERA_ORIENTATIONS = new SparseIntArray();
53+
54+
static {
55+
BACK_CAMERA_ORIENTATIONS.append(Surface.ROTATION_0, 90);
56+
BACK_CAMERA_ORIENTATIONS.append(Surface.ROTATION_90, 0);
57+
BACK_CAMERA_ORIENTATIONS.append(Surface.ROTATION_180, 270);
58+
BACK_CAMERA_ORIENTATIONS.append(Surface.ROTATION_270, 180);
59+
}
60+
61+
/**
62+
* Conversion from screen rotation to JPEG orientation for front facing camera.
63+
*/
64+
private static final SparseIntArray FRONT_CAMERA_ORIENTATIONS = new SparseIntArray();
65+
66+
static {
67+
FRONT_CAMERA_ORIENTATIONS.append(Surface.ROTATION_0, 270);
68+
FRONT_CAMERA_ORIENTATIONS.append(Surface.ROTATION_90, 0);
69+
FRONT_CAMERA_ORIENTATIONS.append(Surface.ROTATION_180, 90);
70+
FRONT_CAMERA_ORIENTATIONS.append(Surface.ROTATION_270, 180);
71+
}
72+
4873
private Activity mActivity;
4974
private CallbackContext mCallbackContext;
5075

@@ -53,6 +78,7 @@ public class CanvasCamera extends CordovaPlugin
5378
private CameraDevice mCamera;
5479
private String mCameraId;
5580
private ImageReader mReader = null;
81+
private int mFileId = 0;
5682
private HandlerThread mBackgroundThread;
5783
private Handler mBackgroundHandler;
5884
private SimpleImageListener mListener = null;
@@ -74,6 +100,10 @@ else if ("setFlashMode".equals(action)) {
74100
setFlashMode(args, callbackContext);
75101
return true;
76102
}
103+
else if ("setCameraPosition".equals(action)) {
104+
setCameraPosition(args, callbackContext);
105+
return true;
106+
}
77107

78108
return false;
79109
}
@@ -86,7 +116,7 @@ private void startCapture(JSONArray args, CallbackContext callbackContext)
86116
Log.d(TAG, "camera manager obtained");
87117

88118
try {
89-
mCameraId = mCameraManager.getCameraIdList()[0];
119+
mCameraId = getCameraIdForOrientation(CameraCharacteristics.LENS_FACING_BACK);
90120
startBackgroundThread();
91121
mCameraManager.openCamera(mCameraId, cameraStateCallback, null);
92122

@@ -137,7 +167,42 @@ private void setFlashMode(JSONArray args, CallbackContext callbackContext)
137167
callbackContext.success();
138168
}
139169
catch (Exception e){
140-
callbackContext.error("Failed to stop capture");
170+
callbackContext.error("Failed to set flash mode");
171+
}
172+
}
173+
174+
private void setCameraPosition(JSONArray args, CallbackContext callbackContext)
175+
{
176+
try {
177+
String cameraPosition = args.getString(0);
178+
179+
Log.d(TAG, "camera is gonna be switched to " + cameraPosition);
180+
181+
int lensOrientation = CameraCharacteristics.LENS_FACING_BACK;
182+
183+
if (cameraPosition.equals("front")) {
184+
lensOrientation = CameraCharacteristics.LENS_FACING_FRONT;
185+
}
186+
187+
mCameraId = getCameraIdForOrientation(lensOrientation);
188+
189+
if (mCameraId != null) {
190+
stopBackgroundThread();
191+
mCameraSession.close();
192+
mCamera.close();
193+
194+
startBackgroundThread();
195+
mCameraManager.openCamera(mCameraId, cameraStateCallback, null);
196+
197+
Log.d(TAG, "camera switched");
198+
callbackContext.success();
199+
}
200+
else {
201+
callbackContext.error("Failed to switch camera");
202+
}
203+
}
204+
catch (Exception e){
205+
callbackContext.error("Failed to switch camera");
141206
}
142207
}
143208

@@ -157,12 +222,12 @@ public void onOpened(CameraDevice camera) {
157222
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
158223

159224
Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG);
160-
Size previewSize = outputSizes[outputSizes.length - 1];
225+
Size previewSize = chooseOptimalSize(outputSizes, 352, 288);
161226

162227
Log.d(TAG, "Creating ImageReader with size " + previewSize.toString() + " for camera " + mCameraId);
163228

164229
mReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(),
165-
ImageFormat.JPEG, /*maxImages*/10);
230+
ImageFormat.JPEG, /*maxImages*/2);
166231

167232
mListener = new SimpleImageListener();
168233

@@ -221,6 +286,23 @@ private CaptureRequest prepareCaptureRequest(int flashMode) {
221286
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
222287

223288
captureBuilder.addTarget(surface);
289+
captureBuilder.set(CaptureRequest.COLOR_CORRECTION_MODE,
290+
CaptureRequest.COLOR_CORRECTION_MODE_FAST);
291+
292+
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
293+
294+
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(mCameraId);
295+
int orientation = characteristics.get(CameraCharacteristics.LENS_FACING);
296+
if(orientation == CameraCharacteristics.LENS_FACING_FRONT) {
297+
rotation = FRONT_CAMERA_ORIENTATIONS.get(rotation);
298+
}
299+
else {
300+
rotation = BACK_CAMERA_ORIENTATIONS.get(rotation);
301+
}
302+
303+
Log.d(TAG, "Rotation: " + rotation);
304+
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, rotation);
305+
224306
captureBuilder.set(CaptureRequest.FLASH_MODE, flashMode);
225307

226308
return captureBuilder.build();
@@ -231,6 +313,29 @@ private CaptureRequest prepareCaptureRequest(int flashMode) {
231313
}
232314
}
233315

316+
private String getCameraIdForOrientation(int cameraFacingOrientation) {
317+
try {
318+
String[] cameraIdList = mCameraManager.getCameraIdList();
319+
320+
for(final String cameraId : cameraIdList) {
321+
CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId);
322+
int orientation = characteristics.get(CameraCharacteristics.LENS_FACING);
323+
if(orientation == cameraFacingOrientation) {
324+
return cameraId;
325+
}
326+
}
327+
328+
if (cameraIdList.length > 0) {
329+
return cameraIdList[0];
330+
}
331+
} catch (CameraAccessException e) {
332+
e.printStackTrace();
333+
return null;
334+
}
335+
336+
return null;
337+
}
338+
234339
private void startBackgroundThread() {
235340
mBackgroundThread = new HandlerThread("CameraBackground");
236341
mBackgroundThread.start();
@@ -252,8 +357,6 @@ private void stopBackgroundThread() {
252357
}
253358

254359
private class SimpleImageListener implements ImageReader.OnImageAvailableListener {
255-
private int mFileId = 0;
256-
257360
@Override
258361
public void onImageAvailable(ImageReader reader) {
259362
Image img = reader.acquireLatestImage();
@@ -305,4 +408,18 @@ public void saveImage(Image image, File file) {
305408
}
306409
}
307410

411+
private static Size chooseOptimalSize(Size[] choices, int width, int height) {
412+
Size bigEnough = choices[0];
413+
for (Size option : choices) {
414+
if (option.getWidth() >= width && option.getHeight() >= height
415+
&& option.getWidth() < bigEnough.getWidth()
416+
&& option.getHeight() < bigEnough.getHeight()
417+
) {
418+
bigEnough = option;
419+
}
420+
}
421+
422+
return bigEnough;
423+
}
424+
308425
}

‎www/CanvasCamera.js

+47-110
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,14 @@
99
cordova.define("cordova/plugin/CanvasCamera", function(require, exports, module) {
1010
var exec = require('cordova/exec');
1111
var CanvasCamera = function(){
12-
var _orientation = 'landscape';
1312
var _obj = null;
1413
var _context = null;
1514
var _camImage = null;
1615

17-
var _x = 0;
18-
var _y = 0;
1916
var _width = 0;
2017
var _height = 0;
2118
};
2219

23-
24-
25-
2620
CanvasCamera.prototype.initialize = function(obj) {
2721
var _this = this;
2822
this._obj = obj;
@@ -32,36 +26,57 @@ cordova.define("cordova/plugin/CanvasCamera", function(require, exports, module)
3226
this._camImage = new Image();
3327

3428
this._camImage.onload = function() {
35-
console.log("_this._context.clearRect"+_this._width+","+_this._height);
36-
_this._context.clearRect(0, 0, _this._width, _this._height);
37-
if (window.orientation == 90
38-
|| window.orientation == -90)
39-
{
40-
_this._context.save();
41-
// rotate 90
42-
console.log("_this._context.translate"+(_this._width/2)+","+ (_this._height/2));
43-
_this._context.translate(_this._width/2, _this._height/2);
44-
_this._context.rotate((90 - window.orientation) *Math.PI/180);
45-
_this._context.drawImage(_this._camImage, 0, 0, 352, 288, -_this._width/2, -_this._height/2, _this._width, _this._height);
46-
//
47-
_this._context.restore();
29+
var image = this;
30+
var canvasWidth = _this._width;
31+
var canvasHeight = _this._height;
32+
var imageWidth = image.width;
33+
var imageHeight = image.height;
34+
var ratio = Math.min(canvasWidth / imageWidth, canvasHeight / imageHeight);
35+
var newWidth = imageWidth * ratio;
36+
var newHeight = imageHeight * ratio;
37+
var cutX, cutY, cutWidth, cutHeight, aspectRatio = 1;
38+
39+
_this._context.clearRect(0, 0, canvasWidth, canvasHeight);
40+
41+
/// decide which gap to fill
42+
if (newWidth < canvasWidth) {
43+
aspectRatio = canvasWidth / newWidth;
4844
}
49-
else
50-
{
51-
console.log("comes in else");
52-
_this._context.save();
53-
// rotate 90
54-
_this._context.translate(_this._width/2, _this._height/2);
55-
_this._context.rotate((90 - window.orientation) *Math.PI/180);
56-
_this._context.drawImage(_this._camImage, 0, 0, 352, 288, -_this._height/2, -_this._width/2, _this._height, _this._width);
57-
//
58-
_this._context.restore();
45+
if (newHeight < canvasHeight) {
46+
aspectRatio = canvasHeight / newHeight;
5947
}
48+
newWidth *= aspectRatio;
49+
newHeight *= aspectRatio;
50+
51+
/// calc source rectangle
52+
cutWidth = imageWidth / (newWidth / canvasWidth);
53+
cutHeight = imageHeight / (newHeight / canvasHeight);
54+
55+
cutX = (imageWidth - cutWidth) * 0.5;
56+
cutY = (imageHeight - cutHeight) * 0.5;
57+
58+
/// make sure source rectangle is valid
59+
if (cutX < 0) cutX = 0;
60+
if (cutY < 0) cutY = 0;
61+
if (cutWidth > imageWidth) cutWidth = imageWidth;
62+
if (cutHeight > imageHeight) cutHeight = imageHeight;
63+
64+
/// fill image in dest. rectangle
65+
_this._context.drawImage(image,
66+
cutX, cutY, cutWidth, cutHeight,
67+
0, 0, canvasWidth, canvasHeight);
6068
};
6169

62-
// register orientation change event
63-
window.addEventListener('orientationchange', this.doOrientationChange);
64-
this.doOrientationChange();
70+
var pixelRatio = window.devicePixelRatio || 1; /// get pixel ratio of device
71+
console.log('pixelRatio=' + pixelRatio);
72+
73+
this._width = 200;
74+
this._height = 200;
75+
this._obj.width = 200;// * pixelRatio; /// resolution of canvas
76+
this._obj.height = 200;// * pixelRatio;
77+
78+
this._obj.style.width = 200 + 'px'; /// CSS size of canvas
79+
this._obj.style.height = 200 + 'px';
6580
};
6681

6782

@@ -90,45 +105,6 @@ cordova.define("cordova/plugin/CanvasCamera", function(require, exports, module)
90105
cordova.exec(function(){}, function(){}, "CanvasCamera", "setCameraPosition", [cameraPosition]);
91106
};
92107

93-
CanvasCamera.prototype.doOrientationChange = function() {
94-
console.log('doOrientationChange');
95-
switch(window.orientation)
96-
{
97-
case -90:
98-
case 90:
99-
this._orientation = 'landscape';
100-
break;
101-
default:
102-
this._orientation = 'portrait';
103-
break;
104-
}
105-
console.log('window.innerWidth'+window.innerWidth);
106-
console.log('window.innerHeight'+window.innerHeight);
107-
108-
//var windowWidth = window.innerWidth;
109-
//var windowHeight = window.innerHeight;
110-
111-
var windowWidth = 200;
112-
var windowHeight = 200;
113-
114-
var pixelRatio = window.devicePixelRatio || 1; /// get pixel ratio of device
115-
116-
117-
this._obj.width = windowWidth;// * pixelRatio; /// resolution of canvas
118-
this._obj.height = windowHeight;// * pixelRatio;
119-
console.log('this._obj.width'+this._obj.width);
120-
121-
this._obj.style.width = windowWidth + 'px'; /// CSS size of canvas
122-
this._obj.style.height = windowHeight + 'px';
123-
console.log('this._obj.style.width'+this._obj.style.width);
124-
125-
this._x = 0;
126-
this._y = 0;
127-
this._width = windowWidth;
128-
this._height = windowHeight;
129-
console.log('this._width'+this._width+" this._height"+this._height);
130-
};
131-
132108
CanvasCamera.prototype.takePicture = function(onsuccess) {
133109
cordova.exec(onsuccess, function(){}, "CanvasCamera", "captureImage", []);
134110
};
@@ -139,43 +115,4 @@ cordova.define("cordova/plugin/CanvasCamera", function(require, exports, module)
139115

140116
var CanvasCamera = cordova.require("cordova/plugin/CanvasCamera");
141117

142-
143-
var DestinationType = {
144-
DATA_URL : 0,
145-
FILE_URI : 1
146-
};
147-
148-
var PictureSourceType = {
149-
PHOTOLIBRARY : 0,
150-
CAMERA : 1,
151-
SAVEDPHOTOALBUM : 2
152-
};
153-
154-
var EncodingType = {
155-
JPEG : 0,
156-
PNG : 1
157-
};
158-
159-
var CameraPosition = {
160-
BACK : 0,
161-
FRONT : 1
162-
};
163-
164-
var CameraPosition = {
165-
BACK : 1,
166-
FRONT : 2
167-
};
168-
169-
var FlashMode = {
170-
OFF : 0,
171-
ON : 1,
172-
AUTO : 2
173-
};
174-
175-
CanvasCamera.DestinationType = DestinationType;
176-
CanvasCamera.PictureSourceType = PictureSourceType;
177-
CanvasCamera.EncodingType = EncodingType;
178-
CanvasCamera.CameraPosition = CameraPosition;
179-
CanvasCamera.FlashMode = FlashMode;
180-
181118
module.exports = CanvasCamera;

0 commit comments

Comments
 (0)
Please sign in to comment.