2010-10-10 9 views
11

Sto provando a scrivere un editor di bitmap per un dispositivo mobile (ad esempio una versione limitata di Photoshop). Il documento dell'utente è composto da ~ 4 bitmap di dimensioni 1000x500 ciascuna.Annulla/ripristina veloce per l'editor di bitmap quando la memoria è limitata?

Desidero un robusto ed efficiente sistema di annullamento/ripristino che sia il più semplice possibile. Sto puntando a circa ~ 0,2 secondi per annullare o ripristinare una modifica. Sto cercando un feedback sul mio attuale approccio previsto o per alcune nuove idee che posso usare. Penso che quello che ho sia troppo complesso, quindi sono cauto nel procedere in modo che solo sapere che è il meglio che potrei fare sarebbe bello.

Ho sperimentato combinazioni di utilizzo del pattern Command e del pattern Memento per il mio sistema di annullamento/ripristino. Alcune conclusioni sono venuto a finora sono:

  1. non ho abbastanza memoria e non riesco a scrivere la memoria su disco sufficiente per l'uso un ricordo per sostenere un'operazione "unexecute" sul comando precedente molte situazioni es se l'utente esegue molti colpi di pittura molto rapidamente, non potrò memorizzare bitmap che rappresentano ciò che l'utente ha dipinto sopra senza far aspettare all'utente che vengano salvati.

  2. Se restauro il documento al suo stato iniziale e riprodurre tutti i comandi tranne l'ultimo ad implementare annullamento, questo è troppo lento dopo anche un modesto numero di comandi esempio la riproduzione di 10 tratti di pittura o 5 tratti di sbavature richiede ~ 1 s che è troppo lento.

  3. posso ottenere intorno al punto precedente salvando l'intero documento in background periodicamente su disco e il ripristino a questo punto di controllo prima di riprodurre i comandi. Per annullare ulteriormente l'ultimo checkpoint, ricarichiamo il checkpoint prima di questo e ripetiamo i comandi.

Approccio 2 con 3 funziona bene tranne che salvare l'intero documento diventa più lento e più lento quando si aggiungono più strati ed è già lento con 4 bitmap (~ 5 - 10 secondi attesa). Devo quindi modificare 3 in modo da salvare solo ciò che è cambiato dall'ultima volta.

Poiché molti comandi operano su un solo livello, è opportuno salvare solo i livelli modificati dall'ultimo checkpoint. Ad esempio, il mio stack di comandi potrebbe apparire come questo se ho 3 livelli iniziali in cui ho indicato dove potrebbero essere salvati i checkpoint.

(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.) 

Durante la modifica, tengo traccia di quali livelli sono stati modificati dal punto di controllo precedente. Quando ripristino un checkpoint, ripristino solo i layer che sono stati modificati, ad es. per ripristinare Checkpoint4 dopo aver modificato i livelli 2 e 3, ricarico i backup dei layer 2 e 3 dal disco. Quando aggiungo un checkpoint, salvi solo il livello che è stato modificato finora. Riesco a fare tutto questo in gran parte automatico, tranne che nella mia interfaccia devono esserci dei punti in cui l'utente è costretto ad attendere il salvataggio dei checkpoint perché posso conservare solo 1 copia temporanea di un livello alla volta.

Cosa ne pensi? È molto più complesso di quanto mi piacerebbe, ma non posso vedere in nessun altro modo. Ci sono altri schemi utili che posso usare per semplificarmi la vita?

risposta

1

Questo seguente potrebbe essere utile per gli strati e annullare i buffer utilizzando immagini:

  • Mantenere l'ultima immagine come immagine
  • Le versioni precedenti sono memorizzati come un XOR con la prossima versione e poi (non assumendo tutto cambiata o modificata nello stesso modo) compresso usando un algoritmo di compressione semplice (come run-length encoding)

Ciò presenta i seguenti vantaggi

  • versioni precedenti potrebbero essere facilmente unite (xorle insieme).

Questo potrebbe non funzionare bene con:

  • regolazioni di colore (tonalità, luminosità ecc)
  • Trasformazioni delle coordinate (coltura, morphing, ecc)
+0

Grazie. Ciò renderà i punti di controllo di salvataggio leggermente più veloci e più efficienti in termini di spazio, ma ripristina leggermente i checkpoint in quanto avrei bisogno di caricare e combinare più checkpoint per ripristinare uno stato precedente. Apprezzerei comunque alcuni commenti sul mio schema generale di annullamento/ripristino e su come potrebbe essere reso più semplice. – memcom

1

Un approccio è quello di mantenere alcuni "fotogrammi" come fotogrammi completi e altri come il comando necessario per creare un fotogramma dal precedente. Alludi a questo nel tuo # 2. Potrebbe essere utile conservare alcuni fotogrammi in memoria.

Un trucco che può aiutare a bilanciare le prestazioni con lo spazio/tempo disponibile per contenere fotogrammi completi è quello di scartare una parte dei "vecchi" fotogrammi, in modo che in qualsiasi momento si possano avere stati di annullamento da ad es. 1, 2, 4, 8, 16, 32 e 64 operazioni fa. Annullare una o due operazioni richiede semplicemente la lettura di una cornice. Annullando tre sarà necessario leggere un checkpoint e ripetere un'operazione. Annullando cinque sarà necessario leggere un checkpoint e ripetere tre operazioni. Annullare il trentatré richiederà la lettura di un checkpoint e la ripetizione di 31 operazioni.

Per migliorare l'uniformità dell'applicazione, in alcuni casi può essere utile ricalcolare i frame di controllo in background durante un'operazione di annullamento. Ad esempio, dopo aver annullato diciassette operazioni, si potrebbe in background iniziare a calcolare gli stati per 48, 40 e 36 passi indietro dal punto di partenza, in modo che se si vuole tornare indietro si avrà già fatto un po 'di il lavoro. Si noti che è possibile abbandonare i frame che erano indietro 1, 2, 4, 8 o 16 operazioni, poiché è possibile ricrearli ripetendo i comandi in avanti dallo stato corrente.

+0

La parte difficile di avere intervalli non costanti (f0 = 1, f1 = 2, f2 = 4, f3 = 8, ecc.) Tra i fotogrammi di annullamento sta mantenendo questi intervalli. Ad esempio, per assicurarti che f2 sia sempre a quattro tratti prima del nuovo tratto, devi andare a f3 e visualizzare ogni tratto in mezzo. La stessa logica vale per f3, f4, ecc. Sì, dovresti iniziare da fmax (che è un'area vuota), ma questo significa in realtà che devi ricostruire l'intero stack di annullamento ogni volta. – jlukanta

+0

@jlukanta: Non è necessario avere checkpoint che sono quelle distanze esatte prima del fotogramma attuale se sono quelle distanze da qualche fotogramma in futuro. Se uno numera tutti i fotogrammi dall'inizio del montaggio a 1, allora si dovrebbe provare ad avere l'ultimo fotogramma dispari, l'ultimo multiplo dispari di 2, l'ultimo multiplo di numeri dispari di quattro, ecc. È un po 'difficile da descrivere lo schema generale, ma fondamentalmente finisce usando il tempo lgN – supercat

Problemi correlati