我正在尝试为iPhone制作一个位图编辑器应用程序,它类似于画笔或图层或Photoshop的缩减版本。如果可能的话,我希望能够支持大约4层的1000x1000分辨率图像。
我正在尝试设计我的撤销/重做系统,然后我编写了太多的代码,由于移动设备的局限性以及位图编辑器操作通常的事实,我遇到了一个很好的解决方案破坏性的。我所知道的最常见的撤销/重做设计是:
使用命令模式。您存储初始状态和用于将其转换为当前状态的命令。要撤消,您需要重新加载初始状态并重播除最后一个命令之外的所有命令。
使用纪念图案。每次操作后,您都会存储足够的信息以便还原该操作。
我预见的问题是:
命令模式:500次编辑操作后我该怎么办?我想撤消最后一次操作?加载初始状态并应用499可能是耗时的,特别是如果其中一些是昂贵的事情,例如应用模糊过滤器。我不喜欢撤销在不同场景下花费不同时间的方式。
Memento模式:保存已修改的位图部分会占用大量内存。将这些位图缓存到磁盘也很慢(因此,如果用户进行大量快速编辑,我可能无法缓存位图)并且我不确定电池使用情况的影响。
我能想到的唯一解决方案是:
使用命令模式和纪念模式,其中,每10个命令左右或在昂贵的操作之后,整个状态也被保存(这为您提供免费的自动保存功能)。要撤消,我会重新加载最近的快照,然后重播这些命令。我宁愿避免这种复杂性。
使用memento模式并强制用户等待缓存位图。如果我将这段时间建立在例如等待过滤器应用但在制作画笔笔划之间不能很好地工作。
是建议吗?我有兴趣知道一些现有应用程序是如何做到的。
我可以想到上面所有类型的怪异混合物,但它们都有明显的问题。我所能想到的只是遇到一些这些问题或者破坏应用程序以使问题更简单(例如减小最大位图大小的大小)。我注意到有几个应用程序的最大位图大小和图层限制非常低。
答案 0 :(得分:1)
使用内存映射检查每个位图 iOS设备上的闪存足够快,可以支持大型位图上的撤消/重做操作。使用mmap系统调用,我可以轻松地映射1024x768 ABGR位图,从而节省了我的程序使用珍贵的DRAM。我不知道你想如何抽象undo / redo模式,但避免任何高开销复制操作的方法是让undo和redo位图的指针交换每个undo / redo。你已经指定了多个撤销级别,但我敢打赌你可以通过一些指针交换来逃避(我现在正遭受一些失眠并试图证明指针交换证明太多了 - 这是一些非常垃圾的伪代码)。 / p>
另外,我不建议将mmap的页面标记为F_NOCACHE。最好让iOS缓存写入DRAM中的位图,因为:
向John Carmack大声说明iDevice Flash内存非常快(他使用F_NOCACHE来获得可预测的读取性能)。
请注意,在fd上调用mmap之前,我必须使文件的大小与实际位图相同。不要疯狂记忆映射100位图,但是(开玩笑 - 做它!)我的意思是,用户可以执行多少撤消操作?经过几秒钟的捣碎后,它们很脆弱,手指也会疲惫不堪。
答案 1 :(得分:0)
我想到了第三个选项:每个操作都在自己的层上执行,撤消删除该层。它需要一个快速渲染机制和“动作层”的智能表示,您不需要存储“透明”(未触摸)像素。
如果您假定 u 撤消级别,则可以将比 u 更早的操作层合并到后台。
你也可以采用混合方法。如果操作为“小”,则将其表示为图层。如果它很大,作为记录动作,需要重播。如你所说,你需要一个启发式来决定两种情况。您可以在设置后的应用程序首次运行时测试渲染/保存性能,并确定启发式的一些参数值。
答案 2 :(得分:0)
答案 3 :(得分:0)
我会选择混合方法。最重要的是,将数据组织成部分(例如图块),这样您只需存储修改部分的状态(使用延迟复制机制)。
答案 4 :(得分:0)
您所面对的似乎是对我的资源限制,因此这与您的UI /应用程序设计有关。获得更多内存,更快的“磁盘”访问等等,没有任何巧妙的技巧。
我会在环形缓冲区中使用memeton并在下一个免费的预分配插槽中处理每个滤波器。这将为您提供有限的快速撤消/重做,而不会出现堆损坏。对于无限制的撤销/重做步骤,您可以获得命令日志。如果您确实需要400个撤消步骤,您还可以像使用命令一样每10个操作保存一个快照,并将这些快照中的10个压缩到更大的快照中。
最重要的是向用户说明他们是在设备的限制下操作,例如当你的快速撤消用完时的警告标志。
此外,在后台准备快速撤消/重做缓冲区可能也是有益的,因此当用户撤消2次时,您已准备好第3次撤消。大多数时候,用户在执行下一次撤消之前会在几分钟内(大约200-400)查看图像。
此外,您可以为使用最少内存的可逆操作实施不同的撤消/重做策略。背景中的快速无失败压缩算法(lzma等)可以进一步减少内存消耗。
但是,由于这似乎是一个资源限制(IO与内存与CPU),所有选项都要与它一起使用,并尝试尽可能地让用户体验到最佳状态。这有时会成为一项艰巨的任务。