import axios, { AxiosProgressEvent } from '@ohos/axios'; import { fileIo, fileUri } from '@kit.CoreFileKit'; import { camera, cameraPicker as picker } from '@kit.CameraKit'; import { util } from '@kit.ArkTS'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; import { image } from '@kit.ImageKit'; import { BusinessError } from '@kit.BasicServicesKit'; import { ContextHelper, ResultCallBack, YTLog } from '../../../../Index'; import { componentSnapshot } from '@kit.ArkUI'; import fs from '@ohos.file.fs'; /** * @method cashPhotos 传入需要下载得url数组并下载文件,通过回调函数返回对应cashPaths数组 * @method takePicture 拍照获取图片 * @method selectImage 从相册选择图片 * @method saveByShowAssetsCreationDialog 通过ShowAssetsCreationDialog保存文件(弹窗) * @method getPhotoFileBuffer 将缓存的图片转化为流 * @method saveImgToAssets 直接保存图片至相册 需要权限 * @method saveScreenshotToAlbum 截屏保存图片 * @method manualCompression压缩图片 */ export class YTPhotoHelper { private cashPaths: string[] = [] private currentIndex: number = 0 //传入需要下载得url数组并下载文件,通过回调函数返回对应cashPaths数组 async cashPhotos(urls: string[], finishDownLoad: (cashPaths: string[]) => void, cashPhotoType: string = '.jpg') { let filePath = ContextHelper.context.cacheDir + '/' + util.generateRandomUUID() + cashPhotoType // Download the file. If the file already exists, delete the existing one first. try { fileIo.accessSync(filePath); fileIo.unlinkSync(filePath); } catch (err) { YTLog.error(err) } await axios({ url: urls[this.currentIndex], method: 'get', context: ContextHelper.context, filePath: filePath, onDownloadProgress: (progressEvent: AxiosProgressEvent): void => { YTLog.info("progress: " + progressEvent && progressEvent.loaded && progressEvent.total ? Math.ceil(progressEvent.loaded / progressEvent.total * 100) : 0) } }) this.currentIndex++ this.cashPaths.unshift(filePath) if (this.currentIndex < urls.length) { this.cashPhotos(urls, finishDownLoad, cashPhotoType) } else { finishDownLoad(this.cashPaths) } } //拍照获取图片 async takePicture() { let pathDir = ContextHelper.context.filesDir; let fileName = `${new Date().getTime()}` let filePath = pathDir + `/${fileName}.png` fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE); let uri = fileUri.getUriFromPath(filePath); let pickerProfile: picker.PickerProfile = { cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK, saveUri: uri }; let result: picker.PickerResult = await picker.pick(ContextHelper.context, [picker.PickerMediaType.PHOTO], //(如果需要录像可以添加) picker.PickerMediaType.VIDEO pickerProfile); if (!result.resultUri) { return Promise.reject('用户未拍照') } return filePath } //从相册选择图片 selectImage(success: (fullPath: string) => void, maxNumber: number = 1) { const option = new photoAccessHelper.PhotoSelectOptions() option.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE option.maxSelectNumber = maxNumber const picker = new photoAccessHelper.PhotoViewPicker() picker.select(option) .then(res => { const photoName = util.generateRandomUUID() const photoType = '.' + res.photoUris[0].split('.').pop() const fullPath = ContextHelper.context.cacheDir + '/' + photoName + photoType const photo = fileIo.openSync(res.photoUris[0]) try { fileIo.copyFile(photo.fd, fullPath) .then(() => { YTLog.info(fullPath) success(fullPath) }) } catch (err) { YTLog.error(err) } }) } // 保存截图到相册的方法 async saveScreenshotToAlbum(activityId: string, result?: ResultCallBack, clearCashPaths: boolean = false) { try { // 获取组件截图 const pixelMap = componentSnapshot.getSync(activityId) if (!pixelMap) { console.error('Failed to get screenshot') return } // 创建临时文件路径 const tempDir = ContextHelper.context.tempDir const filePath = tempDir + '/screenshot_' + util.generateRandomUUID() + '.jpg' // 将PixelMap打包为JPEG格式 const imagePacker = image.createImagePacker() const packOptions: image.PackingOption = { format: 'image/jpeg', quality: 90 } const data = await imagePacker.packing(pixelMap, packOptions) // 写入文件 const file = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE) fs.writeSync(file.fd, data) fs.closeSync(file) this.saveByShowAssetsCreationDialog([filePath], result, clearCashPaths) } catch (error) { console.error('Error saving screenshot: ' + JSON.stringify(error)) } } //传入需要保存得cashPaths数组,并通过ShowAssetsCreationDialog保存文件 async saveByShowAssetsCreationDialog( cashPaths: string[], result?: ResultCallBack, clearCashPaths: boolean = false) { const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(ContextHelper.context); const uris = cashPaths.map(item => fileUri.getUriFromPath(item)) try { // 指定待保存照片的创建选项,包括文件后缀和照片类型,标题和照片子类型可选。 const photoCreationConfigs = uris.map(() => { const photoCreationConfig: photoAccessHelper.PhotoCreationConfig = { fileNameExtension: 'jpg', photoType: photoAccessHelper.PhotoType.IMAGE, } return photoCreationConfig }) // 基于弹窗授权的方式获取媒体库的目标uri。 let desFileUris: Array = await phAccessHelper.showAssetsCreationDialog(uris, photoCreationConfigs); let index = 0 while (index < uris.length) { //通过该uri打开图片 let file = await fileIo.open(desFileUris[index], fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE) //获取流 const buffer = await this.getPhotoFileBuffer(cashPaths[index]) //通过流写入相册 await fileIo.write(file.fd, buffer) //关流 await fileIo.close(file) index++ } result?.() if (clearCashPaths) { cashPaths.forEach(cashPath => fileIo.unlink(cashPath)) } } catch (err) { YTLog.error(err) result?.(undefined, err) } } //传入图片地址,转化为流 async getPhotoFileBuffer(filePath: string): Promise { try { const imageSource = image.createImageSource(filePath) let imagePackerApi = image.createImagePacker(); let buffer = await imagePackerApi.packing(imageSource, { quality: 100, format: 'image/jpeg' }) return buffer } catch (err) { let error: BusinessError = err as BusinessError; console.error(`read file failed, errCode:${error.code}, errMessage:${error.message}`); return Promise.reject(err) } } //须先申请权限ohos.permission.WRITE_IMAGEVIDEO 保存图片至相册 async saveImgToAssets(cashPaths: string[]) { try { let index = 0; while (index < cashPaths.length) { //获取当前上下文 //通过accessHelper模块获取accessHelper对象 let accessHelper = photoAccessHelper.getPhotoAccessHelper(ContextHelper.context) //指定待创建的文件类型、后缀和创建选项,创建图片或视频资源 返回创建的图片和视频的uri let uri = await accessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, 'jpg') //通过该uri打开图片 let file = await fileIo.open(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE) //获取流 const buffer = await this.getPhotoFileBuffer(cashPaths[index]) //通过流写入相册 await fileIo.write(file.fd, buffer) //关流 await fileIo.close(file) index++ } } catch (e) { YTLog.error(e) } } /** * 手动压缩图片 * @param filePath 图片路径 * @param result 回调 * @param quality 压缩质量 */ async manualCompression(filePath: string, result: (imagePath: string) => void, quality: number = 20) { const imageSourceApi: image.ImageSource = image.createImageSource(filePath); const packOpts: image.PackingOption = { format: "image/jpeg", quality }; const imagePackerApi = image.createImagePacker() const buffer = await imagePackerApi.packing(imageSourceApi, packOpts) const imagePath = ContextHelper.context.cacheDir + '/' + util.generateRandomUUID() + '.jpeg' const file = fileIo.openSync(imagePath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE) fileIo.writeSync(file.fd, buffer) fileIo.closeSync(file) fileIo.unlinkSync(filePath) result(imagePath) return imagePath } }