2010-10-10 64 views
11

我正在尝试为移动设备编写位图编辑器(即Photoshop的有限版本)。用户的文档由〜4个大小各为1000x500的位图组成。内存有限时快速撤销/重做位图编辑器?

我想要一个健壮,高效的撤销/重做系统,尽可能简单。我瞄准约0.2秒来撤销或重做编辑。我正在寻找一些关于我目前的预期方法或我可以使用的一些新想法的反馈意见。我认为我所拥有的东西太复杂,所以我对继续进行谨慎,所以只知道这是我能做的最好的事情。

我已经尝试过使用Command模式和Memento模式的组合来使用我的撤销/重做系统。有些结论我来至今是:

  1. 我没有足够的内存,我不能写内存到磁盘速度不够快,使用留念,以支持先前的命令在“unexecute”操作很多情况下如果用户非常快速地执行了多个单独的绘画笔画,那么我将无法存储代表用户画过的位图,而不会让用户等待它们被保存。

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

  3. 我可以通过将整个文档在后台定期保存到磁盘并在回放命令之前恢复到该检查点来解决上述问题。为了撤销比上一个检查点更远的位置,我们在此之前重新加载检查点并重播这些命令。

方法2连3的作品,除了保存整个文件变得慢如增加更多的层和它已经有4位图慢OK(〜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层的备份。添加检查点时,我只保存到目前为止已修改的图层。除了需要在界面中放置用户被迫等待检查点保存的位置之外,我可以将所有这些大部分自动化,因为我一次只能在内存中保留大约1个临时副本。

您认为如何?这比我想要的要复杂得多,但我看不到其他任何方式。有没有其他有用的模式可以让我的生活更轻松?

回答

1

这下面可能是得心应手层和撤消使用图像缓冲区:

  • 保持最新的图像作为图像
  • 以前的版本被存储为下一个版本,然后异或(假设不是一切改变或以相同的方式使用简单的压缩算法(例如行程长度编码)

这具有以下优点压缩改变)

  • 以前的版本可以很容易地合并(将它们组合在一起)。

这可能不会很好地工作:

  • 色彩调整(色调,亮度等)
  • 坐标变换(裁剪,变形等)
+0

谢谢。这将使保存检查点稍微更快,更节省空间,但由于我需要加载并合并多个检查点以恢复以前的状态,因此恢复检查点的速度稍慢。尽管如此,我希望对我的整体撤消/重做计划提出一些意见,以及如何使它变得更简单。 – memcom 2010-10-11 08:48:55

1

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

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

为了提高应用程序的平滑度,在撤销操作期间,在某些情况下可能有助于在后台重新计算检查点帧。例如,在完成了十七次操作之后,可能会在后台开始着手计算从起始点返回48,40和36步的状态,以便如果想要返回更远的状态,则已经完成了一些操作工作。请注意,可以抛弃后面1,2,4,8或16次操作的帧,因为可以通过从当前状态向前重放命令来重新创建它们。

+0

在撤消帧之间有非恒定间隔(f0 = 1,f1 = 2,f2 = 4,f3 = 8等)的难点在于保持这些间隔。例如,要确保f2在新笔画之前总是四个笔画,您需要转到f3,并在其间绘制每个笔画。同样的逻辑适用于f3,f4等等。是的,你应该从fmax开始(这是空的画布),但这实际上意味着你需要每次重建整个撤消堆栈。 – jlukanta 2014-06-11 01:07:39

+0

@jlukanta:没有必要让检查点在当前帧之前的那些确切距离,如果它们是来自某些帧的未来距离。如果从1开始编辑所有帧,则应该尝试使用最后的奇数帧,2的最后一个奇数倍数,4的最后一个奇数倍数等等。有点难以描述整体方案,但它基本上使用lgN时间结束 – supercat 2014-06-11 04:05:31