• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import fs from '@ohos.file.fs';
17import image from '@ohos.multimedia.image';
18import UserFileManager from '@ohos.filemanagement.userFileManager';
19import dataSharePredicates from '@ohos.data.dataSharePredicates';
20
21import { Log } from '../utils/Log';
22import DateTimeUtil from '../utils/DateTimeUtil';
23import { FunctionCallBack, VideoCallBack } from './CameraService';
24import ThumbnailGetter from './ThumbnailGetter';
25import ReportUtil from '../utils/ReportUtil';
26import { GlobalContext } from '../utils/GlobalContext';
27
28const TAG = '[SaveCameraAsset]:';
29
30export type FetchOpType = {
31  fetchColumns: Array<string>,
32  predicates: dataSharePredicates.DataSharePredicates,
33};
34
35export default class SaveCameraAsset {
36  public videoPrepareFile: UserFileManager.FileAsset;
37  private lastSaveTime = '';
38  private saveIndex = 0;
39  private mUserFileManager: UserFileManager.UserFileManager;
40  private mCameraAlbum: UserFileManager.Album;
41  private photoUri: string = '';
42  private videoUri: string = '';
43
44  constructor() {
45    this.mUserFileManager = UserFileManager.getUserFileMgr(GlobalContext.get().getCameraAbilityContext());
46  }
47
48  public getPhotoUri() {
49    Log.log(`${TAG} getPhotoUri= ${this.photoUri}`);
50    return this.photoUri;
51  }
52
53  public saveImage(mReceiver, thumbWidth: number, thumbHeight: number, thumbnailGetter: ThumbnailGetter,
54    captureCallBack: FunctionCallBack): void {
55    Log.info(`${TAG} saveImage E mediaLibrary.getMediaLibrary media: ${this.mUserFileManager}`);
56    mReceiver.on('imageArrival', async () => {
57      Log.start(Log.UPDATE_PHOTO_THUMBNAIL);
58      Log.log(`${TAG} saveImage ImageReceiver on called`);
59      const buffer = await this.getBufferByReceiver(mReceiver);
60      if (!buffer) {
61        return;
62      }
63      captureCallBack.onCapturePhotoOutput();
64      let pickerUri = GlobalContext.get().getPickerUri();
65      Log.info('uri' + pickerUri)
66      if (pickerUri === '' || pickerUri === undefined) {
67        const fileAsset: UserFileManager.FileAsset = await this.createAsset(UserFileManager.FileType.IMAGE);
68        if (!fileAsset) {
69          Log.info(`${TAG} fileAsset is null`);
70          return;
71        }
72        // @ts-ignore
73        await fileAsset.setPending(true);
74        this.photoUri = fileAsset.uri;
75        Log.info(`${TAG} saveImage photoUri: ${this.photoUri}`);
76        await this.fileAssetOperate(fileAsset, async (fd: number) => {
77          Log.info(`${TAG} saveImage fileio write begin`);
78          try {
79            fs.writeSync(fd, buffer);
80            fs.fsyncSync(fd);
81          } catch (e) {
82            Log.error(`${TAG} fileAssetOperate fileio writeSync ${JSON.stringify(e)}`);
83          }
84          Log.info(`${TAG} saveImage fileio write done`);
85        }).catch(error => {
86          Log.error(`${TAG} saveImage error: ${JSON.stringify(error)}`);
87        });
88        // @ts-ignore
89        await fileAsset.setPending(false);
90        thumbnailGetter.getThumbnailInfo(thumbWidth, thumbHeight, this.photoUri).then(thumbnail => {
91          Log.info(`${TAG} saveImage thumbnailInfo: ${thumbnail}`);
92          captureCallBack.onCaptureSuccess(thumbnail, this.photoUri);
93          Log.end(Log.UPDATE_PHOTO_THUMBNAIL);
94        })
95      } else {
96        try {
97          Log.info(`${TAG} save Picker image`);
98          const file: fs.File = await fs.open(pickerUri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
99          Log.info(`${TAG} open Picker image byteLength` + buffer.byteLength);
100          await fs.write(file.fd, buffer);
101          Log.info(`${TAG} write Picker image byteLength`);
102          captureCallBack.onCaptureSuccess('thumbnail', pickerUri);
103        } catch (e) {
104          captureCallBack.onCaptureSuccess('thumbnail', '');
105          Log.error(`${TAG} Picker fileio writeSync error ${JSON.stringify(e)}`);
106        }
107      }
108    })
109    Log.info(`${TAG} saveImage X`);
110  }
111
112  public async getThumbnailInfo(width: number, height: number): Promise<image.PixelMap | undefined> {
113    Log.info(`${TAG} getThumbnailInfo E width: ${width}, height: ${height}`);
114    Log.info(`${TAG} getThumbnailInfo E`);
115    const fileAsset: UserFileManager.FileAsset = await this.getLastFileAsset();
116    if (!fileAsset) {
117      Log.info(`${TAG} getThumbnailInfo getLastFileAsset error: fileAsset undefined.`);
118      return undefined;
119    }
120    let thumbnailSize: image.Size = {
121      width: width, height: height
122    };
123    let thumbnailPixelMap: image.PixelMap = <image.PixelMap> await fileAsset.getThumbnail(thumbnailSize).catch(e => {
124      Log.error(`${TAG} getThumbnail error: ${JSON.stringify(e)}`);
125    });
126    if (thumbnailPixelMap === undefined) {
127      Log.info(`${TAG} getThumbnail fail`);
128    } else {
129      Log.info(`${TAG} getThumbnail successful ` + thumbnailPixelMap);
130    }
131    Log.info(`${TAG} getThumbnailInfo X`);
132    return thumbnailPixelMap;
133  }
134
135  public async getLastFileAsset(): Promise<UserFileManager.FileAsset> {
136    let predicates = new dataSharePredicates.DataSharePredicates();
137    predicates.orderByDesc('date_added').limit(1, 0);
138    let fetchOptions: FetchOpType = {
139      fetchColumns: ['date_added'],
140      predicates: predicates,
141    };
142    Log.info(`${TAG} getLastFileAsset fetchOp: ${JSON.stringify(fetchOptions)}`);
143    return this.getFileAssetByFetchOp(fetchOptions);
144  }
145
146  public async getFileAssetByFetchOp(fetchOp: FetchOpType): Promise<UserFileManager.FileAsset> {
147    let fetchResult;
148    let fileAsset;
149    try {
150      await this.createCameraAlbum();
151      fetchResult = await this.mCameraAlbum?.getPhotoAssets(fetchOp);
152      if (fetchResult !== undefined) {
153        Log.info(`${TAG} getFileAssetByFetchOp fetchResult success`);
154        fileAsset = await fetchResult.getLastObject();
155        if (fileAsset !== undefined) {
156          Log.info(`${TAG} getFileAssetByFetchOp fileAsset.displayName : ` + fileAsset.displayName);
157        }
158      }
159    } catch (e) {
160      Log.error(`${TAG} getFileAssetByFetchOp get fileAsset error: ${JSON.stringify(e)}`);
161    } finally {
162      fetchResult.close();
163    }
164    return fileAsset;
165  }
166
167  public async createAsset(type: UserFileManager.FileType): Promise<UserFileManager.FileAsset> {
168    const displayName = this.getDisplayName(type);
169    Log.info(`${TAG} createAsset  displayName: ${displayName}`);
170    let option: UserFileManager.PhotoCreateOptions = {
171      subType: UserFileManager.PhotoSubType.CAMERA,
172    };
173    let fileAsset: UserFileManager.FileAsset;
174    try {
175      fileAsset = await this.mUserFileManager.createPhotoAsset(displayName, option);
176      if (fileAsset !== undefined) {
177        Log.info(`${TAG} createPhotoAsset successfully displayName` + fileAsset.displayName);
178      } else {
179        Log.error(`${TAG} createPhotoAsset failed, fileAsset is undefined `);
180      }
181    } catch (e) {
182      Log.error(`${TAG} createPhotoAsset failed, error: ${JSON.stringify(e)}}`);
183    }
184    return fileAsset;
185  }
186
187  public async createVideoFd(captureCallBack: VideoCallBack): Promise<number | undefined> {
188    Log.info(`${TAG} createVideoFd E`);
189    const fileAsset: UserFileManager.FileAsset = await this.createAsset(UserFileManager.FileType.VIDEO);
190    if (!fileAsset) {
191      Log.error(`${TAG} createVideoFd mediaLibrary createAsset error: fileAsset undefined.`);
192      return undefined;
193    }
194    let fdNumber: number = 0;
195    try {
196      this.videoPrepareFile = fileAsset;
197      this.videoUri = fileAsset.uri;
198      captureCallBack.videoUri(this.videoUri);
199      Log.info(`${TAG} SaveCameraAsset getLastObject.uri: ${JSON.stringify(fileAsset.uri)}`);
200      fdNumber = await fileAsset.open('Rw');
201    } catch (err) {
202      Log.error(`${TAG} createVideoFd err: ${err}`);
203    }
204    Log.info(`${TAG} createVideoFd X`);
205    return fdNumber;
206  }
207
208  private async createCameraAlbum(): Promise<void> {
209    Log.log(`${TAG} createCameraAlbum E`);
210    if (!this.mCameraAlbum) {
211      let fetchResult =
212        await this.mUserFileManager?.getAlbums(UserFileManager.AlbumType.SYSTEM, UserFileManager.AlbumSubType.CAMERA);
213      this.mCameraAlbum = await fetchResult?.getFirstObject();
214      Log.log(`${TAG} createCameraAlbum albumUri: ${JSON.stringify(this.mCameraAlbum.albumUri)}`);
215    }
216    Log.log(`${TAG} createCameraAlbum X`);
217  }
218
219  private async fileAssetOperate(fileAsset: UserFileManager.FileAsset, operate: (fd: number) => void): Promise<void> {
220    const fd: number = <number> await fileAsset.open('Rw').catch(error => {
221      Log.error(`${TAG} fileAsset open error: ${JSON.stringify(error)}`);
222      return;
223    });
224    try {
225      await operate.apply(this, [fd]);
226    } catch (error) {
227      Log.error(`${TAG} fileAsset operate error: ${JSON.stringify(error)}`);
228    } finally {
229      Log.info(`${TAG} fileAsset operate close`);
230      await fileAsset.close(fd).catch(error => {
231        ReportUtil.write(ReportUtil.SAVE_FAIL);
232        Log.error(`${TAG} fileAsset open error: ${JSON.stringify(error)}`);
233      });
234    }
235  }
236
237  private async getBufferByReceiver(mReceiver: image.ImageReceiver): Promise<ArrayBuffer | undefined> {
238    const imageInfo: image.Image = <image.Image> await mReceiver.readNextImage().catch(error => {
239      Log.error(`${TAG} saveImage receiver read next image error: ${JSON.stringify(error)}`);
240      return undefined;
241    });
242    try {
243      const img: image.Component = await imageInfo.getComponent(image.ComponentType.JPEG);
244      if (img && img.byteBuffer) {
245        const buffer: ArrayBuffer = img.byteBuffer.slice(0, img.byteBuffer.byteLength);
246        Log.info(`${TAG} saveImage getComponent img.byteBuffer.byteLength = ${buffer.byteLength}`);
247        return buffer;
248      } else {
249        Log.error(`${TAG} saveImage getComponent img is undefined error`);
250      }
251    } catch (error) {
252      Log.error(`${TAG} saveImage get buffer from receiver error: ${JSON.stringify(error)}`);
253    } finally {
254      if (imageInfo) {
255        await imageInfo.release().catch(error => {
256          Log.error(`${TAG} image info release error: ${JSON.stringify(error)}`);
257        });
258      }
259    }
260    return undefined;
261  }
262
263  private getDisplayName(type: UserFileManager.FileType): string {
264    const mDateTimeUtil: DateTimeUtil = new DateTimeUtil();
265    const mData: string = mDateTimeUtil.getDate();
266    const mTime: string = mDateTimeUtil.getTime();
267    if (type === UserFileManager.FileType.IMAGE) {
268      return `${this.checkName(`IMG_${mData}_${mTime}`)}.jpg`;
269    } else {
270      return `${this.checkName(`VID_${mData}_${mTime}`)}.mp4`;
271    }
272  }
273
274  private checkName(name: string): string {
275    if (this.lastSaveTime === name) {
276      this.saveIndex++;
277      return `${name}_${this.saveIndex}`;
278    }
279    this.lastSaveTime = name;
280    this.saveIndex = 0;
281    return name;
282  }
283}