内存有限时,位图编辑器的快速撤消/重做?

时间:2010-10-10 17:55:21

标签: algorithm design-patterns optimization undo

我正在尝试为移动设备(即限定版的Photoshop)编写位图编辑器。用户的文档由大约1000x500大小的~4位图组成。

我想要一个尽可能简单的强大而高效的撤销/重做系统。我的目标是大约0.2秒来撤消或重做编辑。我正在寻找关于我目前的预期方法或我可以使用的一些新想法的一些反馈。我认为我所拥有的东西太复杂了,所以我对继续进行谨慎,所以只要知道我能做的最好就会很好。

我已经尝试过将Command模式和Memento模式用于我的撤销/重做系统。到目前为止我得出的一些结论是:

  1. 我没有足够的内存,我无法足够快地将内存写入磁盘,以便在许多情况下使用纪念品来支持上一个命令的“未执行”操作,例如如果用户非常快速地进行多次单独的绘画描边,我将无法存储表示用户绘制的位图,而不会让用户等待保存它们。

  2. 如果我将文档恢复到其初始状态并重放除最后一个命令之外的所有命令以实现撤销,那么即使是适度数量的命令,这也是太慢了。重放10个绘画笔画或5个涂抹笔画需要约1秒,这太慢了。

  3. 我可以通过将整个文档定期保存到磁盘并在播放命令之前恢复到此检查点来解决上一点。为了比上一个检查点更进一步撤消,我们在此之前重新加载检查点并重放命令。

  4. 方法2有3个工作正常除了保存整个文档变得越来越慢,因为添加了更多的图层并且它已经慢了4位图(等待5到10秒)。因此,我需要修改3,以便我只保存自上次以来发生的变化。

    由于许多命令仅在一个层上运行,因此仅保存自上一个检查点以来已修改的层是有意义的。例如,如果我有3个初始图层,我已经指出可以保存检查点的位置,那么我的命令堆栈可能看起来像这样。

    (Checkpoint1: Save layer 1, 2 and 3.)
    Paint on layer 1
    Paint on layer 1
    (Checkpoint2: Save layer 1. Reuse saved layers 2 and 3 from Checkpoint1.)
    Paint on layer 2
    Paint on layer 2
    (Checkpoint3: Save layer 2. Reuse saved layers 1 and 3 from Checkpoint2.)
    Paint on layer 3
    Paint on layer 3
    Flip layer 3 horizontally.
    (Checkpoint4: Save layer 3. Reuse saved layers 1 and 2 from Checkpoint3.)
    Resize layer 1, 2 and 3.
    (Checkpoint5: Save layer 1, 2, 3.)
    

    在编辑过程中,我会跟踪自上一个检查点以来哪些图层已被修改。当我恢复检查点时,我只恢复已更改的图层,例如修改第2层和第3层后恢复Checkpoint4,我从磁盘重新加载第2层和第3层的备份。添加检查点时,我只保存到目前为止已修改的图层。我可以将所有这些大部分都自动化,除非我的界面中需要有用户被迫等待保存检查点的位置,因为我一次只能在内存中保留一层临时副本。

    你怎么看?它比我想要的复杂得多,但我看不到任何其他方式。还有其他有用的模式可以让我的生活更轻松吗?

2 个答案:

答案 0 :(得分:1)

以下内容对于使用图像的图层和撤消缓冲区可能很方便:

  • 将最新图像保留为图像
  • 以前的版本存储为带有下一个版本的xor,然后(假设不是所有内容都以相同的方式更改或更改)使用简单的压缩算法(如运行长度编码)进行压缩

这具有以下优点

  • 以前的版本可以轻松合并(x或它们在一起)。

这可能不适用于:

  • 颜色调整(色调,亮度等)
  • 坐标转换(裁剪,变形等)

答案 1 :(得分:1)

一种方法是将某些“帧”保持为完整帧,将其他帧作为从前一帧创建帧所需的命令。你在#2中暗示了这一点。将一些帧保留在内存中可能会有所帮助。

可能有助于平衡性能与可用于保存完整帧的空间/时间的技巧是丢弃“旧”帧的一部分,以便在任何给定时间您可能具有撤消状态。操作前的1,2,4,8,16,32和64次。撤消一个或两个操作只需要读取一个帧。撤消三个将需要读取检查点并重复一个操作。撤消五个将需要读取检查点并重复三个操作。撤消三十三个将需要读取一个检查点并重复31次操作。

为了提高应用程序的平滑性,在某些情况下,在撤消操作期间重新计算后台中的检查点框架可能会有所帮助。例如,在撤消了17次操作之后,可能会在后台开始计算从起点开始计算48,40和36步的状态,这样如果想要再返回一个,那么就可以做一些工作。请注意,可以抛弃返回1,2,4,8或16个操作的帧,因为可以通过从当前状态向前重播命令来重新创建它们。

相关问题