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


28 апреля 2012 г.

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

Хотелось бы на личном опыте поделиться знаниями и методами по созданию интерактивных журналов для 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-ку, которая, скорей всего, уронит и Ваш движок.
+19
3 ноября 2011, 17:13
57
katleta 4,0

комментарии (24)

+3
vk2 #
«С помощью издательской программы Quark Xpress я вырезал из pdf-ки все тяжелые картинки, дополнительно их сжал, поменял размер, цветовое пространство. Затем я разработал свой псевдо язык скриптов (где использовались html-подобные тэги)»

Я не понял из статьи — кто будет проделывать это над следующими выпусками журнала?
0
katleta #
Планировалось, что я напишу скрипт по вытягиванию картинок из pdf-ок. Но пока это делалось контент-менеджером. По сути полная обработка страницы + написание скрипта занимало 8-12 минут, как мы считали.
+4
spycode #
У вас странное понимание интерактивности журналов.
0
katleta #
Под интерактивностью понималось полное анимирование печатного издание.
Эффекты:
— Перевороты страниц, загибание.
— Закладки, предпросмотр.
— Шрифт текста можно было увеличивать.
— Фразы из текста можно было добавлять в цитаты для шаринга.
— Картинки были кликабельны, их можно было увеличивать, некоторые являлись встроенными галереями.
— На страницах был аудио-голос диктора, виде-файлы.
— Был аппарат для рекламных блоков, в том числе и с анимацией вращения.
— Как варианты, планировалось много туда еще внедрить — как, например интерактивные кроссворды, судоку
+2
tetra #
А изначально PDF нельзя было прислать меньше? к примеру Ваш вес pdf очень похож на вес печатного pdf (300dpi), а из InDesign'a можно выгнать просмотровый pdf (72dpi) и весить он будет гораздо меньше
0
diamant #
Это лишь отсрочит проблему — падать будет не через два, а через пять перелистываний.
0
Kuprianov #
вообще, конечно, сама по себе постановка вопроса — «сделать интерактивный журнал из PDF-версии» — уже радует

а на результат-то в app store посмотреть можно? что за издательство было?
0
kopch #
А чем заказчика не устроили готовые решения для индиза, вроде woodwing'овских ( goo.gl/ZFQ8 )? Или ещё каких. Легче за 500 баксов купить и перевести всё своё добро самим. И продавать через аппстор, а не мучиться с подписками и балансом.
0
Kuprianov #
готовые решения для индиза стоят дорого :) хотя да, альтернативы есть, но заказчики о них не слышали, похоже
0
katleta #
Даже 500 долларов для заказчика было много на то, чтобы тратить на готовые движки.
Хотя это было бы более рациональное решение.
0
zone19 #
А в интерактивности что-нибудь кроме «перелистывания страниц» было?
0
katleta #
В ответ на комментарий spycode — я подробно расписал все эффекты.
+1
graycrow #
… регистрации пользователя, пополнения баланса...


А разве Apple не запрещает покупки в приложениях кроме как через App Store?
–2
pcholberg #
Apple требует чтобы все эти операции были доступны через app store, если программа предоставляет ещё и свой способ оплаты (в дополнение к app store), то почему бы и нет.
–1
katleta #
Да apple не запрещает Вам прикручивать оплаты через банковские карты, робо-кассы и прочие сервисы
0
vipzona #
Почему не рассматривался вариант сохранения в pdf не с полиграфическим качеством, а для просмотра на экране iPad`a? Непонятно как получется 7Мб страница при параметрах 1024×768px 132 px/inch (ppi).
0
futureader #
Потому что людям, смотрящим журналы, надо подробности. Увеличить там что-нибудь.
0
katleta #
качество журналов было 300dpi.
По этому и писал можно сказать статью, чтобы показать как пришлось выкручиваться из всей ситуации в целом.
Сейчас многие планируют делать электронные издательства, надеюсь кто-нибудь заметит сразу ошибки в своих планах и будущие трудности.
+3
PavelT #
Думается, что применение формата PDF в качестве источника первичной информации ошибочно. PDF задуман для решения задачи гарантированной визуализации, но не для преобразования или разбора на составные части.

Я бы пересмотрел весь процесс издания журнала и генерировал его электронную версию в рамках издательского процесса, а не изолированно — мол, вот вам файл и делайте с ним что хотите. Тут надо общаться с заказчиком и корректировать процесс производста.
0
katleta #
Так в конечном итоге — рендерился и не pdf. А набор отдельных блоков текста и картинок — и небольшие pdf-вставки. Для этого и разрабатывал язык верстки журналов.

По сути, в итоге получился готовый движок для построения несложных электроных, анимированных журналов на базе pdf и дополнительных материалов.
0
futureader #
А UIPageView из iOS 5 не пробовали? Правда, он сам смотрит за контроллерами отрисовывающими страницы.
0
katleta #
Год назад еще не было 5 iOs. Можно будет посмотреть на досуге
+2
Bobrovsky #
Я в пару месяцев назад решил такую проблему таким образом:

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

При получении любого memory warning класс закрывает CGPDFDocument, это позволяет полностью освободить память занятую под документ и страницы (включает внутренний кэш).

При последующем обращении на отрисовку страницы документ опять открывается и рисуется.

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

Комментариев нет:

Отправить комментарий