1/* 2 * Copyright (c) 2022 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 { Constants } from '../../common/model/common/Constants'; 17import { PhotoEditCrop } from './crop/PhotoEditCrop'; 18import { PhotoEditBase } from './base/PhotoEditBase'; 19import { PhotoEditMode } from './base/PhotoEditType'; 20import { PixelMapWrapper } from './base/PixelMapWrapper'; 21import { ImageFilterStack } from './ImageFilterStack'; 22import { MediaDataItem } from '@ohos/base/src/main/ets/data/MediaDataItem'; 23import { Loader } from './Loader'; 24import { Save } from './Save'; 25import { Log } from '@ohos/base/src/main/ets/utils/Log'; 26 27export class PhotoEditorManager { 28 private TAG: string = 'PhotoEditorManager'; 29 private currentMode: PhotoEditMode = PhotoEditMode.EDIT_MODE_MAIN; 30 private origin: PixelMapWrapper = undefined; 31 private item: MediaDataItem = undefined; 32 private editors: Array<PhotoEditBase> = undefined; 33 private historyManager: ImageFilterStack = undefined; 34 isSaving: boolean = false; 35 36 private constructor() { 37 this.historyManager = new ImageFilterStack(); 38 this.editors = []; 39 this.editors[PhotoEditMode.EDIT_MODE_CROP] = new PhotoEditCrop(); 40 } 41 42 static getInstance(): PhotoEditorManager { 43 if (AppStorage.Get(Constants.PHOTO_EDITOR_MANAGER) == null) { 44 AppStorage.SetOrCreate(Constants.PHOTO_EDITOR_MANAGER, new PhotoEditorManager()); 45 } 46 return AppStorage.Get(Constants.PHOTO_EDITOR_MANAGER); 47 } 48 49 initialize(item: MediaDataItem, mode: PhotoEditMode, errCallback?: any) { 50 Log.info(this.TAG, `initialize mode[${mode}]`); 51 this.item = item; 52 Loader.loadPixelMapWrapper(item, true).then((pixelMap) => { 53 if (pixelMap) { 54 this.origin = pixelMap; 55 this.historyManager.setOriginPixelMap(this.origin); 56 this.switchMode(mode); 57 } else { 58 Log.error(this.TAG, 'initialize loadPixelMapWrapper failed'); 59 errCallback && errCallback(); 60 } 61 }) 62 } 63 64 clear() { 65 Log.debug(this.TAG, 'clear'); 66 this.editors[this.currentMode] && this.editors[this.currentMode].exit(); 67 this.item = undefined; 68 this.origin && this.origin.release(); 69 this.origin = undefined; 70 this.historyManager.setOriginPixelMap(undefined); 71 this.historyManager.releaseAll(); 72 this.currentMode = PhotoEditMode.EDIT_MODE_MAIN; 73 } 74 75 getPhotoEditBaseInstance(mode: PhotoEditMode): PhotoEditBase { 76 return this.editors[mode]; 77 } 78 79 getLastPixelMap(): PixelMapWrapper { 80 let position = this.historyManager.getPosition(); 81 Log.debug(this.TAG, `getLastPixelMap position = ${position}`); 82 if (position < 0) { 83 return this.origin; 84 } else { 85 return this.historyManager.at(position).getCache(); 86 } 87 } 88 89 switchMode(mode: PhotoEditMode): PhotoEditMode { 90 Log.info(this.TAG, `switchMode: currentMode[${this.currentMode}] mode[${mode}]`); 91 if (this.currentMode == mode) { 92 return mode; 93 } 94 95 // exit current edit mode 96 if (this.editors[this.currentMode] != undefined) { 97 const filter = this.editors[this.currentMode].exit(); 98 if (filter != undefined) { 99 // save cache 100 if (!filter.isCached()) { 101 const prePixelMap = this.getLastPixelMap(); 102 filter.setCache(filter.render(prePixelMap)); 103 } 104 this.historyManager.push(filter); 105 } 106 } 107 108 // entry next edit mode 109 let input = this.getLastPixelMap(); 110 if (input && this.editors[mode] != undefined) { 111 this.editors[mode].entry(input); 112 // update current edit mode 113 this.currentMode = mode; 114 } 115 return this.currentMode; 116 } 117 118 isRedoValid(): boolean { 119 return this.historyManager.isRedoValid(); 120 } 121 122 isUndoValid(): boolean { 123 return this.historyManager.isUndoValid(); 124 } 125 126 redo(): boolean { 127 if (this.isRedoValid()) { 128 let newPixel = this.historyManager.doRedo(); 129 this.editors[this.currentMode].entry(newPixel); 130 return true; 131 } 132 133 return false; 134 } 135 136 undo(): boolean { 137 if (this.isUndoValid()) { 138 let newPixel = this.historyManager.doUndo(); 139 this.editors[this.currentMode].entry(newPixel); 140 return true; 141 } 142 143 return false; 144 } 145 146 async save(isReplace: boolean): Promise<number> { 147 Log.info(this.TAG, `save enter isReplace = ${isReplace}`); 148 this.isSaving = true; 149 const filter = this.editors[this.currentMode].exit(); 150 if (filter != undefined) { 151 this.historyManager.push(filter); 152 } 153 return await Save.save(this.item, this.historyManager, isReplace);; 154 } 155}