I am using phonegap 2.0.0 on iOS and using basically the stock image capture code. After the image is captured it is saved to the phone, the URI is saved to the database along with the rest of the items info and the image is displayed on the page.
All this is working on both iOS and android. The issue is that when the iOS phone is turned off and allowed to sit for a period of time (overnight) the images no longer display. The rest of the data is retrieved from the database and displayed but the images just show a black square where the image should be (indicating the info is still inn the database)
Does iOS rename images after being turned off and allowed to sit for a some time? any suggestions? if the phone is turned off and back on this does not happen.. only after the phone sits for some time...
this seems very relevant...
Capturing and storing a picture taken with the Camera into a local database / PhoneGap / Cordova / iOS
for anybody else having this issue the following code worked for me...
function capturePhoto() {
navigator.camera.getPicture(movePic, onFail,{ quality : 70 });
}
function movePic(file){
window.resolveLocalFileSystemURI(file, resolveOnSuccess, resOnError);
}
function resolveOnSuccess(entry){
var d = new Date();
var n = d.getTime();
var newFileName = n + ".jpg";
var myFolderApp = "myPhotos";
window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSys) {
fileSys.root.getDirectory( myFolderApp,
{create:true, exclusive: false},
function(directory) {
entry.moveTo(directory, newFileName, successMove, resOnError);
},
resOnError);
},
resOnError);
}
function successMove(imageUri) {
document.getElementById('smallImage').src = imageUri.fullPath;
//hidden input used to save the file path to the database
document.getElementById('site_front_pic').value = "file://"+imageUri.fullPath;
smallImage.style.display = 'block';
}
function onFail(message) {
alert('Failed to load picture because: ' + message);
}
function resOnError(error) {
alert(error.code);
}
Related
I have an app which is used for taking pictures and sending them to the server. I use Image Picker -> Camera to take photos and they are stored in the default Image Picker storage.
I wrote a method to check for photos older than x days and removing them from the storage. However the path returned from the getApplicationDocumentsDirectory() method: /data/user/0/com.example.buzzbee/app_flutter is not what it is really on the phone: Android/data/com.example.buzzbee/files/Pictures.
Any ideas of what is going on? Where is this additional "app_flutter" coming from - do I need to erase it manually?
Here is the code:
Future<void> clearOldPictures({int daysOld}) async {
var directory = (await getApplicationDocumentsDirectory()).path;
debugPrint('APP STORAGE DIRECTORY: $directory');
var pictureList = Io.Directory("$directory/files/Pictures/").listSync();
debugPrint(pictureList.toString());
for (var picture in pictureList) {
var stat = Io.FileStat.statSync(picture.path);
var createdDate = stat.accessed;
var daysOld = DateTime.now().difference(createdDate).inDays;
if (daysOld >= daysOld) {
picture.delete();
}
}
}
I would like to do image annotation for my Ionic Application. So the flow of the app would be using the camera plugin to take a picture and use FabricJs to draw on the image then save the file.
I hit the roadblock when I am trying to save or overwrite the file. Apparently the source "http://localhost:8080/file/data/user/0/***/files/1547183479807.png" file does not update.
The flow of the app
1) Take picture with #ionic-native/camera
2) Copy the file to a local directory
3) Use this.win.Ionic.WebView.convertFileSrc to convert the file name to "http://localhost:8080/file/data/user/0/***/files/1547183479807.png"
4) Push to another page to access the canvas
5) Use the link to setBackground to my canvas (FabricJs)
6) Draw on the image (Manually)
7) Save the file via overwriting the existing file but nothing works from here on.
I tried to
- overwrite with writeFile & writeExisitingFile, did not work.
- removeFile and writeFile and did not work.
- tried converting to ArrayBuffer rather than Blob and did not work
- tried creating another new file, did not work too (it seems like after I push to a new page, all the file functions does not affect the files)
- tried using native cordova but did not work too.
- delete that same files twice, (first time I did not get an error but the second time I got an error saying "File Does not exist" but when I view the source, the file is also there and appearing in my thumbnail on my App.
private copyFileToLocalDir(namePath, currentName, newFileName,id,index) {
this.file.copyFile(namePath, currentName, this.file.dataDirectory, newFileName).then(success => {
const keys = id.split('-');
let filename = this.file.dataDirectory + newFileName;
this.fp = this.win.Ionic.WebView.convertFileSrc(filename) ;
this.navCtrl.push(AnnotationsPage, {
filepath: this.fp,
filename: newFileName
});
this.presentToast("Image Successfully Added",'middle');
}, error => {
this.presentToast('Error while storing file.','middle');
});
}
Annotation.ts
savePicture() {
let image = this.canvas.toDataURL({
format: 'png'
});
this.saveBase64(image);
}
public saveBase64(base64:string):Promise<string>{
return new Promise((resolve, reject)=>{
var realData = base64.split(",")[1]
let blob=this.b64toBlob(realData,"image/png")
this.file.writeFile(this.file.dataDirectory,this.filename,blob,{replace:true})
// this.file.writeExistingFile(this.file.dataDirectory,this.filename, blob)
.then((val)=>{
console.log('Write Info',val)
let fp = this.win.Ionic.WebView.convertFileSrc(this.file.dataDirectory+this.filename) ;
})
.catch((err)=>{
console.log('error writing blob')
console.log(err);
// reject(err)
})
})
}
b64toBlob(b64Data, contentType) {
contentType = contentType || '';
var sliceSize = 512;
var byteCharacters = atob(b64Data);
var byteArrays = [];
for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
var slice = byteCharacters.slice(offset, offset + sliceSize);
var byteNumbers = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
I check the base64 file, it is working fine (Throw the data to an online converter and it display the picture.
After the function "copyFileToLocalDir", it seems like I am unable to modify the files store in the local directory.
Thanks in advance. Feel free to ask me more question. 7 hours and no result.
Update on the testing, I am doing.
Did File.readAsDataUrl and as expected the file file:///data/user/0/*/files/1547231914843.png updated from the old image to the new edited. (Tested the base64 on some online converter) but it still does not reflect on the source http://localhost:8080/file/data/user/0/***/files/1547231914843.png
Thanks to all those who read through.
After tons of testing, I found out that Ionic Webview's files, will not be updated unless you recall them again (Kind of like a cache and apparently there is no way to reset or flush the cache).
So in my case, I would need to remove the image from the webview and call it out again then it will go back to retrieve again or create another file with another file name and display it.
I'm using the Plugin.Media from #JamesMontemagno version 2.4.0-beta (which fixes picture orientation), it's working on Adroind 4.1.2 (Jelly Bean) and Marshmallow, but NOT on my Galaxy S5 Neo with Android version 5.1.1.
Basically when I take a picture it never returns back on the page from where I started the process; always returns back to the initial home page.
On devices where it works, when I take a picture, I see that first of all the application fires OnSleep, then after taking the picture fires OnResume.
On my device where is NOT working it fires OnSleep and after taking the picture doesn't fire OnResume, it fires the initialization page and then OnStart.
For this reason it doesn't open the page where I was when taking the picture.
What should I do to make sure it fires OnResume returning to the correct page and not OnStart which returns on initial fome page ?
In addition, when I take a picture it takes almost 30 seconds to get back to the code after awaiting TakePhotoAsync process, and it's too slow!
Following my code:
MyTapGestureRecognizerEditPicture.Tapped += async (sender, e) =>
{
//Display action sheet
String MyActionResult = await DisplayActionSheet(AppLocalization.UserInterface.EditImage,
AppLocalization.UserInterface.Cancel,
AppLocalization.UserInterface.Delete,
AppLocalization.UserInterface.TakePhoto,
AppLocalization.UserInterface.PickPhoto);
//Execute action result
if (MyActionResult == AppLocalization.UserInterface.TakePhoto)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Take photo
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert(AppLocalization.UserInterface.Alert, AppLocalization.UserInterface.NoCameraAvailable, AppLocalization.UserInterface.Ok);
}
else
{
var MyPhotoFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
Directory = "MyApp",
Name = "MyAppProfile.jpg",
SaveToAlbum = true,
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Small
});
if (MyPhotoFile != null)
{
//Render image
MyProfilePicture.Source = ImageSource.FromFile(MyPhotoFile.Path);
//Save image on database
MemoryStream MyMemoryStream = new MemoryStream();
MyPhotoFile.GetStream().CopyTo(MyMemoryStream);
byte[] MyArrBytePicture = MyMemoryStream.ToArray();
await SaveProfilePicture(MyArrBytePicture);
MyPhotoFile.Dispose();
MyMemoryStream.Dispose();
}
}
}
if (MyActionResult == AppLocalization.UserInterface.PickPhoto)
{
//-----------------------------------------------------------------------------------------------------------------------------------------------
//Pick photo
await CrossMedia.Current.Initialize();
if (!CrossMedia.Current.IsPickPhotoSupported)
{
await DisplayAlert(AppLocalization.UserInterface.Alert, AppLocalization.UserInterface.PermissionNotGranted, AppLocalization.UserInterface.Ok);
}
else
{
var MyPhotoFile = await CrossMedia.Current.PickPhotoAsync();
if (MyPhotoFile != null)
{
//Render image
MyProfilePicture.Source = ImageSource.FromFile(MyPhotoFile.Path);
//Save image on database
MemoryStream MyMemoryStream = new MemoryStream();
MyPhotoFile.GetStream().CopyTo(MyMemoryStream);
byte[] MyArrBytePicture = MyMemoryStream.ToArray();
await SaveProfilePicture(MyArrBytePicture);
MyPhotoFile.Dispose();
MyMemoryStream.Dispose();
}
}
}
};
Please help!! We need to deploy this app but we cannot do it with this problem.
Thank you in advance!
It is perfectly normal to have the Android OS terminate and restart an Activity. As you are seeing, your app's Activity it will be automatically restarted when the camera app exits and the OS returns control to your app. The odds are it just needed more memory in order to take that photo with the Neo's 16MP camera, you can watch the logcat output to confirm that.
Restarted – It is possible for an activity that is anywhere from paused to stopped in the lifecycle to be removed from memory by Android. If the user navigates back to the activity it must be restarted, restored to its previously saved state, and then displayed to the user.
What to do:
So on the Xamarin.Forms OnStart lifecycle method you need to restore your application to a valid running state (initializing variables, preforming any bindings, etc...).
Plug code:
The Android platform code for the TakePhotoAsync method looks fine to me, but remember that the memory for that image that is passed back via the Task will be doubled as it is marshaled from the ART VM back the Mono VM. Calling GC.Collect() as soon as possible after the return will help (but your Activity is restarting anyway...)
public async Task<MediaFile> TakePhotoAsync(StoreCameraMediaOptions options)
{
~~~
var media = await TakeMediaAsync("image/*", MediaStore.ActionImageCapture, options);
In turn calls:
this.context.StartActivity(CreateMediaIntent(id, type, action, options));
Not much less you can really do within the Android OS to popup the Camera.
In addition, when I take a picture it takes almost 30 seconds to get back to the code after awaiting TakePhotoAsync process, and it's too slow!
Is that on your Neo? Or all devices?
I would call that very suspect (ie. a bug) as even flushing all the Java memory after the native Camera Intent/Activity and the restart time for your app's Activity should not take 30 seconds on a oct-core 1.6 GHz Cortex... but I do not have your device, app and code in front of me....
Can anyone help me find out if/how you can get image data off of the 'camera roll' in an Android device, using (Appcelorator) Titanium ? I have found a 3rd party module for IOS that does this but I am desperate to find one for Android. Otherwise I'll have to scrap the Titanium and go true native.
What I need is a function that returns an array of data about the images on the device. Although I would love to get 'geolocation' data ( if it exists ), all I really need is a 'create date', and a path to the image, or the actual TiBlob.
Seems simple but i get no responses on the Appcelerator forums, which worries me. There must be at least an Android 'module' that achieves this?
Ti.Media.openPhotoGallery({
allowEditing : true,
success : function(event) {
var image = require('/modules/parts/squarecropper').crop(event.media);
setImage(image);
Ti.Media.hideCamera();
},
cancel : function() {
},
saveToPhotoGallery : false,
mediaTypes : [Ti.Media.MEDIA_TYPE_PHOTO],
});
The above method would do your job. Now then either access it directly or get into a file system and encode and decode the data.
var f = Titanium.Filesystem.getFile(currIamge);
var temp = f.read();
var encodeData = Ti.Utils.base64encode(temp);
alert("encodeData = "+encodeData);
Hey CodeWarriors, anyone know if on the iPhone in Mobile Safari whether there is a timeout for loading a certain amount of Javascripting/jQuery?? The moving background and the black covering over the heart are not working on the iPhone, but are solid on Firefox and my MacBook Pro's Safari – they don't load:
http://www.zookeeper.com/beyourowncreature/2011
Still working on some things on this site before it launches...
Thanks in advance if you have any ideas.
-Dave
All I can see is an error in your jquery.spritely on line 268, 1st line in the window.Touch clause. el[0] does not exist
activeOnClick: function() {
// make this the active script if clicked...
var el = $(this);
if (window.Touch) { // iphone method see http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone/9 or http://www.nimblekit.com/tutorials.html for clues...
el[0].ontouchstart = function(e) {
$._spritely.activeSprite = el;
};
} else {
el.click(function(e) {
$._spritely.activeSprite = el;
});
}
return this;
},
And as the previous comment says, you have and unmatched tag