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