Быстрая отмена средства для растрового редактора - PullRequest
11 голосов
/ 13 июля 2010

Я пытаюсь сделать приложение для растрового редактора для iphone, которое было бы похоже на Brushes или Layers или урезанную версию Photoshop. Я хотел бы иметь возможность поддерживать изображения с разрешением 1000x1000 и примерно 4 слоя, если это возможно.

Я пытаюсь спроектировать свою систему отмены / повтора, прежде чем писать слишком много кода, и у меня возникают реальные проблемы, которые дают хорошее решение из-за ограничений мобильного устройства и того факта, что операции редактора растровых изображений обычно выполняются разрушительный. Наиболее распространенные конструкции отмены / повторения, которые я знаю:

  1. Использовать шаблон команды. Вы сохраняете исходное состояние и команды, используемые для его преобразования в текущее состояние. Для отмены перезагружаете исходное состояние и воспроизводите все команды, кроме последней.

  2. Используйте шаблон памятного подарка. После каждой операции вы сохраняете достаточно информации, чтобы иметь возможность отменить эту операцию.

Проблемы, которые я предвижу:

  1. Шаблон команды: что мне делать после 500 операций редактирования, и я хочу отменить последнюю? Загрузка исходного состояния и применение 499 может занять много времени, особенно если некоторые из них являются дорогостоящими, например, например. применяя фильтры размытия. Мне не нравится, как отмена занимает разное время в разных сценариях.

  2. Шаблон памяти: сохранение измененных частей растрового изображения занимает много памяти. Кэширование этих растровых изображений на диск также может быть медленным (поэтому у меня могут возникнуть проблемы с кэшированием растровых изображений, если пользователь делает много быстрых изменений), и я не уверен в последствиях использования батареи.

Единственные решения, о которых я могу думать, это:

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

  2. Используйте шаблон памяти и заставьте пользователя ждать кэширования растровых изображений. Это не так уж плохо, если я встроу это время, например, в ожидание применения фильтра, но он не работает между мазками кисти.

Есть совет? Мне было бы интересно узнать, как некоторые существующие приложения делают это.

Я могу думать о всевозможных странных гибридах из вышеперечисленного, но у всех них есть очевидные проблемы. Все, что я могу сделать, - это решить некоторые из этих проблем или скомпрометировать приложение, чтобы упростить задачу (например, уменьшить максимальный размер растрового изображения). Я заметил, что несколько приложений имеют довольно низкие максимальные размеры растрового изображения и ограничения слоя.

Ответы [ 5 ]

1 голос
/ 05 февраля 2011

Проверка каждой битовой карты с отображением памяти Флэш-память на устройствах iOS достаточно быстрая, чтобы поддерживать операции отмены / возврата на больших растровых изображениях. Используя системный вызов mmap, я с легкостью отображал растровые изображения 1024x768 ABGR, спасая мою программу от использования драгоценного DRAM. Я не знаю, как бы вы хотели абстрагировать шаблоны отмены / повторения, но способ избежать любых операций копирования с большими накладными расходами состоит в том, чтобы указатели для отмены и повторного растрового изображения меняли местами все отмены / повторы. Вы указали более одного уровня отмены, но держу пари, что вы можете обойтись без некоторого обмена указателями (сейчас я страдаю от некоторой бессонницы и пытаюсь продемонстрировать, что обмен указателями оказался слишком большим - это был какой-то довольно симпатичный псевдокод).

Кроме того, я бы не рекомендовал отмечать ваши mmap'd страницы как F_NOCACHE. Предпочтительно иметь записи кэша iOS в растровое изображение в DRAM, потому что:

  • Быстрее, если не прошить, чтобы прошить
  • Флэш-память рассчитана на фиксированное количество операций записи - не очень удобно сжигать пользовательскую флэш-память (я думаю, что требуется порядка 5 миллионов записей с качественной флэш-памятью на устройствах iOS)
  • Я полагаю, что iOS достаточно агрессивна в управлении памятью, чтобы отключить отображение ваших кэшированных записей и очистить их во время кризиса памяти (хотя я никогда не заботился о том, чтобы проверить это)

Призывайте Джона Кармака (John Carmack) за подсказку, что флэш-память iDevice довольно быстрая (однако он использует F_NOCACHE для получения предсказуемой производительности чтения).

Обратите внимание, что мне нужно было сделать файл размером с фактическое растровое изображение перед вызовом mmap на fd. Не сходите с ума, отображая память на 100 битмапов, хотя (шучу - ДЕЛАЙТЕ!) Я имею в виду, сколько отмен может выполнить пользователь? Они слабы, и их пальцы устают после нескольких секунд нажатия кнопки.

0 голосов
/ 08 февраля 2011

То, с чем вы сталкиваетесь, кажется мне ограничением ресурсов, так что это то, что касается вашего пользовательского интерфейса / дизайна приложения.Нет никаких хитростей, чтобы получить больше памяти, более быстрый доступ к «диску» и т. Д.

Я бы использовал гибридный подход, используя меметон в кольцевом буфере и обрабатывая каждый фильтр в следующем свободном предварительно выделенном слоте.Это даст вам ограниченный быстрый откат / повтор без повреждения кучи.Для неограниченных шагов отмены / повтора у вас есть журнал команд.Если вам действительно нужно 400 шагов отмены, вы также можете сохранить, как каждые 10 операций, снимок с командами и сжать 10 из этих снимков в больший снимок.

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

Также может быть полезно подготовить буфер быстрой отмены / повтора в фоновом режиме, поэтому, когда пользователь отменяет 2 раза, вы уже готовите третью отмену.В большинстве случаев пользователь просматривает изображение в течение нескольких мс (около 200–400), прежде чем он выполнит следующую отмену.

Также вы можете реализовать различные стратегии отмены / возврата для обратимых операций, использующих минимальное количество памяти.Алгоритм быстрого сжатия без потерь (lzma и т. Д.) В фоновом режиме может еще больше снизить потребление памяти.

Но так как это кажется ограничением ресурсов (IO по сравнению с памятью и CPU), все ваши варианты:жить с этим и попытаться сделать пользовательский опыт как можно лучше.И это иногда становится трудной задачей.

0 голосов
/ 23 июля 2010

Для меня модель моментов выглядит лучше всего. Это означает, что я, вероятно, попытался бы придумать способы оптимального хранения этой информации. Вы упомянули, что это может быть растровое изображение 1000x1000, потенциально для одного действия. Можете ли вы, например, представить растровое изображение как 1-разрядное растровое изображение с отдельным полем цвета, хранящимся в другом месте? Теперь вместо 2MB у вас есть 125KB для хранения.

Еще одна вещь, которую я, вероятно, рассмотрю, - это сбор информации, когда пользователь выполняет действие - то есть, пока он пишет, вы можете записать эти биты в структуру данных, как это происходит. И затем, когда они будут сделаны, вы можете зафиксировать действие в своей истории отмены.

Вы должны быть в состоянии применить некоторую алгоритмическую логику к этим структурам данных отмены, чтобы уменьшить их влияние на память, скрывая использование ЦП в течение времени ожидания пользователя.

0 голосов
/ 12 января 2011

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

0 голосов
/ 13 июля 2010

На ум приходит третий вариант: каждое действие выполняется на своем собственном слое и отменяет удаление этого слоя.Он нуждается в быстром механизме рендеринга и умном представлении «слоев действия», где вы не сохраняете «прозрачные» (нетронутые) пиксели.

Если вы принимаете u уровни отмены, выможет объединять слои действия старше u шагов в фоновом режиме.

Вы также можете использовать гибридный подход.Если действие «маленькое», представьте его как слой.Если оно большое, как записанное действие, его необходимо воспроизвести.Как вы говорите, вам нужно эвристическое решение для выбора между двумя случаями.Вы можете проверить производительность рендеринга / сохранения при первом запуске приложения после установки и определить некоторые значения параметров для эвристики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...