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