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 { EditStack } from './utils/EditStack'; 17import { ImageFilterBase } from './base/ImageFilterBase'; 18import { PixelMapWrapper } from './base/PixelMapWrapper'; 19 20enum CacheDirection { 21 BACKWARD, 22 FORWARD 23} 24 25export class ImageFilterStack extends EditStack<ImageFilterBase> { 26 private static readonly CACHE_MAX: number = 20; 27 private cacheStart: number = 0; 28 private cacheEnd: number = 0; 29 private origin: PixelMapWrapper = undefined; 30 31 apply(pixelMap: PixelMapWrapper): PixelMapWrapper { 32 super.executeEach((filter: ImageFilterBase) => { 33 pixelMap = filter.render(pixelMap); 34 }, super.getLength()); 35 return pixelMap; 36 } 37 38 push(filter: ImageFilterBase) { 39 super.push(filter); 40 this.updateCache(CacheDirection.FORWARD); 41 } 42 43 releaseAll() { 44 super.executeEach((filter: ImageFilterBase) => { 45 filter && filter.release(); 46 }, super.getLength()); 47 super.reset(); 48 this.cacheStart = 0; 49 this.cacheEnd = 0; 50 } 51 52 setOriginPixelMap(origin: PixelMapWrapper) { 53 this.origin = origin; 54 } 55 56 doRedo(): PixelMapWrapper { 57 let position: number = super.redo(); 58 this.updateCache(CacheDirection.FORWARD); 59 return super.at(position).getCache(); 60 } 61 62 doUndo(): PixelMapWrapper { 63 let position: number = super.undo(); 64 this.updateCache(CacheDirection.BACKWARD); 65 return super.at(position).getCache(); 66 } 67 68 private shouldReleaseCache(): boolean { 69 return (this.cacheEnd - this.cacheStart >= ImageFilterStack.CACHE_MAX); 70 } 71 72 private updateCache(direction: CacheDirection) { 73 let position = super.getPosition(); 74 let filter = super.at(position); 75 if (direction == CacheDirection.BACKWARD) { 76 if (!filter.isCached()) { 77 let pixelMap = this.origin; 78 filter.setCache(this.apply(pixelMap)); 79 this.cacheStart--; 80 } 81 82 if (this.shouldReleaseCache()) { 83 super.at(this.cacheEnd).release(); 84 this.cacheEnd--; 85 } 86 } else if (direction == CacheDirection.FORWARD) { 87 if (!filter.isCached()) { 88 let pixelMap = (position > 0) ? super.at(position - 1).getCache() : this.origin; 89 filter.setCache(filter.render(pixelMap)); 90 this.cacheEnd++; 91 } 92 93 if (this.shouldReleaseCache()) { 94 super.at(this.cacheStart).release(); 95 this.cacheStart++; 96 } 97 } 98 } 99}