Зачем читать PDF, если на них нельзя писать?
Всем привет! Я Альберт, и я люблю делать инструменты более удобными для работы.
Если вы когда-либо пробовали заниматься самообразованием, изучать учебники по программированию или читать сложные технические документы из PDF на своем ноутбуке или планшете, вы знакомы с этой проблемой. Вы открываете книгу, хотите выделить ключевой фрагмент кода, нарисовать стрелку-схему рядом с объяснением или оставить заметку на полях — и понимаете, что стандартные просмотрщики PDF либо перегружены функциями, либо платные, либо полностью теряют ваши рисунки при случайном обновлении вкладки.
Я хотел исправить это и создать PDF Ink — легкое и быстрое веб-приложение для чтения и интерактивного аннотирования PDF-книг прямо в браузере.
Идея и технологический стек
Главная цель состояла в том, чтобы построить инструмент, который:
- Запускается в один клик в любом современном браузере.
- Позволяет загружать любой локальный PDF-учебник.
- Позволяет рисовать на страницах с помощью мыши, стилуса или касания, а также вводить текстовые заметки.
- Самое главное: надежно сохраняет текущую страницу, уровень масштабирования, список библиотек и все заметки с рисунками локально, чтобы вы могли продолжить обучение в любой момент.
Для реализации я выбрал современный стек: React + TypeScript + Vite + TailwindCSS.
Для рендеринга PDF интегрировал надежную библиотеку pdfjs-dist (PDF.js) от Mozilla.
Двухслойная архитектура Canvas
Чтобы приложение оставалось быстрым во время рисования, я разделил рабочую область на два независимых слоя:
- Слой PDF: Статический фоновый
<canvas>, который рендерит изображение страницы PDF с учетом масштаба. - Слой аннотаций: Прозрачный верхний
<canvas>, который перехватывает события указателя, рисует векторные штрихи и накладывает текст.
Благодаря этому рисование происходит мгновенно: когда вы рисуете линию, приложение обновляет только легкий слой векторных штрихов, не затрагивая тяжелый холст PDF.
Эволюция базы данных: Переход на IndexedDB v2
Первая версия сохраняла PDF-файл и все рисунки как один объект в IndexedDB. С большими книгами запись файла размером 20 МБ каждые 250 мс вызывала лаги интерфейса.
Я переписал менеджер IndexedDB для разделения файлов и аннотаций:
- Хранилище
pdfs: Хранит исходный бинарный файл (ArrayBuffer) и записывается только один раз при импорте. - Хранилище
pdfs_metadata: Хранит легкие метаданные рисунков, страниц и текстов в JSON.
Теперь при рисовании обновляется только легкий объект метаданных. Запись занимает доли миллисекунды, полностью устраняя лаги!
Попробуйте сами!
Вы можете протестировать живую версию приложения здесь:
👉 Practice Book PDF APP Live App
Учитесь с удовольствием и пишите код, который делает жизнь проще!