-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Если планируем новую ветку с промежуточными фильтрами, надо решить, как жить дальше.
Как было раньше (в старых ST, за 2008 год):
- Исходные файлы идентифицируются по ImageId. Внутри Id - всего лишь полный путь к файлу, так что это уникальный идентификатор.
- В ходе работы делается нарезка на страницы, которые все равно реально представлены одним изображением. Поэтому id завернут внутрь PageId, который хранит ImageId и дополнительно номер страницы.
- Все фильтры, кроме последнего, не меняют исходное изображение, а только масштабируют, поворачивают, и подрезают. Все это умеет делать Qt на лету при рисовании QImage. Поэтому от фильтра к фильтру передается исходный QImage, а каждый фильтр только правит матрицы преобразований и контур подрезки, а Qt их рисует, когда надо - такая обработка происходит очень быстро.
После выбора новой страницы обработка идет в три стадии Обработка изображения, Обновление эскиза, Прорисовка эскиза:
-
Обработка изображения
- Обработка происходит в Task::process()
- Главное окно собирает список задач (у каждой задачи есть указатель на следующую, или нуль).
- Получается цепочка LoadFileTask -> fix_orientation::Task -> page_split::Task -> ... -> null.
- LoadFileTask загружает исходный файл, и далее по цепочке передается Id, QImage и Transformation.
- Каждый фильтр в цепочке правит либо трансформацию (ориентация, поворот), либо подрезку (страницы, поля).
- По завершении результаты (изображение, трансформация и подрезка) передаются в центральное изображение, где Qt и рисует исходную картинку - повернутую и подрезанную.
-
Обновление эскиза
- Обработка происходит в CacheDrivenTask::process()
- Первая стадия сигналит списку эскизов (ThumbnailSequence), и тот запускает вторую цепочку из CacheDrivenTask.
- В ней нет файловых операций, она только возвращает результирующую трансформацию для Id.
- В список эскизов помещается обновленный легковесный Item c Id внутри.
-
Прорисовка эскиза
- Прорисовка происходит в обработчике события paint()
- Эскиз, которому надо прорисоваться, лезет в кеш (ThumbnailPixmapCache) по PageId.
- Кеш для PageId генерирует уникальное имя файла для записи на диск, создает и записывает туда изображение, и возвращает эскизу для прорисовки.
- Уникальное имя получается дописыванием к исходному имени хеша, полученного из полного пути (который как раз есть в Id). Уникальный путь дает уникальных хеш и имя эскиза для записи.
Важно, что прорисовка эскизов оптимизирована. Как и с главной картинкой, на всех стадиях кроме последней, используется одно и то же изображение. Это можно посмотреть во время работы ST в каталоге out\cache\thumbs. На всех стадиях в кеше хранится одна копия эскиза, потому имя файла кеш генерирует по одному и тому же Id. А зрительно эскизы отличаются потому, что после загрузки из кеша эскиз еще кое-что дорисовывает поверх сам.
Исключение - последняя стадия, output. На этой стадии сначала Task::process() создает новое окончательное изображение, и записывает его в каталог out под именем out_file_path. А потом создает новый эскиз, у которого Id подменен на новый - PageId(ImageId(out_file_path)). И цепочка CacheDrivenTask::process() тоже возвращает новый идентификатор - PageId(ImageId(out_file_path)). После этого при рисовании эскиза в кеше появится новая запись, потому что хеш пути поменялся, и на стадии output эскиз становится другой.
Как стало в ST/STA/STU
Если попробовать поменять изображение в какой-нибудь из промежуточных стадий (как в STD) - ломается логика работы цепочек Task/CacheDrivenTask и кеша, которые в оригинале максимально легковесны. Возможно, поэтому во всех поздних версиях ST обработку изображения затолкали на вкладки последней стадии, чтобы не переделывать базовую логику.
Как сделано в STEX
После появления в середине обработки стадии dewarp понадобилось обновлять эскизы, если сделана развертка (а если только поворот - то не надо). Поэтому кеш был доработан: элементам ThumbId внутри него добавлены флаги isAffineTransform. Эти флаги отличают распрямленные изображения от обычных, и кеш генерирует для них другие имена (см. метод ThumbnailPixmapCache::Impl::getThumbFilePath). Поэтому для развернутых изображений кеш, начиная со стадии dewarp и до конца, создает дополнительные файлы эскизов, которые не смешиваются с эскизами предыдущих стадий.
Что должно быть теперь?
Теперь планируется в еще одной новой стадии менять изображение по дороге. Разумеется, нужно менять и эскиз. Какие есть варианты? Сходу могу предложить:
- Просто генерировать в кеше для разных стадий разные имена файлов: img_1_XXX, img_2_XXX, img_3_XXX. Просто и дубово. Появятся лишние чтения - записи.
- Ввести параметр "версия эскиза", и передавать ее по цепочкам. Какой фильтр нахулиганил - увеличивает версию, и в кеше генерируется новый файл. Это аналог решения из STEX. Видимо, средне-сложно.
- Принудительно записывать новый файл на диск, если фильтр поменял изображение, и дальше передавать уже его Id. Придется в каталоге out завести подкаталоги для вредных фильтров. Это аналог решения в стадии output. Видимо, самое сложное.
- В отладочной версии сейчас после распрямления видны жуткие тормоза, от стадии dewarp и до самого конца. Видимо, повторные генерации изображения тормозят. Решение с промежуточной записью должно вроде ускорить дело.
- Теоретически, тут можно и внешнюю обработку добавить. Внешняя программа как раз через этот промежуточный сохраненный файл и обменивалась бы с ST.