Pull to refresh

Разработка электронного, интерактивного журнала для iPad

Reading time 4 min
Views 17K
Хотелось бы на личном опыте поделиться знаниями и методами по созданию интерактивных журналов для iPad.

Где-то в конце 2010 года ко мне обратились с заказом реализовать приложение, которое бы позволяло перевести печатную продукцию издательств (журналы, книги, брошюры) в электронный формат для удобного чтения на iPad. После долгих разговоров и уточнений, финальная задача технического задания была сформулирована так:

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

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

За основу анимации я взял проект github.com/brow/leaves, который до сих пор является одним из самых известных движков в этом направлении. Мне очень понравилась реализация эффектов отгибания и перелистывания страниц. Изначальный вид движка представлен на рисунке внизу.

image

После того как я изменил движок под себя, сделал функции по отображению превью, добавления страниц в закладки и прочие нюансы, получил pdf-версию 40 страничного журнала из издательства, который весил 144Мб и залил на реальный девайс, столкнулся с фатальной проблемой. При перевороте случайной страницы, журнал просто вылетал.

Обратившись к логам я столкнулся с ошибкой:
data formatters temporarily unavailable
По сути, у iPad'a кончилась виртуальная опертивная память, которая разрешена для использования приложения. Копая намного глубже, используя tools — memory allocations, я заметил, что при рендеринге очередной pdf-страницы выделенная память накапливается и не освобождается.

Можно конечно подумать, что я не грамотно использовал CGPDFPageRelease и прочие операции, связанные с освобождением и чисткой памяти. Но тестируя приложение более месяца, изучив сотни интернет-постов, проблем и решений, единственное разумное объяснение по теме «Рендеринг больших pdf» — это то, что iOs sdk, при вызове метода CGPDFPageRelease действительно не уничтожает память. Как было написано на официальном сайте apple (к сожалению, ссылку уже найти не смог) CGPDF кэширует в памяти тайлы страницы, чтобы в следующий раз при обращении рендеринг проходил быстрее. То есть появилась проблема вот такого внутреннего кэш-механизма от apple, который стабильно не давал читать тяжелые pdf-журналы.

В холодном поту, горя по срокам, я начал искать оптимальные решения сложившейся проблемы. Дополнительно заказчику не очень нравилась медленная прорисовка CATiledLayer, хотя объяснить ему, что одна страница весила не менее 7Мб было сложно. Попробовал загрузить мой чудо-pdf файл из издательства в UIWebView, в итоге идея потерпела полное фиаско. Веб-компонента упала еще быстрее, чем мой движок, уже полный костылей.

Переходим к решениям проблемы:

В итоге я хотел написать pdf-парсер, который бы вынимал все картинки и текст из файла. Потом я их перегонял в свой формат, и выводил в приложении стандартными средствами (например, UIImageView, UITextView или CoreText). Прочитать тонну мануалов от Adobe я не осилил, хотя до сих пор считаю это перспективной идеей. Найти нормальный парсер pdf в Интернете тоже не получилось — все выдирали изображения или коряво, или совсем не то делали. Про то, чтобы доставать тексты из pdf хотя бы в формате .doc или .html вообще молчу.

Конечная реализация моя представляла следующий механизм.
С помощью издательской программы Quark Xpress я вырезал из pdf-ки все тяжелые картинки, дополнительно их сжал, поменял размер, цветовое пространство. Затем я разработал свой псевдо язык скриптов (где использовались html-подобные тэги), например:

(page num = 1)
(pdf)1(/pdf)
(image)0,0,768,1024,first_page_image.png(/image)
(text).....(text)
(video).....(video)
(slide).....(slide)
(3d)....(3d)
(/page)

Затем создавались легкие jpg-превью для каждой страницы. Когда эффект перелистывания заканчивался на превью добавлялся CATiledLayer который начинал рисовать pdf-ку с вырезанными картинками (то есть только текст и несложные элементы). Параллельно парсился файлик с тэгами, и на задний или передний план добавлялись все интерактивные элементы, вешались на них обработчики, в нужных местах начиналась анимации, поверх них добавлялись специальные элементы «активаторы» — для взаимодействия с интерактивными элементами.

В итоге мое приложение не падало, работало достаточно быстро и отвечало всем требованиям ТЗ.

Около месяца назад поступало опять похожее предложение на реализацию электронного журнала. Но я был вынужден отказаться, так как не хотел опять пройти через весь этот гемор. Но ради собственного любопытства, я проанализировал новые стабильные free-движки в интернете. Из новых понравился github.com/vfr/Reader
Но как только я залил в него ту самую pdf-ку с которой так долго мучался год назад, он тоже упал. Все официальные движки от apple падают также.

Если кто хочет поделиться опытом, или заверить, что его движок решает проблему чтения гигантских pdf-ок — пишите, буду рад поделиться более подробными советами и скинуть ту самую злостную pdf-ку, которая, скорей всего, уронит и Ваш движок.
Tags:
Hubs:
+19
Comments 26
Comments Comments 26

Articles