• 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, { Filter, ConflictFiles } 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 EventLog from '../utils/EventLog';
26import { GlobalContext } from '../utils/GlobalContext';
27
28const TAG = '[SaveCameraAsset]:';
29
30export type FetchOpType = {
31  fetchColumns: Array<string>,
32  predicates: dataSharePredicates.DataSharePredicates,
33};
34
35type FileMessageType = {
36  fileId: string;
37  bufferLength: number;
38};
39
40export default class SaveCameraAsset {
41  private lastSaveTime = '';
42  private saveIndex = 0;
43  private mUserFileManager: UserFileManager.UserFileManager;
44  public videoPrepareFile: UserFileManager.FileAsset;
45  private lastFileMessage: FileMessageType = {
46    fileId: '', bufferLength: 0
47  };
48  private mCameraAlbum: UserFileManager.Album;
49  private photoUri: string = '';
50  private videoUri: string = '';
51
52  constructor() {
53    this.mUserFileManager = UserFileManager.getUserFileMgr(GlobalContext.get().getCameraAbilityContext());
54  }
55
56  public getPhotoUri() {
57    Log.log(`${TAG} getPhotoUri= ${this.photoUri}`);
58    return this.photoUri;
59  }
60
61  private async createCameraAlbum(): Promise<void> {
62    Log.log(`${TAG} createCameraAlbum E`);
63    if (!this.mCameraAlbum) {
64      let fetchResult = await this.mUserFileManager?.getAlbums(UserFileManager.AlbumType.SYSTEM, UserFileManager.AlbumSubType.CAMERA);
65      this.mCameraAlbum = await fetchResult?.getFirstObject();
66      Log.log(`${TAG} createCameraAlbum albumUri: ${JSON.stringify(this.mCameraAlbum.albumUri)}`);
67    }
68    Log.log(`${TAG} createCameraAlbum X`);
69  }
70
71  public saveImage(mReceiver, thumbWidth: number, thumbHeight: number, thumbnailGetter: ThumbnailGetter, captureCallBack: FunctionCallBack): void {
72    Log.info(`${TAG} saveImage E mediaLibrary.getMediaLibrary media: ${this.mUserFileManager}`);
73    mReceiver.on('imageArrival', async () => {
74      Log.start(Log.UPDATE_PHOTO_THUMBNAIL);
75      Log.log(`${TAG} saveImage ImageReceiver on called`);
76      const buffer = await this.getBufferByReceiver(mReceiver);
77      if (!buffer) {
78        return;
79      }
80      captureCallBack.onCapturePhotoOutput();
81
82      const fileAsset: UserFileManager.FileAsset = await this.createAsset(UserFileManager.FileType.IMAGE);
83      if (!fileAsset) {
84        Log.info(`${TAG} fileAsset is null`);
85        return;
86      }
87      // @ts-ignore
88      await fileAsset.setPending(true);
89      this.lastFileMessage = {
90        fileId: fileAsset.uri, bufferLength: buffer.byteLength
91      };
92      this.photoUri = fileAsset.uri;
93      Log.info(`${TAG} saveImage photoUri: ${this.photoUri}`);
94      await this.fileAssetOperate(fileAsset, async (fd: number) => {
95        Log.info(`${TAG} saveImage fileio write begin`);
96        try {
97          fs.writeSync(fd, buffer);
98          fs.fsyncSync(fd);
99        } catch (e) {
100          Log.error(`${TAG} fileAssetOperate fileio writeSync ${JSON.stringify(e)}`);
101        }
102        Log.info(`${TAG} saveImage fileio write done`);
103      }).catch(error => {
104        Log.error(`${TAG} saveImage error: ${JSON.stringify(error)}`);
105      });
106      // @ts-ignore
107      await fileAsset.setPending(false);
108      thumbnailGetter.getThumbnailInfo(thumbWidth, thumbHeight, this.photoUri).then(thumbnail => {
109        Log.info(`${TAG} saveImage thumbnailInfo: ${thumbnail}`);
110        captureCallBack.onCaptureSuccess(thumbnail, this.photoUri);
111        Log.end(Log.UPDATE_PHOTO_THUMBNAIL);
112      })
113    })
114    Log.info(`${TAG} saveImage X`);
115  }
116
117  public async getThumbnailInfo(width: number, height: number): Promise<image.PixelMap | undefined> {
118    Log.info(`${TAG} getThumbnailInfo E width: ${width}, height: ${height}`);
119    Log.info(`${TAG} getThumbnailInfo E`);
120    const fileAsset: UserFileManager.FileAsset = await this.getLastFileAsset();
121    if (!fileAsset) {
122      Log.info(`${TAG} getThumbnailInfo getLastFileAsset error: fileAsset undefined.`);
123      return undefined;
124    }
125    let thumbnailSize: image.Size = {
126      width: width, height: height
127    };
128    let thumbnailPixelMap: image.PixelMap = <image.PixelMap> await fileAsset.getThumbnail(thumbnailSize).catch(e => {
129      Log.error(`${TAG} getThumbnail error: ${JSON.stringify(e)}`);
130    });
131    if (thumbnailPixelMap === undefined) {
132      Log.info(`${TAG} getThumbnail fail`);
133    } else {
134      Log.info(`${TAG} getThumbnail successful ` + thumbnailPixelMap);
135    }
136    Log.info(`${TAG} getThumbnailInfo X`);
137    return thumbnailPixelMap;
138  }
139
140  public async getLastFileAsset(): Promise<UserFileManager.FileAsset> {
141    let predicates = new dataSharePredicates.DataSharePredicates();
142    predicates.orderByDesc('date_added').limit(1, 0);
143    let fetchOptions: FetchOpType = {
144      fetchColumns: ['date_added'],
145      predicates: predicates,
146    };
147    Log.info(`${TAG} getLastFileAsset fetchOp: ${JSON.stringify(fetchOptions)}`);
148    return this.getFileAssetByFetchOp(fetchOptions);
149  }
150
151  public async getFileAssetByFetchOp(fetchOp: FetchOpType): Promise<UserFileManager.FileAsset> {
152    let fetchResult;
153    let fileAsset;
154    try {
155      await this.createCameraAlbum();
156      fetchResult = await this.mCameraAlbum?.getPhotoAssets(fetchOp);
157      if (fetchResult !== undefined) {
158        Log.info(`${TAG} getFileAssetByFetchOp fetchResult success`);
159        fileAsset = await fetchResult.getLastObject();
160        if (fileAsset !== undefined) {
161          Log.info(`${TAG} getFileAssetByFetchOp fileAsset.displayName : ` + fileAsset.displayName);
162        }
163      }
164    } catch (e) {
165      Log.error(`${TAG} getFileAssetByFetchOp get fileAsset error: ${JSON.stringify(e)}`);
166    } finally {
167      fetchResult.close();
168    }
169    return fileAsset;
170  }
171
172  private async fileAssetOperate(fileAsset: UserFileManager.FileAsset, operate: (fd: number) => void): Promise<void> {
173    const fd: number = <number> await fileAsset.open('Rw').catch(error => {
174      Log.error(`${TAG} fileAsset open error: ${JSON.stringify(error)}`);
175      return;
176    });
177    try {
178      await operate.apply(this, [fd]);
179    } catch (error) {
180      Log.error(`${TAG} fileAsset operate error: ${JSON.stringify(error)}`);
181    } finally {
182      Log.info(`${TAG} fileAsset operate close`);
183      await fileAsset.close(fd).catch(error => {
184        EventLog.write(EventLog.SAVE_FAIL);
185        Log.error(`${TAG} fileAsset open error: ${JSON.stringify(error)}`);
186      });
187    }
188  }
189
190  private async getBufferByReceiver(mReceiver: image.ImageReceiver): Promise<ArrayBuffer | undefined> {
191    const imageInfo: image.Image = <image.Image> await mReceiver.readNextImage().catch(error => {
192      Log.error(`${TAG} saveImage receiver read next image error: ${JSON.stringify(error)}`);
193      return undefined;
194    });
195    try {
196      const img: image.Component = await imageInfo.getComponent(image.ComponentType.JPEG);
197      if (img && img.byteBuffer) {
198        const buffer: ArrayBuffer = img.byteBuffer.slice(0, img.byteBuffer.byteLength);
199        Log.info(`${TAG} saveImage getComponent img.byteBuffer.byteLength = ${buffer.byteLength}`);
200        return buffer;
201      } else {
202        Log.error(`${TAG} saveImage getComponent img is undefined error`);
203      }
204    } catch (error) {
205      Log.error(`${TAG} saveImage get buffer from receiver error: ${JSON.stringify(error)}`);
206    } finally {
207      if (imageInfo) {
208        await imageInfo.release().catch(error => {
209          Log.error(`${TAG} image info release error: ${JSON.stringify(error)}`);
210        });
211      }
212    }
213    return undefined;
214  }
215
216  public async createAsset(type: UserFileManager.FileType): Promise<UserFileManager.FileAsset> {
217    const displayName = this.getDisplayName(type);
218    Log.info(`${TAG} createAsset  displayName: ${displayName}`);
219    let option: UserFileManager.PhotoCreateOptions = {
220      subType: UserFileManager.PhotoSubType.CAMERA,
221    };
222    let fileAsset: UserFileManager.FileAsset;
223    try {
224      fileAsset = await this.mUserFileManager.createPhotoAsset(displayName, option);
225      if (fileAsset !== undefined) {
226        Log.info(`${TAG} createPhotoAsset successfully displayName` + fileAsset.displayName);
227      } else {
228        Log.error(`${TAG} createPhotoAsset failed, fileAsset is undefined `);
229      }
230    } catch (e) {
231      Log.error(`${TAG} createPhotoAsset failed, error: ${JSON.stringify(e)}}`);
232    }
233    return fileAsset;
234  }
235
236  private getDisplayName(type: UserFileManager.FileType): string {
237    const mDateTimeUtil: DateTimeUtil = new DateTimeUtil();
238    const mData: string = mDateTimeUtil.getDate();
239    const mTime: string = mDateTimeUtil.getTime();
240    if (type === UserFileManager.FileType.IMAGE) {
241      return `${this.checkName(`IMG_${mData}_${mTime}`)}.jpg`;
242    } else {
243      return `${this.checkName(`VID_${mData}_${mTime}`)}.mp4`;
244    }
245  }
246
247  public async createVideoFd(captureCallBack: VideoCallBack): Promise<number | undefined> {
248    Log.info(`${TAG} createVideoFd E`);
249    const fileAsset: UserFileManager.FileAsset = await this.createAsset(UserFileManager.FileType.VIDEO);
250    if (!fileAsset) {
251      Log.error(`${TAG} createVideoFd mediaLibrary createAsset error: fileAsset undefined.`);
252      return undefined;
253    }
254    let fdNumber: number = 0;
255    try {
256      this.videoPrepareFile = fileAsset;
257      this.videoUri = fileAsset.uri;
258      captureCallBack.videoUri(this.videoUri);
259      Log.info(`${TAG} SaveCameraAsset getLastObject.uri: ${JSON.stringify(fileAsset.uri)}`);
260      fdNumber = await fileAsset.open('Rw');
261    } catch (err) {
262      Log.error(`${TAG} createVideoFd err: ${err}`);
263    }
264    Log.info(`${TAG} createVideoFd X`);
265    return fdNumber;
266  }
267
268  private checkName(name: string): string {
269    if (this.lastSaveTime === name) {
270      this.saveIndex++;
271      return `${name}_${this.saveIndex}`;
272    }
273    this.lastSaveTime = name;
274    this.saveIndex = 0;
275    return name;
276  }
277}