← Все инструменты
📑

Склейка дуплексного скана — Собрать лицевые и оборотные страницы PDF

Бесплатный инструмент для сборки дуплексных сканов: объединяет два PDF (лицевые и оборотные страницы) в один документ с правильным чередованием. Прямо в браузере.

+Загрузить PDF или фотоили перетащите файлы сюда🚀 Запустить инструмент бесплатно

Как это работает

01

Откройте инструмент Дуплекс

Нажмите на инструмент Дуплексный скан в главном меню приложения.

02

Загрузите фронт и оборот

В открывшемся окне загрузите два PDF: лицевые и оборотные страницы.

03

Настройте порядок оборотных

Если оборотный PDF отсканирован в обратном порядке — включите опцию «Обратный порядок».

04

Дождитесь обработки

Приложение читает оба файла и выстраивает страницы: Фронт₁ / Оборот₁ / Фронт₂...

05

Получите готовую галерею

Все страницы чередуются в правильном порядке — экспортируйте финальный PDF.

Почему pdfredX

🔒

Полная конфиденциальность

Файлы не покидают ваш браузер. Никакой загрузки на сторонние серверы.

Обработка на стороне клиента

Все вычисления выполняются локально — быстро, безопасно и бесплатно.

🆓

Без регистрации

Просто откройте браузер и приступайте. Никаких аккаунтов не нужно.

📱

На любом устройстве

Работает на ПК, планшете и смартфоне без установки.

Полезные материалы по теме

Дуплексный скан PDF: собираем документ из двух прогонов АПД
Когда сканируете стопку двусторонних листов через автоподатчик, сканер делает два прогона: сначала все лицевые страницы, потом все оборотные. На выходе — два PDF вместо одного. Стандартные онлайн-сервисы не понимают эту структуру и не умеют её восстанавливать. Инструмент дуплексного скана в pdfredX делает именно это — прямо в браузере, без отправки ваших документов куда бы то ни было.

Когда сканируете стопку двусторонних листов через автоподатчик, сканер делает два прогона: сначала все лицевые страницы, потом все оборотные. На выходе — два PDF вместо одного. Стандартные онлайн-сервисы не понимают эту структуру и не умеют её восстанавливать. Инструмент дуплексного скана в pdfredX делает именно это — прямо в браузере, без отправки ваших документов куда бы то ни было.


Шаг 01. Загрузка файлов

Откройте pdfredX и перетащите оба PDF в зону загрузки — или выберите их через проводник. Загружайте файлы в правильном порядке: сначала фронт (нечётные, лицевые), затем бэк (чётные, оборотные). Порядок загрузки имеет значение: именно он определяет, какой файл алгоритм считает первым.

После загрузки галерея сразу покажет цветовую маркировку: зелёная полоса на карточках — страницы фронта, синяя — страницы бэка. Это не декоративная деталь. Маркировка отражает внутренние ключи pdfSrcKey: 'duplex:front:...' и 'duplex:back:...' в массиве items[] — по ним алгоритм чередования будет собирать правильный порядок. Если цвета перепутаны — значит, файлы загружены в обратном порядке; просто удалите их и загрузите заново.


Шаг 02. Настройка дуплексного режима

Нажмите кнопку «Дуплексный скан» на тулбаре. Откроется боковая панель #DM с тремя элементами управления.

Назначение файлов. Два выпадающих списка: «Фронт» и «Бэк». Если вы загрузили файлы в правильном порядке, назначение проставляется автоматически по порядку поступления. Если нет — переназначьте вручную, это занимает пять секунд.

Реверс бэка (dmReverseBack). Самый важный переключатель. Большинство АПД после первого прогона переворачивают стопку — оборотные страницы сканируются в обратном порядке: последний лист становится первым. Если не учесть это, чередование сломается: Front₁ → Back₅ → Front₂ → Back₄ вместо Front₁ → Back₁ → Front₂ → Back₂.

При включённом реверсе алгоритм читает бэк-массив справа налево: backLen - 1 - i вместо i. Это единственное математическое изменение, но оно полностью восстанавливает правильный порядок. Как понять, нужен ли реверс вашему сканеру: включите его и посмотрите на превью в галерее. Если страница 2 стала оборотной страницы 1 — всё правильно. Если нет — выключите.

Предпросмотр порядка. Ещё до нажатия «Применить» галерея обновляет порядок карточек в реальном времени по мере изменения настроек. Вы можете прокрутить все страницы и убедиться в правильности чередования до финальной сборки.


Шаг 03. Сборка и переход к экспорту

Нажмите «Применить». Алгоритм за доли секунды перестраивает массив items[] — это чисто индексная операция без повторного рендера страниц. Галерея перестраивается и показывает финальный порядок: Front₁ / Back₁ / Front₂ / Back₂ / ...

Быстрый старт с лендинга. Если вы пришли на главную страницу pdfredX через лендинг инструмента «Дуплексный скан», браузер уже сделал за вас один шаг. js/features-landing.js записывает в sessionStorage параметр openTool=duplex и перенаправляет на главную страницу. При загрузке приложение читает этот параметр и автоматически открывает боковую панель дуплекса — вам не нужно искать кнопку в тулбаре. Просто перетащите файлы и настройте реверс.

Экспорт. Нажмите «Скачать PDF». jsPDF 2.5.1 итерирует по обновлённому массиву items[]: для каждой страницы вызывается addImage(editUrl, ...) с автоматическим определением ориентации A4 по пропорциям изображения. Файл собирается полностью в памяти браузера и скачивается напрямую — без очереди, без ожидания серверного ответа.


Как это устроено под капотом

Каждый загруженный PDF рендерится постранично через PDF.js 3.11.174. Каждая страница превращается в растровый dataURL в Canvas и сохраняется в массив items[] с меткой источника. Два PDF дают два отдельных массива с разными pdfSrcKey.

При сборке дуплекса ничего не рендерится заново. Алгоритм строит новый индексный массив: попеременно берёт items[i] из фронт-массива и items[j] из бэк-массива, где j = i или j = backLen - 1 - i в зависимости от флага dmReverseBack. Вся операция — переупорядочивание ссылок в JavaScript, а не тяжёлый рендер. На 200 страницах это занимает меньше 100 миллисекунд.


Известные ограничения

Только растровый результат. PDF.js рендерит страницы в Canvas, поэтому на выходе мы работаем с растровыми изображениями. Текст в итоговом PDF нельзя выделить как текст — он является частью растра. Если нужен редактируемый текстовый слой, используйте инструмент OCR по области поверх нужных страниц.

Производительность на мобильных. Документы толще 80–100 страниц на слабых смартфонах рендерятся с заметной задержкой: PDF.js держит каждую страницу в памяти как ImageData. На десктопе это практически незаметно.

Разное разрешение фронта и бэка. Если оба прогона отсканированы с разным DPI или в разной ориентации, чередование сработает корректно, но визуально документ будет непоследовательным. Выровняйте ориентацию страниц через инструмент поворота перед сборкой дуплекса.

Лимит памяти браузера. Практический предел — около 200–300 страниц на вкладку в зависимости от объёма RAM устройства. Сверх этого — Chrome начинает выгружать кэш, и повторный рендер замедляет сборку.


Если вы сканировали книгу в режиме разворота — каждая страница содержит два листа — задача другая, и у нас есть отдельный гайд: Разделить разворот книги PDF на две страницы.

Попробуйте прямо сейчас — pdfredx.com, без регистрации, файлы остаются у вас.

Дуплекс скан PDF и конфиденциальность: что происходит с документом, когда вы нажимаете Upload
Вы сканируете трудовой договор, HR-анкету с паспортными данными или акт с конфиденциальными условиями. Сканер выдаёт два файла — фронт и бэк. Чтобы склеить их в один правильный документ, нужен инструмент. Вы открываете первый попавшийся онлайн-сервис, нажимаете Upload — и в этот момент ваш документ уже не полностью ваш.

Вы сканируете трудовой договор, HR-анкету с паспортными данными или акт с конфиденциальными условиями. Сканер выдаёт два файла — фронт и бэк. Чтобы склеить их в один правильный документ, нужен инструмент. Вы открываете первый попавшийся онлайн-сервис, нажимаете Upload — и в этот момент ваш документ уже не полностью ваш.

Разберём, что именно происходит в тот момент. И почему обработка PDF прямо в браузере — это не маркетинговый слоган, а архитектурное решение с измеримыми последствиями для конфиденциальности ваших данных.


Куда улетают ваши документы при стандартной облачной обработке

Когда вы загружаете файл в типичный онлайн-PDF-сервис, происходит следующее:

Файл уходит на удалённый сервер. Он физически покидает ваше устройство и передаётся в дата-центр — возможно, в другой стране, под другой юрисдикцией, на серверах, которые вы никак не контролируете.

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

Метаданные попадают в логи. Дата загрузки, IP-адрес, имя файла, его размер, технические параметры — всё это фиксируется в серверных журналах. Логи хранятся дольше, чем сам файл.

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

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

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


Полная изоляция в браузере: как устроена обработка в pdfredX

pdfredX не загружает ваши файлы ни на какой сервер. Это не обещание из раздела «О нас» — это следствие архитектуры приложения, которую можно проверить.

PDF.js рендерит файл прямо в вашем браузере. Библиотека PDF.js 3.11.174 запускается внутри вашей вкладки и читает PDF-файл локально через браузерный FileReader API. Каждая страница растеризуется в Canvas — встроенный HTML5-холст. Никакого сетевого запроса в этот момент не происходит.

Данные хранятся в оперативной памяти вкладки. Каждая страница превращается в dataURL — закодированное изображение — и сохраняется в массиве items[] в памяти браузера. Этот массив существует только внутри вашей открытой вкладки. Закрыли вкладку — данные уничтожены.

sessionStorage хранит только служебное состояние. Настройки интерфейса, параметры инструментов — всё это пишется в sessionStorage, который изолирован внутри браузера и никогда не передаётся на сервер. Это стандарт браузерной безопасности, а не наша реализация.

jsPDF собирает итоговый файл на клиенте. Когда вы нажимаете «Скачать PDF», библиотека jsPDF 2.5.1 компонует документ прямо в памяти вкладки и передаёт его браузеру для скачивания. Не на сервер — браузеру. Файл появляется в вашей папке «Загрузки» без промежуточной остановки на чужой инфраструктуре.

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


Безопасная обработка дуплексного скана: пошагово

01. Загрузка файлов

Перетащите оба PDF — фронт и бэк — в зону загрузки на pdfredx.com. Файлы читает браузерный FileReader API: они не покидают устройство ни на этом шаге, ни на последующих. Галерея показывает страницы сразу после локального рендера.

02. Настройка порядка

Откройте панель «Дуплексный скан». Назначьте, какой файл является фронтом, какой — бэком. При необходимости включите реверс бэка (dmReverseBack) — для АПД-сканеров, которые переворачивают стопку после первого прогона. Галерея показывает предпросмотр порядка в реальном времени. Всё происходит в памяти вкладки.

03. Экспорт и закрытие

Нажмите «Применить», затем «Скачать PDF». jsPDF собирает документ локально и передаёт его браузеру для скачивания. После закрытия вкладки все данные о файле уничтожаются автоматически — в sessionStorage и в памяти браузера ничего не остаётся.


Что мы гарантировать не можем — честный дисклеймер

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

Кейлоггер или вредоносное ПО на вашем устройстве. Если на компьютере уже установлен перехватчик ввода или шпионское ПО, оно может читать файлы с диска или перехватывать данные на уровне ОС. Браузерное приложение против этого бессильно.

Расширения браузера с широкими правами. Некоторые расширения запрашивают разрешение на чтение содержимого всех вкладок. Если такое расширение установлено и активно — оно может видеть данные в DOM страницы. Работайте с чувствительными документами в браузере без сторонних расширений или в режиме инкогнито.

Файл на вашем диске. После скачивания PDF оказывается на вашем локальном диске. Безопасность хранения этого файла — ваша ответственность: шифрование диска, права доступа, политика хранения.

Историческая запись о посещении сайта. Браузер фиксирует адрес pdfredx.com в истории. Сам документ нигде не логируется, но факт посещения сервиса — да. Если это критично, используйте режим инкогнито.

Мы считаем честность в этих вопросах частью архитектурных решений, а не их опровержением.


Попробуйте дуплексный скан без загрузки файлов на серверы — pdfredx.com, без регистрации, без подписки.

Алгоритм дуплексной сборки PDF в браузере: разбор реализации на PDF.js и jsPDF
Когда я начинал проектировать дуплексный модуль в pdfredX, задача казалась тривиальной: взять два массива страниц и перемешать их поочерёдно. На практике оказалось, что именно в деталях — формате хранения страниц, управлении памятью, обработке нестандартного поведения АПД-сканеров и ограничениях браузерного рантайма — находится большая часть реального инженерного труда.

Когда я начинал проектировать дуплексный модуль в pdfredX, задача казалась тривиальной: взять два массива страниц и перемешать их поочерёдно. На практике оказалось, что именно в деталях — формате хранения страниц, управлении памятью, обработке нестандартного поведения АПД-сканеров и ограничениях браузерного рантайма — находится большая часть реального инженерного труда.

В этой статье разберём архитектурные решения, лежащие в основе duplex-инструмента pdfredX: почему выбрана связка PDF.js + jsPDF, как устроен алгоритм перестановки индексов, как dmReverseBack меняет шаг обхода массива, и где именно упирается производительность на реальных устройствах.


Архитектурный вызов: что значит «склеить два PDF» в браузере

В классическом серверном мире задача решается примитивно: принять два файла через HTTP, прочитать их PDF-структуру, переставить страницы через библиотеку типа PyMuPDF или iTextSharp, отдать результат. Браузер накладывает другие ограничения.

Почему нельзя просто распарсить PDF-структуру на клиенте. Формат PDF — это сложный бинарный граф: кросс-референсные таблицы (xref), сжатые потоки объектов, шрифты с подстановками, ICC-профили, зашитые в ColorSpace. Читать эту структуру на JavaScript без серверного бэкенда означает либо тащить в браузер полный PDF-парсер (тяжело, нестабильно на повреждённых файлах), либо работать с растровым представлением — то есть сначала рендерить страницы в Canvas, потом оперировать с пикселями и dataURL.

Выбор в пользу растра — осознанный компромисс. PDF.js 3.11.174 — это индустриальный стандарт рендеринга PDF в Canvas. Он обрабатывает 99% реальных файлов корректно, включая PDF с электронными подписями, слоями и нестандартными шрифтами. Цена: текстовый слой оригинального PDF теряется. Страница становится изображением. Для сценария дуплексного сканирования офисных документов это приемлемо — исходные файлы уже являются сканами, то есть растром.

Почему jsPDF, а не pdf-lib. pdf-lib позволяет работать со структурой PDF без растеризации, что теоретически лучше для сохранения текстового слоя. Но её стабильность на реальных отсканированных файлах с нестандартными метаданными оказалась ниже, чем у связки PDF.js → Canvas → jsPDF. Последняя требует дополнительного шага растеризации, но зато работает предсказуемо на файлах любого происхождения.


Глубокий разбор реализации алгоритма

Структура хранения страниц: массив items[]

Каждый загруженный PDF рендерится постранично через PDF.js. Рендер происходит в lowerCanvasEl — нижний Canvas-слой Fabric.js, который в режиме без аннотаций выступает прямым рабочим холстом. Результат каждой страницы конвертируется в dataURL через canvas.toDataURL('image/jpeg', 0.92) и помещается в единый массив items[].

Каждый элемент массива содержит:

{
  id:        string,       // уникальный идентификатор, например 'pdf-001-page-3'
  editUrl:   string,       // dataURL текущего состояния страницы
  origUrl:   string,       // dataURL оригинала — никогда не мутирует
  pdfSrcKey: string,       // 'duplex:front:filename.pdf' или 'duplex:back:filename.pdf'
  fromPdf:   true,
  isEdited:  boolean
}

Ключ pdfSrcKey с префиксом duplex:front: или duplex:back: — это то, что позволяет алгоритму сборки однозначно идентифицировать происхождение каждой страницы и собрать два отдельных под-массива.

Алгоритм перестановки индексов

После загрузки оба PDF дают два под-массива. Обозначим их F (фронт, длина fLen) и B (бэк, длина bLen). Задача алгоритма — построить новый массив R в правильном порядке.

Базовый случай (реверс выключен):

for (let i = 0; i < Math.max(fLen, bLen); i++) {
  if (i < fLen) R.push(F[i]);
  if (i < bLen) R.push(B[i]);
}
// Результат: F[0], B[0], F[1], B[1], F[2], B[2], ...

С включённым dmReverseBack:

for (let i = 0; i < Math.max(fLen, bLen); i++) {
  if (i < fLen) R.push(F[i]);
  const j = bLen - 1 - i;           // обход бэка справа налево
  if (j >= 0) R.push(B[j]);
}
// Результат: F[0], B[bLen-1], F[1], B[bLen-2], F[2], B[bLen-3], ...

Это именно то, что происходит, когда АПД переворачивает стопку после первого прогона: физически последний лист стопки становится первым отсканированным бэком. Без обращения индекса j = bLen - 1 - i каждая лицевая страница оказывается напротив неправильной оборотной.

Обратите внимание на Math.max(fLen, bLen): алгоритм корректно обрабатывает несимметричные случаи — когда фронт и бэк содержат разное количество страниц (потеряли лист при сканировании, асимметричный документ). Лишние страницы из более длинного массива просто добавляются в конец результирующего порядка без пары.

Сборка итогового PDF через jsPDF

После перестановки индексов массив items[] обновлён, но ничего не рендерилось заново — всё это была только работа с ссылками в JavaScript. Сам рендер страниц уже произошёл при загрузке файлов.

При нажатии «Скачать PDF» запускается makePDF():

const doc = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' });
for (const [idx, item] of items.entries()) {
  const { w, h } = imgDims(item.editUrl);          // определяем пропорции страницы
  const orient = w > h ? 'landscape' : 'portrait'; // автоопределение ориентации
  if (idx > 0) doc.addPage([210, 297], orient);
  doc.addImage(item.editUrl, 'JPEG', 0, 0, 210, 297);
}
doc.save('output.pdf');

Ключевой момент: imgDims вызывается для каждой страницы независимо. Это важно для документов, где часть страниц в портретной ориентации, часть в альбомной — например, смешанные сканы договора с приложениями.


Компромиссы производительности и лимиты по памяти

Почему растровое хранение дорого

Каждая страница хранится как JPEG dataURL. Для листа A4, отсканированного на 150 DPI: - Разрешение: 1240 × 1754 пикселей - JPEG с quality 0.92: ~300–600 КБ на страницу в зависимости от содержимого - Плюс in-memory decoded bitmap для Canvas: 1240 × 1754 × 4 байта (RGBA) ≈ 8.7 МБ на страницу

Для 100-страничного документа decoded bitmap в памяти может занимать ~870 МБ. Chrome ограничивает RAM вкладки примерно 2–4 ГБ в зависимости от версии и системных ресурсов. При подходе к этому пределу браузер начинает выгружать неактивные объекты из памяти, что вызывает повторный рендер страниц при прокрутке галереи.

На практике это означает: - До 80 страниц: работает без заметных задержек даже на мобильных устройствах. - 80–200 страниц: на мобильных возникает lag при прокрутке галереи; на десктопе приемлемо. - Свыше 200 страниц: Chrome начинает агрессивно выгружать кэш; повторная прокрутка сопровождается re-render паузами в 1–3 секунды на страницу.

Почему нет Web Worker для рендера

Очевидный следующий шаг — вынести рендер PDF.js в Web Worker, чтобы не блокировать main thread. Проблема: Canvas API недоступен из Worker напрямую (только OffscreenCanvas, поддержка которого на момент разработки была нестабильной в Safari). Перегонять ImageData между Worker и main thread для каждой страницы создаёт дополнительный overhead через postMessage и Transferable. Для текущего объёма документов выигрыш в UX не перекрывает сложность реализации. Это осознанный технический долг.

Почему мы не стриммируем страницы в jsPDF

jsPDF собирает весь документ в памяти перед вызовом doc.save(). Для документов в 200+ страниц это означает, что в момент сборки в памяти одновременно находятся: decoded bitmaps страниц, jsPDF internal buffers, итоговый PDF blob. Пиковое потребление RAM в момент экспорта может быть в 2–3 раза выше, чем в режиме просмотра галереи. В следующей версии рассматриваем потоковую запись через WritableStream + TransformStream для частичного сброса буфера на диск без полной сборки в памяти.


Что планируем улучшить

OffscreenCanvas + Worker для рендера. Когда Safari выровняет поддержку — это первый приоритет для снятия нагрузки с main thread на мобильных.

Потоковый экспорт через WritableStream. Позволит экспортировать документы в 500+ страниц без пикового потребления RAM.

LRU-кэш decoded bitmaps. Держать в памяти только последние N страниц в раскодированном виде, остальные — как сжатый dataURL. Уменьшит пиковое потребление памяти примерно на порядок.


Если хотите посмотреть, как дуплексная сборка ведёт себя под нагрузкой — загрузите два реальных многостраничных скана на pdfredx.com. Регистрация не нужна, файлы не уходят никуда.

🚀 Запустить инструмент бесплатно