Reputation: 23
Upon selecting an Image with the Image Picker I receive a content// url
content://com.android.providers.media.documents/document/image%3A139
When using ImageSource.fromAsset() I am returned in empty object. My current goal is to save that image as a new image so I can send it in a req.
I have also tried Utils.android.getApplicationContext().getContentResolver() with no avail.
public onSelectSingleTap() {
return new Promise((resolve, reject) => {
this.isSingleMode = true;
let context = imagepicker.create({
mode: "single",
mediaType: ImagePickerMediaType.Image,
});
context
.authorize()
.then(() => {
return context.present();
})
.then((selection) => {
if (selection.length > 0) {
ImageSource.fromAsset(selection[0])
.then((imageSource) => {
console.log('Image Source: ', imageSource)
let documentsFolder = knownFolders.documents();
let random = Math.floor(Math.random() * 1000000000);
const filePath: string = path.join(documentsFolder.path, 'image' + random.toString());
let saved = imageSource.saveToFile(filePath, 'jpg')
if (saved) {
const savedFilePath: string = path.join(documentsFolder.path, 'image' + random.toString() + '.jpg');
const file: File = File.fromPath(savedFilePath);
// resolve({file: file, content: selection[0]})
}
})
.catch((err) => console.error("Error loading ImageSource:", err));
}
});
})
}
ImageSource: {"android": {}}
I am not sure if I need to SAVE as a new image or get the actual file path to send it in my request.
Most other answers that I come across are deprecated.
Upvotes: 0
Views: 455
Reputation: 164
I've had to do this in several places in an app I built a few years ago. That app is using @nativescript/[email protected] and @nativescript/[email protected]. I'm thinking it should still work in current versions.
I've implemented a reusable service for triggering the image picker and returning an array of image paths. The array is typed as an array of strings, but I'm not sure what it actually is. (not typing things properly was a huge oversight back then)
import { Injectable } from '@angular/core'
import * as imgPicker from '@nativescript/imagepicker'
import { ImageSource, Folder, knownFolders, path, isAndroid, isIOS } from '@nativescript/core'
@Injectable({
providedIn: 'root'
})
export class ImagePickerService {
private iosFolder: Folder
private iosCounter = 0
constructor() {}
public async chooseImages(maxImages: number, folderName: string): Promise<string[]> {
// init image picker
const options: imgPicker.Options = {
mode: maxImages > 1 ? 'multiple' : 'single',
mediaType: imgPicker.ImagePickerMediaType.Image
}
const context = imgPicker.create(options)
// authorize
await context.authorize()
// get selection
const selection = await context.present()
const imgPaths = []
if (!selection || !selection.length) return imgPaths
// create folder for ios
if (isIOS) {
this.iosFolder = knownFolders.documents().getFolder(folderName)
}
// get the local path for each image and add it to images array
for (const imgAsset of selection) {
if (isIOS) {
const imgSrc = await ImageSource.fromAsset(imgAsset)
// imgAsset.ios is PHAsset and not path - so I am creating my own path
const imgPath = path.join(this.iosFolder.path, `${Date.now()}-${this.iosCounter}.jpg`)
imgSrc.saveToFile(imgPath, 'jpg')
imgPaths.push(imgPath)
this.iosCounter++
} else if (isAndroid) {
imgPaths.push(imgAsset.android.toString())
}
}
return imgPaths
}
public clearFolder(folderName: string): void {
if (this.iosFolder) this.iosFolder.clear()
}
}
Once you have your list of image paths, you can send them to a backend via the background http service:
import { Injectable } from '@angular/core'
import { UtilsService } from './utils.service'
const bgHttp = require('@nativescript/background-http')
const nsLocalStorage = require('@proplugins/nativescript-localstorage')
import { config } from '../config/config'
import { UserError } from '../classes/custom-errors'
@Injectable({
providedIn: 'root'
})
export class FormdataService {
private serverUrl = this.utilsService.serverUrl
constructor(private utilsService: UtilsService) {}
public uploadPhotos(imgPaths, folder, complete, res) {
const jwt = nsLocalStorage.getItem('JWT')
// upload configuration
const session = bgHttp.session('images')
const request = {
url: `${this.serverUrl}/photos/${folder}`,
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream',
Authorization: `Bearer ${jwt}`
},
androidDisplayNotificationProgress: true,
androidAutoClearNotification: true
}
// prepare images for upload
const uploadImgs = imgPaths.map((image) => {
if (image.size > config.fileSizeLimit) throw new UserError('One or more photos are too large.')
return { name: 'images', filename: image, mimeType: 'image/jpeg' }
})
// upload images and data
const task = session.multipartUpload(uploadImgs, request)
// handle events
task.on('complete', (e) => complete(e))
task.on('error', (e) => complete(e))
task.on('responded', (e) => res(e.data))
}
}
Upvotes: 0