Ionic Camera Uploading to S3 - ionic-framework

I am having a problem taking a picture and uploading it to an S3 bucket when using FILE_URI for the camera.DestinationType. When using this same process with the DATA_URL DestinationType it works fine.
When using FILE_URI the file that gets uploaded to the S3 bucket says it's corrupt. I did notice the file size is much smaller (~100B) than an actual image.
Here are the versions I am using:
Ionic Framework 3.9.2 and cordova-plugin-camera 4.0.2
Here is the code I'm using:
const options: CameraOptions = {
quality: 100,
correctOrientation: true,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
sourceType: this.camera.PictureSourceType.CAMERA,
}
this.camera.getPicture(options).then((imageData) => {
console.log(imageData);
let base64data = 'data:image/jpeg;base64,' + imageData;
this.bigImg = base64data;
// imageData is either a base64 encoded string or a file URI
// If it's base64:
this.selectedPhoto = this.dataURItoBlob(this.bigImg);
}, (err) => {
// Handle error
console.log("Get Image Error: " + err);
});
this.sub = AWS.config.credentials.identityId;
let uploadMessage = "Uploading Image...";
let photoName = "testPic";
this.upload(this.selectedPhoto, uploadMessage, photoName)
.then(data => {
// Change active page to list
this.navCtrl.setRoot(TabsPage).then(() => {
});
});
dataURItoBlob(dataURI) {
// code adapted from: http://stackoverflow.com/questions/33486352/cant-upload-image-to-aws-s3-from-ionic-camera
let binary = atob(dataURI.split(',')[1]);
let array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
};
upload(selectedPhoto, uploadMessage, photoName) {
return new Promise((resolve, reject) => {
let loading = this.loadingCtrl.create({
content: uploadMessage
});
loading.present();
if (selectedPhoto) {
this.s3.upload({
'Key': 'protected/' + this.sub + '/' + photoName,
'Body': selectedPhoto,
'ContentType': 'image/jpeg'
}).promise().then((data) => {
this.data2 = data;
console.log('upload complete:', JSON.stringify(data));
loading.dismiss();
resolve(data);
}, err => {
console.log('upload failed....', JSON.stringify(err));
loading.dismiss();
reject(err);
});
} else {
loading.dismiss();
reject("upload failed");
}
});

Related

readAsDataUrl function no output

i am using ionic 5 & capacitor.
For some reason, the readAsDataURL isnt working and it isnt showing me an error message either.
the path & file name seem fine, they are :
filePath: file:///storage/emulated/0/Android/data/io.ionic.starter/cache/1763816379-cropped.jpg
path : file:///storage/emulated/0/Android/data/io.ionic.starter/cache/
fileName: 1763816379-cropped.jpg
showCroppedImage(ImagePath) {
var filePath = ImagePath;
let fileName = filePath.split("/").pop();
let path = filePath.substring(0, filePath.lastIndexOf("/") + 1);
alert(filePath);
alert(fileName);
alert(path);
alert("works till here");
this.file
.readAsDataURL(path, fileName)
.then((base64) => {
alert(base64);
})
.catch((err) => {
console.log(err);
alert(err);
});
}
this.file.createFile(
this.file.externalDataDirectory,
"base64string.txt",
true
);
this.file.readAsText(this.file.externalDataDirectory, "base64string.txt");
this.blob = new Blob([this.base64string]);
this.file
.writeFile(
this.file.externalDataDirectory,
"base64string.txt",
this.blob,
{ replace: true, append: false }
)
.then(() => {
alert("File saved in internal storage/android/data/io.starter.ionic/");
});
}
Earlier, my file was getting saved in an internal directory which was not accessible by a user. So i used the externalDataDirectory function, which fixed my issue. It stores the file in an external directory which is accessible by the user.
The file is stored in "internal storage/android/data/#app_id#/"
I ended up sorting the problem for my application and I have included it below:
/** #desc crop the selected image */
async cropImage(fileUrl: any) {
this.show_spinner = true;
await this.ionLoader.showLoader('Cropping Image...');
this.crop.crop(fileUrl, {
quality: 75,
targetHeight: 320,
targetWidth: 240
})
.then(
async (newImage) => {
this.show_spinner = false;
await this.ionLoader.hideLoader();
this.showCroppedImage(newImage.split('?')[0]);
},
async (error: IonicResultMessageInterface) => {
this.show_spinner = false;
await this.ionLoader.hideLoader();
console.error('Error cropping image', error);
console.log(error);
this.setUserProfileImage();
this.toasterService.showToast(error.message, 'failure');
}
);
}
/** #desc show the image after it has been cropped */
async showCroppedImage(ImagePath: string) {
console.log(ImagePath);
this.show_spinner = true;
const copyPath = ImagePath;
const splitPath = copyPath.split('/');
const imageName = splitPath[splitPath.length - 1];
const file_ext = imageName.substr(imageName.lastIndexOf('.') + 1);
try {
const base64 = await Filesystem.readFile({ path: ImagePath});
if (base64) {
console.log(base64);
this.userImageUrl = 'data:image/' + file_ext + ';base64,' + base64.data;
this.show_spinner = false;
await this.updateProfilePictureMethod();
} else {
this.show_spinner = false;
console.log('Error in the showCroppedImage File method');
console.log('Unexpected Error');
this.setUserProfileImage();
this.toasterService.showToast('Unexpected Error Occurred in the showCroppedImage File', 'failure');
}
} catch (error) {
this.show_spinner = false;
console.log('Error in the showCroppedImage File method');
console.log('Unexpected Error');
this.setUserProfileImage();
this.toasterService.showToast(error.message, 'failure');
}
}

IONIC-I cannot convert 'image to base64'

The photo I took using the application camera appears as a black screen. I looked at the other questions and tried some of the answers, but I can't translate the picture to base64. Could you help?
You can see the entire code from the link.
https://pastebin.ubuntu.com/p/4FwYdk5fvD/
takePicture(sourceType: PictureSourceType)
{
var options: CameraOptions = {
quality: 100,
sourceType: sourceType,
saveToPhotoAlbum: false,
correctOrientation: true
};
this.camera.getPicture(options).then(imagePath => {
if (this.plt.is('android') && sourceType === this.camera.PictureSourceType.PHOTOLIBRARY)
{
this.filePath.resolveNativePath(imagePath)
.then(filePath => {
let correctPath = filePath.substr(0, filePath.lastIndexOf('/') + 1);
let currentName = imagePath.substring(imagePath.lastIndexOf('/') + 1, imagePath.lastIndexOf('?'));
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
});
}
else
{
var currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
var correctPath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
this.copyFileToLocalDir(correctPath, currentName, this.createFileName());
}
});
}
i sorta had the same issue. I also wanted the name (not the path though), and i also wanted a base 64... so what i did what this:
takePicture(sourceType: PictureSourceType) {
var options: CameraOptions = {
quality: 80,
sourceType: sourceType,
saveToPhotoAlbum: false,
correctOrientation: true,
destinationType: 1,
targetWidth: 1240,
targetHeight: 768,
};
this.camera.getPicture(options)
.then((imageData) => {
this.imgService.convertFilePathToBlob(imageData).subscribe(blob => {
this.image = blob;
});
let correctPath = imageData; // or subStr the parts you want
let currentName = this.image[1]; // grab the name
let currentImage = this.image[0]; // the image itself as base64
}).catch((err) => {
console.warn("takePicture Error: " + err);
});}
and the convert function... remember to import File, FileEntry from '#ionic-native/file/ngx'
convertFilePathToBlob(filePath:string) {
return from(this.file.resolveLocalFilesystemUrl(filePath)).pipe(
mergeMap((fileEntry: FileEntry) => {
return Observable.create(observer => {
fileEntry.file(file => {
const reader = new FileReader();
reader.onloadend = () => {
const imgBlob = new Blob([reader.result], { type: file.type });
observer.next([imgBlob, file.name]); // the name can be grabbed now
observer.complete();
};
reader.readAsArrayBuffer(file);
}, error => {
observer.error(error);
});
});
}));}
This works in my case, but i find it insane i had to do all this, and it took some debugging and googling... i hope it helps you in some way... :)

how to navigate to a page by clicking back button on camera open in ionic2

I have a HomePage and in ionViewWillEnter() I have added camera code. So that when HomePage get trigger it opens the Camera first
I want to customize the back button behavior that when I press the back button, after opening the camera it should navigate to SecondPage,by default it is navigating to HomePage.
ionViewWillEnter() {
this.captureVideo();
}
captureVideo() {
platform.registerBackButtonAction(() => {
this.navCtrl.push(SecondPage)
});
let options: CaptureVideoOptions = { limit: 1 };
this.mediaCapture.captureVideo(options)
.then((videodata: MediaFile[]) => {
var i, path, len;
for (i = 0, len = videodata.length; i < len; i += 1) {
path = videodata[i].fullPath;
}
this.flag_play = false;
this.flag_upload = false;
this.file.resolveLocalFilesystemUrl(path).then((newUrl) => {
alert(JSON.stringify(newUrl))
let dirPath = newUrl.nativeURL;
let dirPathSegments = dirPath.split('/')
dirPathSegments.pop()
dirPath = dirPathSegments.join('/')
this.file.readAsArrayBuffer(dirPath, newUrl.name).then(async (buffer)
=> {
await this.upload(buffer, newUrl.name);
})
})
})
.then(() => {
var videoFileName = 'video-name-here';
this.videoEditor.createThumbnail(
{
fileUri:'abc',// this.videoId,
outputFileName: videoFileName,
atTime: 2,
width: 320,
height: 480,
quality: 100
}
).then(result => {
this.result = result;
this.base64.encodeFile(result).then((base64File) => {
this.base64Thumbnail = base64File.replace("*;charset=utf-8", "jpg")
}, err => {
alert("Unable to create thumbnail")
})
})
})
}
The hardware back button works as default behaviour of cancel ...so to customize it put your specific code in the error...
takePicture(){
this.camera.getPicture({
destinationType: this.camera.DestinationType.DATA_URL,
targetWidth: 1000,
targetHeight: 1000
}).then((imageData) => {
// imageData is a base64 encoded string
this.base64Image = "data:image/jpeg;base64," + imageData;
}, (err) => {
this.navCtrl.pop();
});
}
}

how to save image base 64 as a file

I'm using ionic2: I want to upload an image from the gallery, crop it and send it to a server.
uploadImage(): Promise<any> {
var status = 'upload';
return new Promise(resolve =>
{
const options: CameraOptions = {
quality: 100,
sourceType: 2,
destinationType: this.camera.DestinationType.DATA_URL,
mediaType: this.camera.MediaType.PICTURE,
allowEdit: true
}
this.camera.getPicture(options).then((imageData) => {
// imageData is either a base64 encoded string or a file URI
// If it's base64:
this.base64Image = "data:image/jpeg;base64",imageData;
console.log("imaaage ",this.base64Image);
resolve(this.base64Image);
}, (err) => {
console.log("error")
});
});
}
the problem is that: I want destinationType to be FILE_URL to send it, at the same time I want it to be DATA_URL to display it to the user.
what should I do to solve this problem?

Uploading hundreds of photos (almost a thousand) using ionic

I've been struggling for months to do this but it seems impossible.
I am creating an app using ionic framework which uploads hundreds of photos.
This app is used to generate reports which contains a lot of photos.
The APIs work perfectly on a local server but when I tried using our cloud server much photos are not getting uploaded, the app shows success but when I check the server only few photos are getting uploaded (less than a hundred).
Any ideas about what should I do to make this work?
Thanks.
EDIT:
here's the code for capturing photos cameraservice.js
app.factory('cameraService', function ($rootScope, $q, $http, $location, $timeout, $cordovaCamera,$cordovaFile,$cordovaFileTransfer, apiUrl) {
var settings = {
saveToPhotoAlbum: true,
correctOrientation: true,
quality: 10,
targetWidth: 720,
targetHeight: 720,
};
return {
getPicture: function(){
var d = $q.defer();
let options = {
popoverOptions: CameraPopoverOptions
};
angular.extend(options, settings)
$cordovaCamera.getPicture(options).then(function(imageData) {
let namePath = imageData.substr(0, imageData.lastIndexOf('/') + 1);
let filename = imageData.replace(/^.*[\\\/]/, '');
$cordovaFile.moveFile(namePath, filename, cordova.file.dataDirectory, filename)
.then(function (res) {
d.resolve({ filename: res.name });
}, function (error) {
console.log(error)
});
}, function(err) {
console.log(err)
});
return d.promise;
}
}
})
and here's my uploadservice.js
app.factory('imageUploadService', function ($cordovaFileTransfer) {
var settings = {
fileKey: "file",
chunkedMode: false,
mimeType: "multipart/form-data",
headers : {
Connection:"close"
}
};
return {
upload: function(url, filename, options){
let filePath = cordova.file.dataDirectory + filename;
angular.extend(options, settings);
console.log(url, filePath, options)
return $cordovaFileTransfer.upload(url, filePath, options);
}
}
});
this is how I use the APIs sendservice.js
app.factory('sendService', function ($http, $q, imageUploadService, $timeout, apiUrl) {
return {
photos: function(id, data){
let d = $q.defer();
var url = apiUrl + "/api/senddescription"
var api = apiUrl + "/api/senddetailedphoto";
let q = [];
angular.forEach(data, (item, index)=>{
angular.forEach(item.photos, (i)=>{
let origName = i.image;
var options = {
filename: i.image,
params : {
report_no : id,
label: i.label,
photo_count: index,
photo_label: i.label
},
chunkedMode: false,
headers : {
Connection : "close"
}
};
setTimeout(function(){
q.push(imageUploadService.upload(api, origName, options))
},15000);
})
let data = {
report_no: id,
photo_count: index,
product_description: item.product_description
}
q.push($http.post(url, data));
$q.all(q).then(res=>{
d.resolve(res);
}, err=>{
d.reject(err);
})
})
return d.promise;
}
}
});
These are my APIs
/api/senddescription
public function sendPhotoDescription(Request $request){
$desc = DetailedPhotoDescription::where('report_number',$request->input('report_no'))->where('photo_count',$request->input('photo_count'))->first();
if (!$desc) {
$desc = new DetailedPhotoDescription();
$desc->report_number = $request->input('report_no');
}
$desc->photo_count = $request->input('photo_count');
$desc->product_description = $request->input('product_description');
if ($desc->save()) {
return response()->json([
'message'=>'OK'
],200);
}else{
return response()->json([
'message'=>'Error submitting photo. Please resend the report!'
],500);
}
}
/api/senddetailedphoto
public function sendDetailedPhoto(Request $request){
$file = $request->file('file');
//set a unique file name
$filename = uniqid() . '.' . $file->getClientOriginalExtension();
// //move the files to the correct folder
if ($file->move('images/reports/'. $request->input('report_no').'/detailedPhoto'.'/'.$request->input('photo_count').'/', $filename)) {
$detailed = new DetailedPhoto();
$detailed->report_number = $request->input('report_no');
$detailed->photo_count = $request->input('photo_count');
$detailed->photo_label = $request->input('photo_label');
$detailed->image_data = $filename;
if ($detailed->save()) {
return response()->json([
'message' => 'OK'
],200);
}else{
return response()->json([
'message' => 'Error saving detailed photos. Please resend the report!'
],500);
}
}else{
return response()->json([
'message' => 'Error uploading detailed photos. Please resend the report!'
],500);
}
}