Представьте себе документ размером 3000 КБ с десятью страницами и следующими объектами:
- четыре поднабора шрифтов, используемые на каждой странице, каждый размером около 50 КБ
- десять изображений, которые фигурируют на одной странице, каждое размером около 200 КБ (одно изображение на страницу)
- четыре изображения, которые фигурируют на каждой странице, каждое около 50 КБ
- десять страниц с потоками контента размером около 25 КБ каждый
- около 350 КБ для таких объектов, как каталог, информационный словарь, дерево страниц, таблица перекрестных ссылок и т.д...
Для одной страницы потребуется как минимум: - четыре набора шрифтов: 4 раза по 50 КБ - одно изображение: 1 раз по 200 КБ - четыре изображения: 4 раза по 50 КБ - один поток содержимого: 1 раз по 50 КБ - немного уменьшенный таблица перекрестных ссылок, немного уменьшенное дерево страниц, почти идентичный каталог, информационный словарь одинакового размера,... 200 КБ
Вместе это 850 КБ. Это означает, что вы получите 8500 КБ (10 раз по 850 КБ), если вы разделите 10-страничный PDF-документ размером 3000 КБ на 10 отдельных страниц.
Этот пример является результатом догадок (основанных на опыте) и предполагает, что PDF предсказуем. Большинство PDF-файлов не являются:
- на некоторых страницах потребуются изображения высокой четкости (возможно, даже в мегабайтах), на других страницах изображений не будет,
- некоторым страницам потребуется много разных шрифтов и подмножеств шрифтов (много килобайт), другие страницы будут состоять только из нескольких векторных рисунков (крошечный поток контента при сжатии).
- разные страницы могут совместно использовать большое количество ресурсов (Form XObjects, Image XObjects,...), другие страницы не будут совместно использовать какие-либо ресурсы.
- и так далее...
Вы сами это заметили, когда пишете: Я могу разбить этот документ на страницы. Но это также не очень хорошее решение, поскольку размер страницы также неравномерно распределяется по страницам.
Именно поэтому на ваш вопрос не может быть другого ответа, кроме как: вам придется действовать методом проб и ошибок. Никакое программное обеспечение не может предсказать, сколько места требуется странице, прежде чем вы посмотрите, что требуется для этой страницы. страница.
Обновление:
Как указывает Дэвид в комментариях, можно рассчитать все ресурсы, необходимые для страницы, и проверить, не превышают ли текущие ресурсы плюс необходимые ресурсы максимальный размер файла.
Я написал небольшой пример:
public void manipulatePdf(String src, String dest)
throws IOException, DocumentException {
Document document = new Document();
PdfCopy copy = new PdfSmartCopy(document, new FileOutputStream(dest));
document.open();
PdfReader reader = new PdfReader(src);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
// check resources needed for reader.getPageN(i);
copy.addPage(copy.getImportedPage(reader, i));
System.out.println("After adding page: " + copy.getOs().getCounter());
}
document.close();
System.out.println("After closing document: " + copy.getOs().getCounter());
reader.close();
}
Я выполнил пример на образце PDF с 18 страницами, и это было результатом:
After adding page: 56165
After adding page: 111398
After adding page: 162691
After adding page: 210035
After adding page: 253419
After adding page: 273429
After adding page: 330696
After adding page: 351564
After adding page: 400351
After adding page: 456545
After adding page: 495321
After adding page: 523640
After adding page: 576468
After adding page: 633525
After adding page: 751504
After adding page: 907490
After adding page: 957164
After adding page: 999140
After closing document: 1002509
Вы видите, как размер файла копии постепенно увеличивается с каждой добавляемой страницей. После добавления всех страниц размер составляет 999140 байт, а затем записывается дерево страниц и поток перекрестных ссылок, добавляя еще 3369 байт.
Там, где указано // check resources needed for reader.getPageN(i);
, вы можете приблизительно оценить размер, который будет добавлен для страницы, и выйти из цикла, если он превысит максимальное значение.
Почему это предположение:
- Возможно, вы считаете объекты, которые уже добавлены. Если вы будете следить за объектами (это не так сложно), ваша догадка будет более точной.
- Я использую
PdfSmartCopy
. Предположим, что внутри вашего PDF-файла есть два одинаковых объекта. Плохое программное обеспечение PDF часто вызывает такие проблемы. Например: одни и те же байты изображения дважды добавляются в файл. PdfSmartCopy
может обнаружить это и будет повторно использовать первый встреченный объект вместо добавления избыточных байтов дополнительного объекта.
В настоящее время у нас нет reader.getTotalPageBytes()
в PdfReader
, потому что PdfReader
пытается использовать как можно меньше памяти. Он не будет загружать какие-либо объекты в память, пока эти объекты не нужны. Следовательно, он не знает размер каждого объекта до того, как страница будет импортирована.
Тем не менее, я позабочусь о том, чтобы такой метод был добавлен в следующем выпуске.
Обновление:
В следующей версии вы найдете инструмент под названием SmartPdfSplitter
, который зависит от нового класс с именем PdfResourceCounter
. Вы можете использовать его следующим образом:
PdfReader reader = new PdfReader(src);
SmartPdfSplitter splitter = new SmartPdfSplitter(reader);
int part = 1;
while (splitter.hasMorePages()) {
splitter.split(new FileOutputStream("results/merge/part_" + part + ".pdf"), 200000);
part++;
}
reader.close();
Обратите внимание, что это может привести к тому, что одностраничный PDF-файл превысит ограничение (которое было установлено на 200000
байт в примере кода), если эта отдельная страница не может быть уменьшена до меньшего количества байтов. В этом случае splitter.isOverSized()
вернет true
, и вам придется найти другой способ уменьшить PDF.
person
Bruno Lowagie
schedule
19.02.2015