如何在照片编辑应用程序中实现“撤销”功能是最佳方法?

5

显然,存储一系列变更历史的数组需要大量内存...虽然我的应用程序可以这样工作,但似乎有更聪明的方法来处理它。

ArrayList<Photo> photoHistory = new ArrayList<>();
photoHistory.add(originalPhoto);
photoHistory.add(change1);
photoHistory.add(change2);

// bad implementation - lots of memory

也许只需存储一个原始和当前视图模型,并记录使用的方法/过滤器?然后,当用户点击“撤消”时,它会获取所做更改的总数并再次运行所有更改减去一个?这似乎也非常低效。
我想我只是在寻求有关如何实现软件应用程序的通用“撤消”功能的建议。

3
命令模式是一种行为型设计模式,它通过将请求封装成对象来解耦发送者和接收者。这个模式可以用于撤销、重做、队列等操作。命令对象包含了执行操作所需的所有信息,例如方法名称、参数和接收者。由于命令对象拥有执行方法,因此可以轻松地实现撤销和重做功能。此外,命令模式还可以组合多个命令对象,以实现更复杂的操作。 - Andy Turner
1
计算更改后和更改前之间的差异,即用于撤消更改的新版本的差异。历史记录是这些差异。对于完整的过滤器,可能是完整的图片,但对于诸如红眼过滤器之类的东西,仅涉及眼睛,即要小得多。 - Andreas
@AndyTurner提到的命令模式通常是遵循的好模式,如果您只想拥有一个通用的撤销功能。然而,在图形应用程序场景中,使它相当复杂的是撤销方法本身(需要添加到每个命令中)。在命令中实现撤销可能并不容易。正如您所提到的-您可以保留已执行命令的列表,并在撤销最后一个命令时重新应用以前的命令。但是,这可能效率低下。因此,总的来说-在一般情况下,命令模式是可以的,但在图形编辑器中可能不是最佳选择。 - Mike Wojtyna
1个回答

6
这是GIMP实现撤销的提示:
GIMP的撤销实现相当复杂。许多操作需要很少的撤销内存(例如,改变图层的可见性),因此您可以在它们从撤销历史中退出之前执行长序列的操作。有些操作,例如改变图层的可见性,被压缩,所以连续几次执行它们只会在撤销历史中产生一个点。然而,还有其他可能消耗大量撤销内存的操作。大多数滤镜都是由插件实现的,因此GIMP核心没有有效的方法知道发生了什么变化。因此,除了在操作之前和之后记忆受影响图层的全部内容外,没有其他方法可以实现撤销。在撤销历史中只能执行少数这样的操作。 来源

为了尽可能地优化,您需要根据正在撤消的操作执行不同的操作。 显示或隐藏图层可以用极少量的空间表示,但过滤整个图像可能需要存储另一个完整图像的副本。 但是,如果您只过滤图像的一部分(或在图像的一小部分中绘制),则可能只需要存储该图像的那一部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接