2010-10-10 63 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