Compare commits

...
Author SHA1 Message Date
Murat Sutunc ee5cfe89a5 CB-9443 Pick correct maxResolution
This closes #111, closes #56
2015-08-03 15:45:55 -07:00
Murat Sutunc 813d143667 CB-9151 Trigger captureAction only once 2015-08-03 10:09:15 -07:00
Murat Sutunc 110b3b3388 CB-9413 Close RandomAccessStream once copied 2015-07-27 11:39:38 -07:00
Andrey Kurdyumov eeb5880580 CB-5661 Remove outdated iOS quirks about memory 2015-07-27 15:53:13 +06:00
Murat Sutunc 9dfd37cd66 Closing stale pull request: close #106 2015-07-13 16:02:12 -07:00
GillardoandMurat Sutunc c50757c245 CB-9349 Focus control and nice UI
Removed old comment, move style text. close #106
2015-07-10 10:03:36 -07:00
Murat Sutunc 0264e56162 Closing stale pull request: close #73 2015-07-09 15:22:02 -07:00
Murat Sutunc 8ebaaa62bd Closing stale pull request: close #77 2015-07-09 15:19:19 -07:00
Jesse MacFadyen 11eaaa8b9f remove travis-ci integration 2015-07-07 17:36:10 -07:00
Joe Bowser 899802a202 CB-9259: Forgot to add another check on which URI we're using when fixing this thing the first time 2015-07-07 14:27:44 -07:00
Shazron Abdullah 1e607ddcc8 CB-9247 - typo 2015-06-25 06:22:24 -07:00
Shazron Abdullah 63110ea54c CB-9247 - Added macro to conditionally add NSData+Base64.h 2015-06-25 06:20:25 -07:00
Shazron Abdullah b683315be6 CB-9247 - Fixes compilation errors with cordova-ios 4.x 2015-06-25 06:09:59 -07:00
Jesse MacFadyen 2e147ba9ca Merge branch 'CB-8498-take2' of https://github.com/vldmrrr/cordova-plugin-camera 2015-06-17 17:38:01 -07:00
Steve Gill 11498404fc CB-9192 Incremented plugin version. 2015-06-17 17:35:34 -07:00
vladimir 363dd02584 Fix returning native url on windows. 2015-06-17 16:14:58 -05:00
9 changed files with 163 additions and 90 deletions
-13
View File
@@ -1,13 +0,0 @@
language: objective-c
git:
depth: 2
node_js:
- "0.10"
install:
- echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- cd ..
- npm install -g cordova-paramedic
- npm install -g cordova
- npm install -g ios-sim
script:
- cordova-paramedic --platform ios --plugin ${TRAVIS_BUILD_DIR}
-4
View File
@@ -19,8 +19,6 @@
# cordova-plugin-camera
[![Build Status](https://travis-ci.org/apache/cordova-plugin-camera.svg)](https://travis-ci.org/apache/cordova-plugin-camera)
This plugin defines a global `navigator.camera` object, which provides an API for taking pictures and for choosing images from
the system's image library.
@@ -293,8 +291,6 @@ with the Google Plus Photos application. Other crops may not work.
#### iOS Quirks
- Set `quality` below 50 to avoid memory errors on some devices.
- When using `destinationType.FILE_URI`, photos are saved in the application's temporary directory. The contents of the application's temporary directory is deleted when the application ends.
#### Tizen Quirks
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-camera",
"version": "1.2.0",
"version": "1.2.1-dev",
"description": "Cordova Camera Plugin",
"cordova": {
"id": "cordova-plugin-camera",
+1 -1
View File
@@ -22,7 +22,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="cordova-plugin-camera"
version="1.2.0">
version="1.2.1-dev">
<name>Camera</name>
<description>Cordova Camera Plugin</description>
<license>Apache 2.0</license>
+8 -2
View File
@@ -379,7 +379,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
//We don't support PNG, so let's not pretend we do
exif.createInFile(getTempDirectoryPath() + "/.Pic.jpg");
exif.createInFile(sourcePath);
exif.readExifData();
rotate = exif.getOrientation();
@@ -442,7 +442,13 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
this.callbackContext.success(uri.toString());
} else {
bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
if(croppedUri != null) {
bitmap = getScaledBitmap(FileHelper.stripFileProtocol(croppedUri.toString()));
}
else
{
bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
}
if (rotate != 0 && this.correctOrientation) {
bitmap = getRotatedBitmap(rotate, bitmap, exif);
+18 -4
View File
@@ -20,7 +20,6 @@
#import "CDVCamera.h"
#import "CDVJpegHeaderWriter.h"
#import "UIImage+CropScaleOrientation.h"
#import <Cordova/NSData+Base64.h>
#import <ImageIO/CGImageProperties.h>
#import <AssetsLibrary/ALAssetRepresentation.h>
#import <AssetsLibrary/AssetsLibrary.h>
@@ -31,6 +30,10 @@
#import <MobileCoreServices/UTCoreTypes.h>
#import <objc/message.h>
#ifndef __CORDOVA_4_0_0
#import <Cordova/NSData+Base64.h>
#endif
#define CDV_PHOTO_PREFIX @"cdv_photo_"
static NSSet* org_apache_cordova_validArrowDirections;
@@ -38,9 +41,20 @@ static NSSet* org_apache_cordova_validArrowDirections;
static NSString* toBase64(NSData* data) {
SEL s1 = NSSelectorFromString(@"cdv_base64EncodedString");
SEL s2 = NSSelectorFromString(@"base64EncodedString");
SEL realSel = [data respondsToSelector:s1] ? s1 : s2;
NSString* (*func)(id, SEL) = (void *)[data methodForSelector:realSel];
return func(data, realSel);
SEL s3 = NSSelectorFromString(@"base64EncodedStringWithOptions:");
if ([data respondsToSelector:s1]) {
NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s1];
return func(data, s1);
} else if ([data respondsToSelector:s2]) {
NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s2];
return func(data, s2);
} else if ([data respondsToSelector:s3]) {
NSString* (*func)(id, SEL, NSUInteger) = (void *)[data methodForSelector:s3];
return func(data, s3, 0);
} else {
return nil;
}
}
@implementation CDVPictureOptions
+131 -61
View File
@@ -267,7 +267,12 @@ function takePictureFromFileWindows(successCallback, errorCallback, args) {
else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
successCallback(URL.createObjectURL(storageFile));
if(destinationType == Camera.DestinationType.NATIVE_URI) {
successCallback("ms-appdata:///local/" + storageFile.name);
}
else {
successCallback(URL.createObjectURL(storageFile));
}
}, function () {
errorCallback("Can't access localStorage folder.");
});
@@ -307,24 +312,32 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
saveToPhotoAlbum = args[9],
cameraDirection = args[11],
capturePreview = null,
captureCancelButton = null,
cameraCaptureButton = null,
cameraCancelButton = null,
capture = null,
captureSettings = null,
CaptureNS = Windows.Media.Capture,
sensor = null;
var createCameraUI = function () {
// Create fullscreen preview
capturePreview = document.createElement("video");
// create style for take and cancel buttons
var buttonStyle = "width:45%;padding: 10px 16px;font-size: 18px;line-height: 1.3333333;color: #333;background-color: #fff;border-color: #ccc; border: 1px solid transparent;border-radius: 6px; display: block; margin: 20px; z-index: 1000;border-color: #adadad;";
// z-order style element for capturePreview and captureCancelButton elts
// Create fullscreen preview
// z-order style element for capturePreview and cameraCancelButton elts
// is necessary to avoid overriding by another page elements, -1 sometimes is not enough
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 999";
capturePreview = document.createElement("video");
capturePreview.style.cssText = "position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 999;";
// Create capture button
cameraCaptureButton = document.createElement("button");
cameraCaptureButton.innerText = "Take";
cameraCaptureButton.style.cssText = buttonStyle + "position: fixed; left: 0; bottom: 0; margin: 20px; z-index: 1000";
// Create cancel button
captureCancelButton = document.createElement("button");
captureCancelButton.innerText = "Cancel";
captureCancelButton.style.cssText = "position: fixed; right: 0; bottom: 0; display: block; margin: 20px; z-index: 1000";
cameraCancelButton = document.createElement("button");
cameraCancelButton.innerText = "Cancel";
cameraCancelButton.style.cssText = buttonStyle + "position: fixed; right: 0; bottom: 0; margin: 20px; z-index: 1000";
capture = new CaptureNS.MediaCapture();
@@ -355,6 +368,22 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
return capture.initializeAsync(captureSettings);
}).then(function () {
// create focus control if available
var VideoDeviceController = capture.videoDeviceController;
var FocusControl = VideoDeviceController.focusControl;
if (FocusControl.supported === true) {
capturePreview.addEventListener('click', function () {
var preset = Windows.Media.Devices.FocusPreset.autoNormal;
FocusControl.setPresetAsync(preset).done(function () {
});
});
}
// msdn.microsoft.com/en-us/library/windows/apps/hh452807.aspx
capturePreview.msZoom = true;
capturePreview.src = URL.createObjectURL(capture);
@@ -365,11 +394,10 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
if (sensor !== null) {
sensor.addEventListener("orientationchanged", onOrientationChange);
}
capturePreview.addEventListener('click', captureAction);
captureCancelButton.addEventListener('click', function () {
destroyCameraPreview();
errorCallback('Cancelled');
}, false);
// add click events to capture and cancel buttons
cameraCaptureButton.addEventListener('click', onCameraCaptureButtonClick);
cameraCancelButton.addEventListener('click', onCameraCancelButtonClick);
// Change default orientation
if (sensor) {
@@ -388,9 +416,10 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
return;
}
// Insert preview frame and controls into page
// add elements to body
document.body.appendChild(capturePreview);
document.body.appendChild(captureCancelButton);
document.body.appendChild(cameraCaptureButton);
document.body.appendChild(cameraCancelButton);
if (aspectRatios.indexOf(DEFAULT_ASPECT_RATIO) > -1) {
return setAspectRatio(capture, DEFAULT_ASPECT_RATIO);
@@ -405,16 +434,27 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
};
var destroyCameraPreview = function () {
// If sensor is available, remove event listener
if (sensor !== null) {
sensor.removeEventListener('orientationchanged', onOrientationChange);
}
// Pause and dispose preview element
capturePreview.pause();
capturePreview.src = null;
[capturePreview, captureCancelButton].forEach(function(elem) {
// Remove event listeners from buttons
cameraCaptureButton.removeEventListener('click', onCameraCaptureButtonClick);
cameraCancelButton.removeEventListener('click', onCameraCancelButtonClick);
// Remove elements
[capturePreview, cameraCaptureButton, cameraCancelButton].forEach(function (elem) {
if (elem /* && elem in document.body.childNodes */) {
document.body.removeChild(elem);
}
});
// Stop and dispose media capture manager
if (capture) {
capture.stopRecordAsync();
capture = null;
@@ -441,33 +481,33 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
var photoStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
var finalStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
capture.capturePhotoToStreamAsync(encodingProperties, photoStream)
.then(function() {
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(photoStream);
})
.then(function(dec) {
finalStream.size = 0; // BitmapEncoder requires the output stream to be empty
return Windows.Graphics.Imaging.BitmapEncoder.createForTranscodingAsync(finalStream, dec);
})
.then(function(enc) {
// We need to rotate the photo wrt sensor orientation
enc.bitmapTransform.rotation = orientationToRotation(sensor.getCurrentOrientation());
return enc.flushAsync();
})
.then(function() {
return tempCapturedFile.openAsync(Windows.Storage.FileAccessMode.readWrite);
})
.then(function(fileStream) {
return Windows.Storage.Streams.RandomAccessStream.copyAsync(finalStream, fileStream);
})
.done(function() {
photoStream.close();
finalStream.close();
complete(tempCapturedFile);
}, function() {
photoStream.close();
finalStream.close();
throw new Error("An error has occured while capturing the photo.");
});
.then(function() {
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(photoStream);
})
.then(function(dec) {
finalStream.size = 0; // BitmapEncoder requires the output stream to be empty
return Windows.Graphics.Imaging.BitmapEncoder.createForTranscodingAsync(finalStream, dec);
})
.then(function(enc) {
// We need to rotate the photo wrt sensor orientation
enc.bitmapTransform.rotation = orientationToRotation(sensor.getCurrentOrientation());
return enc.flushAsync();
})
.then(function() {
return tempCapturedFile.openAsync(Windows.Storage.FileAccessMode.readWrite);
})
.then(function(fileStream) {
return Windows.Storage.Streams.RandomAccessStream.copyAndCloseAsync(finalStream, fileStream);
})
.done(function() {
photoStream.close();
finalStream.close();
complete(tempCapturedFile);
}, function() {
photoStream.close();
finalStream.close();
throw new Error("An error has occured while capturing the photo.");
});
});
})
.done(function(capturedFile) {
@@ -480,8 +520,8 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
}, function(err) {
destroyCameraPreview();
errorCallback(err);
destroyCameraPreview();
errorCallback(err);
});
};
@@ -552,6 +592,33 @@ function takePictureFromCameraWP(successCallback, errorCallback, args) {
});
};
/**
* When Capture button is clicked, try to capture a picture and return
*/
var onCameraCaptureButtonClick = function() {
// Make sure user can't click more than once
if (this.getAttribute('clicked') === '1') {
return false;
} else {
this.setAttribute('clicked', '1');
}
captureAction();
};
/**
* When Cancel button is clicked, destroy camera preview and return with error callback
*/
var onCameraCancelButtonClick = function() {
// Make sure user can't click more than once
if (this.getAttribute('clicked') === '1') {
return false;
} else {
this.setAttribute('clicked', '1');
}
destroyCameraPreview();
errorCallback('no image selected');
};
/**
* When the phone orientation change, get the event and change camera preview rotation
* @param {Object} e - SimpleOrientationSensorOrientationChangedEventArgs
@@ -629,24 +696,27 @@ function takePictureFromCameraWindows(successCallback, errorCallback, args) {
// decide which max pixels should be supported by targetWidth or targetHeight.
var maxRes = null;
var UIMaxRes = WMCapture.CameraCaptureUIMaxPhotoResolution;
var totalPixels = targetWidth * targetHeight;
switch (true) {
case (targetWidth >= 1280 || targetHeight >= 960) :
cameraCaptureUI.photoSettings.maxResolution = UIMaxRes.large3M;
break;
case (targetWidth >= 1024 || targetHeight >= 768) :
maxRes = UIMaxRes.mediumXga;
break;
case (targetWidth >= 800 || targetHeight >= 600) :
maxRes = UIMaxRes.mediumXga;
break;
case (targetWidth >= 640 || targetHeight >= 480) :
maxRes = UIMaxRes.smallVga;
break;
case (targetWidth >= 320 || targetHeight >= 240) :
case (totalPixels <= 320 * 240):
maxRes = UIMaxRes.verySmallQvga;
break;
default :
case (totalPixels <= 640 * 480):
maxRes = UIMaxRes.smallVga;
break;
case (totalPixels <= 1024 * 768):
maxRes = UIMaxRes.mediumXga;
break;
case (totalPixels <= 3 * 1000 * 1000):
maxRes = UIMaxRes.large3M;
break;
case (totalPixels <= 5 * 1000 * 1000):
maxRes = UIMaxRes.veryLarge5M;
break;
default:
maxRes = UIMaxRes.highestAvailable;
break;
}
cameraCaptureUI.photoSettings.maxResolution = maxRes;
@@ -685,7 +755,7 @@ function savePhoto(picture, options, successCallback, errorCallback) {
resizeImageBase64(successCallback, errorCallback, picture, options.targetWidth, options.targetHeight);
} else {
fileIO.readBufferAsync(picture).done(function(buffer) {
var strBase64 =encodeToBase64String(buffer);
var strBase64 = encodeToBase64String(buffer);
picture.deleteAsync().done(function() {
successCallback(strBase64);
}, function(err) {
@@ -476,7 +476,7 @@
pictureOptions.encodingType = EncodingTypePNG;
resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions];
XCTAssertEqualObjects([resultData base64EncodedString], [originalImageDataPNG base64EncodedString]);
XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataPNG base64EncodedStringWithOptions:0]);
// Original, JPEG, full quality
@@ -487,7 +487,7 @@
pictureOptions.encodingType = EncodingTypeJPEG;
resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions];
XCTAssertEqualObjects([resultData base64EncodedString], [originalImageDataJPEG base64EncodedString]);
XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataJPEG base64EncodedStringWithOptions:0]);
// Original, JPEG, with quality value
@@ -500,7 +500,7 @@
NSData* originalImageDataJPEGWithQuality = UIImageJPEGRepresentation(originalImage, [pictureOptions.quality floatValue]/ 100.f);
resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions];
XCTAssertEqualObjects([resultData base64EncodedString], [originalImageDataJPEGWithQuality base64EncodedString]);
XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataJPEGWithQuality base64EncodedStringWithOptions:0]);
// TODO: usesGeolocation is not tested
}
+1 -1
View File
@@ -22,7 +22,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="cordova-plugin-camera-tests"
version="1.2.0">
version="1.2.1-dev">
<name>Cordova Camera Plugin Tests</name>
<license>Apache 2.0</license>