这个问题可能适用于一般的绘图系统。我想知道如何在 PS 中实现撤消功能。程序是否在每次操作之前拍摄画布的快照?如果是这样,这不会导致巨大的内存需求吗?我已经研究了命令模式,但我不太明白这将如何应用于绘图。
问候,门诺
它被称为命令模式。它很容易实现,对任何类型的编辑器都很有用。
Photoshop 在原始图像上应用堆叠变换。一操作一命令。当您撤消时,它只是取消应用转换。所以它只保留原始版本和最新版本,但我想它可能会缓存最后几个版本只是为了提高性能。
由于某些操作将是不可逆的,并且正如您所说,每次都对整个图像进行快照是不可能的,那么我能看到的唯一其他选择就是一堆增量。delta 是一组掩码,包含在操作之前修改的像素。当然,许多操作可能是可逆的,因此可以优化它们的增量。
我不确定 Adobe Photoshop 是如何实现的,但Apple Shakeundo
合成应用程序中的 Paint 节点很容易解释:
x
笔画(我认为是 10 笔)当前图像都会缓存到内存中。这有两个问题:
好吧,还有第三个问题,Shake 是一个可怕的错误,并且在许多领域实现得很差,Paint 节点就是其中之一 - 所以我不确定这是一个多么好的实现,但我无法想象 Photoshop 是太不相似(尽管优化得更好)。
我发现解决这个问题的最简单方法是使用持久数据结构,尽管我不知道 Adobe 是如何解决的,如下所示:
您将图像视为图像块的集合,例如每个 64x64 像素,它们会被垃圾收集或引用计数(例如:shared_ptr
在 C++ 中使用)。
现在,当用户对图像拼贴进行更改时,您可以在浅层复制未修改的拼贴时创建一个新版本:
在这样的变化下,除了那些黑色瓷砖之外的所有东西都被浅浅地复制了。当你这样做时,你的整个撤消系统归结为:
before user operation:
store current image in undo stack
on undo/redo:
swap image at top of undo stack with current image
而且它变得超级简单,不需要在每个撤消条目中一遍又一遍地存储整个图像。作为用户复制和粘贴图层的奖励,除非/直到他们对粘贴的图层进行更改,否则几乎不会占用更多内存。它基本上为您提供了一个图像实例化系统。另一个好处是,当用户创建一个透明层,比如说,2000x2000 像素,但他们只绘制了一小部分图像,比如只有 100x100 像素,这也几乎不会占用任何内存,因为空/透明图块不会必须存储任何像素,只有几个空指针。它还加快了与此类大部分透明图层的合成速度,因为您不必对空图像图块进行 alpha 混合,而可以跳过它们。
至于PS动作,那是一种不同的方法。在那里,您可能会使用一些脚本来指示要执行的操作,但您可以将其与上述结合起来,以有效地仅缓存图像的修改部分。这种方法的重点是避免不得不一遍又一遍地深度复制整个图像,并炸毁内存使用以缓存图像的先前状态以进行撤消,而不必为各种类型的文件编写单独的撤消/重做逻辑。可能发生的不同操作。
Photoshop 使用历史记录来跟踪他们的操作。这些也用作撤消,因为您可以随时回到历史。您可以在首选项中设置历史记录的大小。
我还建议您将Adobe Version Cue 作为一种用于追溯撤消或版本的工具,它内置在套件中仅用于此目的。http://en.wikipedia.org/wiki/Adobe_Version_Cue