Быстрая отмена/повтор для редактора растровых изображений, когда память ограничена?

Я пытаюсь написать растровый редактор для мобильного устройства (т.е. ограниченную версию Photoshop). Пользовательский документ состоит из ~ 4 растровых изображений размером около 1000x500.

Я хочу, чтобы как можно более прочная и эффективная система отмены/повтора. Я собираюсь около ~ 0.2s для отмены или повторного редактирования. Я ищу некоторые отзывы о моем текущем планируемом подходе или о некоторых новых идеях, которые я могу использовать. Я думаю, что у меня слишком сложная задача, поэтому я осторожно отношусь к тому, чтобы просто знать, что самое лучшее, что я мог сделать, было бы хорошо.

Я экспериментировал с комбинациями использования шаблона Command и шаблона Memento для моей системы отмены/повтора. Некоторые выводы, которые я пришел до сих пор:

  • У меня недостаточно памяти, и я не могу записать память на диск достаточно быстро, чтобы использовать память для поддержки "невыполненной" операции над предыдущей командой во многих ситуациях, например. если пользователь делает несколько отдельных штрихов краски очень быстро, я не смогу хранить растровые изображения, которые отображают то, что пользователь нарисовал, не заставляя пользователя ждать их сохранения.

  • Если я верну документ в исходное состояние и воспроизведу все команды, кроме последнего, чтобы выполнить отмену, это слишком медленно после даже небольшого количества команд, например. повторение 10 мазков краски или 5 мазков ударов занимает ~ 1 с, что слишком вяло.

  • Я могу обойти предыдущую точку, периодически сохраняя весь документ в фоновом режиме на диск и восстанавливая эту контрольную точку перед воспроизведением команд. Чтобы отменить назад, чем последняя контрольная точка, мы перезагружаем контрольную точку до этого и воспроизводим команды.

Подход 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.)

Во время редактирования я отслеживаю, какие слои были изменены с предыдущей контрольной точки. Когда я восстанавливаю контрольную точку, я только восстанавливаю слои, которые изменились, например. чтобы восстановить Checkpoint4 после изменения уровня 2 и 3, я перезагружаю резервные копии слоев 2 и 3 с диска. При добавлении контрольной точки я сохраняю только тот слой, который был изменен до сих пор. Я могу сделать все это главным образом автоматическим, за исключением того, что в моем интерфейсе должны быть места, где пользователь вынужден ждать, пока контрольные точки будут сохранены, потому что я могу хранить только одну временную копию слоя в памяти за раз.

Как вы думаете? Это гораздо сложнее, чем мне хотелось бы, но я не вижу другого пути. Есть ли другие полезные шаблоны, которые я могу использовать, чтобы облегчить мне жизнь?

Ответ 1

Это может быть удобно для слоев и отменить буферы с использованием изображений:

  • Сохранять последнее изображение как изображение
  • Предыдущие версии сохраняются как xor со следующей версией, а затем (при условии, что не все изменилось или изменилось таким же образом) сжато с использованием простого алгоритма сжатия (например, кодирование длины прогона)

Это имеет следующие преимущества.

  • предыдущие версии могут быть легко объединены (они вместе).

Это может не сработать:

  • настройки цвета (оттенок, яркость и т.д.)
  • преобразования координат (обрезка, морфинг и т.д.)

Ответ 2

Один из подходов состоит в том, чтобы сохранить определенные "кадры" как полные кадры, а другие - как команду, необходимую для создания кадра из предыдущего. Вы ссылаетесь на это в своем # 2. Может быть полезно сохранить некоторые кадры в памяти.

Трюк, который может помочь сбалансировать производительность с пространством/временем, доступным для хранения полных кадров, - это отбросить часть "старых" кадров, чтобы в любой момент времени у вас могли быть состояния отмены, например. 1, 2, 4, 8, 16, 32 и 64 операции назад. Отмена одной или двух операций потребует просто чтения кадра. Отмена три потребует прочтения контрольной точки и повторения одной операции. Отмена пяти требует считывания контрольной точки и повторения трех операций. Отмена тридцати трех потребует прочтения контрольной точки и повторения 31 операции.

Чтобы улучшить гладкость приложения, в некоторых случаях может оказаться полезным перекомпоновать кадры контрольной точки в фоновом режиме во время операции отмены. Например, после отмены семнадцати операций можно в фоновом режиме начать работу над вычислением состояний на 48, 40 и 36 шагов назад от начальной точки, так что если кто-то захочет вернуться назад, то уже будет сделано несколько работа. Обратите внимание, что можно сбрасывать кадры, которые были назад 1, 2, 4, 8 или 16 операций, так как их можно воссоздать, переведя команды вперед из текущего состояния.